Skip to content

Commit b67a499

Browse files
authored
Merge pull request #910 from sdroege/simpler-object-construction
glib: Add new object constructor for constructing an object with default property values
2 parents 83db468 + 52d39ab commit b67a499

18 files changed

+527
-48
lines changed

examples/gio_task/file_size/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ unsafe impl Sync for FileSize {}
1313

1414
impl FileSize {
1515
pub fn new() -> Self {
16-
glib::Object::new(&[])
16+
glib::Object::new_default()
1717
}
1818

1919
pub fn retrieved_size(&self) -> Option<i64> {

gio/src/async_initable.rs

Lines changed: 305 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
// Take a look at the license at the top of the repository in the LICENSE file.
22

3-
use std::{boxed::Box as Box_, pin::Pin};
3+
use std::{boxed::Box as Box_, marker::PhantomData, pin::Pin};
44

55
use futures_util::TryFutureExt;
66
use glib::{object::IsClass, prelude::*, Object, Type};
77

88
use crate::{prelude::*, AsyncInitable, Cancellable};
99

1010
impl AsyncInitable {
11+
// rustdoc-stripper-ignore-next
12+
/// Create a new instance of an async initable object with the given properties.
13+
///
14+
/// Similar to [`Object::new`] but can fail because the object initialization in
15+
/// `AsyncInitable::init` failed.
16+
#[allow(clippy::new_ret_no_self)]
1117
#[doc(alias = "g_async_initable_new_async")]
1218
#[track_caller]
13-
pub fn new_async<
14-
O: Sized + IsClass + IsA<Object> + IsA<AsyncInitable>,
15-
P: IsA<Cancellable>,
19+
pub fn new<
20+
O: IsClass + IsA<Object> + IsA<AsyncInitable>,
1621
Q: FnOnce(Result<O, glib::Error>) + 'static,
1722
>(
1823
properties: &[(&str, &dyn ToValue)],
1924
io_priority: glib::Priority,
20-
cancellable: Option<&P>,
25+
cancellable: Option<&impl IsA<Cancellable>>,
2126
callback: Q,
2227
) {
2328
Self::with_type(
@@ -29,9 +34,14 @@ impl AsyncInitable {
2934
)
3035
}
3136

37+
// rustdoc-stripper-ignore-next
38+
/// Create a new instance of an async initable object with the given properties as future.
39+
///
40+
/// Similar to [`Object::new`] but can fail because the object initialization in
41+
/// `AsyncInitable::init` failed.
3242
#[doc(alias = "g_async_initable_new_async")]
3343
#[track_caller]
34-
pub fn new_future<O: Sized + IsClass + IsA<Object> + IsA<AsyncInitable>>(
44+
pub fn new_future<O: IsClass + IsA<Object> + IsA<AsyncInitable>>(
3545
properties: &[(&str, &dyn ToValue)],
3646
io_priority: glib::Priority,
3747
) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
@@ -41,13 +51,18 @@ impl AsyncInitable {
4151
)
4252
}
4353

54+
// rustdoc-stripper-ignore-next
55+
/// Create a new instance of an async initable object of the given type with the given properties.
56+
///
57+
/// Similar to [`Object::with_type`] but can fail because the object initialization in
58+
/// `AsyncInitable::init` failed.
4459
#[doc(alias = "g_async_initable_new_async")]
4560
#[track_caller]
46-
pub fn with_type<P: IsA<Cancellable>, Q: FnOnce(Result<Object, glib::Error>) + 'static>(
61+
pub fn with_type<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
4762
type_: Type,
4863
properties: &[(&str, &dyn ToValue)],
4964
io_priority: glib::Priority,
50-
cancellable: Option<&P>,
65+
cancellable: Option<&impl IsA<Cancellable>>,
5166
callback: Q,
5267
) {
5368
if !type_.is_a(AsyncInitable::static_type()) {
@@ -71,6 +86,11 @@ impl AsyncInitable {
7186
};
7287
}
7388

89+
// rustdoc-stripper-ignore-next
90+
/// Create a new instance of an async initable object of the given type with the given properties as future.
91+
///
92+
/// Similar to [`Object::with_type`] but can fail because the object initialization in
93+
/// `AsyncInitable::init` failed.
7494
#[doc(alias = "g_async_initable_new_async")]
7595
#[track_caller]
7696
pub fn with_type_future(
@@ -105,13 +125,116 @@ impl AsyncInitable {
105125
}
106126
}
107127

128+
// rustdoc-stripper-ignore-next
129+
/// Create a new instance of an async initable object with the default property values.
130+
///
131+
/// Similar to [`Object::new_default`] but can fail because the object initialization in
132+
/// `AsyncInitable::init` failed.
108133
#[doc(alias = "g_async_initable_new_async")]
109134
#[track_caller]
110-
pub fn with_values<P: IsA<Cancellable>, Q: FnOnce(Result<Object, glib::Error>) + 'static>(
135+
pub fn new_default<
136+
O: IsClass + IsA<Object> + IsA<AsyncInitable>,
137+
Q: FnOnce(Result<O, glib::Error>) + 'static,
138+
>(
139+
io_priority: glib::Priority,
140+
cancellable: Option<&impl IsA<Cancellable>>,
141+
callback: Q,
142+
) {
143+
Self::new_default_with_type(O::static_type(), io_priority, cancellable, move |res| {
144+
callback(res.map(|o| unsafe { o.unsafe_cast() }))
145+
})
146+
}
147+
148+
// rustdoc-stripper-ignore-next
149+
/// Create a new instance of an async initable object with the default property values as future.
150+
///
151+
/// Similar to [`Object::new_default`] but can fail because the object initialization in
152+
/// `AsyncInitable::init` failed.
153+
#[doc(alias = "g_async_initable_new_async")]
154+
#[track_caller]
155+
pub fn new_default_future<O: IsClass + IsA<Object> + IsA<AsyncInitable>>(
156+
io_priority: glib::Priority,
157+
) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
158+
Box::pin(
159+
Self::new_default_with_type_future(O::static_type(), io_priority)
160+
.map_ok(|o| unsafe { o.unsafe_cast() }),
161+
)
162+
}
163+
164+
// rustdoc-stripper-ignore-next
165+
/// Create a new instance of an async initable object of the given type with the default
166+
/// property values.
167+
///
168+
/// Similar to [`Object::new_default_with_type`] but can fail because the object initialization in
169+
/// `AsyncInitable::init` failed.
170+
#[doc(alias = "g_async_initable_new_async")]
171+
#[track_caller]
172+
pub fn new_default_with_type<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
173+
type_: Type,
174+
io_priority: glib::Priority,
175+
cancellable: Option<&impl IsA<Cancellable>>,
176+
callback: Q,
177+
) {
178+
if !type_.is_a(AsyncInitable::static_type()) {
179+
panic!("Type '{type_}' is not async initable");
180+
}
181+
182+
unsafe {
183+
let obj = Object::new_internal(type_, &mut []);
184+
obj.unsafe_cast_ref::<Self>().init_async(
185+
io_priority,
186+
cancellable,
187+
glib::clone!(@strong obj => move |res| {
188+
callback(res.map(|_| obj));
189+
}),
190+
)
191+
};
192+
}
193+
194+
// rustdoc-stripper-ignore-next
195+
/// Create a new instance of an async initable object of the given type with the default property values as future.
196+
///
197+
/// Similar to [`Object::new_default_with_type`] but can fail because the object initialization in
198+
/// `AsyncInitable::init` failed.
199+
#[doc(alias = "g_async_initable_new_async")]
200+
#[track_caller]
201+
pub fn new_default_with_type_future(
202+
type_: Type,
203+
io_priority: glib::Priority,
204+
) -> Pin<Box_<dyn std::future::Future<Output = Result<Object, glib::Error>> + 'static>> {
205+
if !type_.is_a(AsyncInitable::static_type()) {
206+
panic!("Type '{type_}' is not async initable");
207+
}
208+
209+
unsafe {
210+
Box_::pin(crate::GioFuture::new(
211+
&(),
212+
move |_obj, cancellable, send| {
213+
let obj = Object::new_internal(type_, &mut []);
214+
obj.unsafe_cast_ref::<Self>().init_async(
215+
io_priority,
216+
Some(cancellable),
217+
glib::clone!(@strong obj => move |res| {
218+
send.resolve(res.map(|_| obj));
219+
}),
220+
);
221+
},
222+
))
223+
}
224+
}
225+
226+
// rustdoc-stripper-ignore-next
227+
/// Create a new instance of an async initable object of the given type with the given properties.
228+
///
229+
/// Similar to [`Object::with_values`] but can fail because the object initialization in
230+
/// `AsyncInitable::init` failed.
231+
#[doc(alias = "g_async_initable_new_async")]
232+
#[track_caller]
233+
pub fn with_values<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
111234
type_: Type,
112235
properties: &[(&str, glib::Value)],
113236
io_priority: glib::Priority,
114-
cancellable: Option<&P>,
237+
cancellable: Option<&impl IsA<Cancellable>>,
115238
callback: Q,
116239
) {
117240
if !type_.is_a(AsyncInitable::static_type()) {
@@ -135,6 +258,11 @@ impl AsyncInitable {
135258
};
136259
}
137260

261+
// rustdoc-stripper-ignore-next
262+
/// Create a new instance of an async initable object of the given type with the given properties as a future.
263+
///
264+
/// Similar to [`Object::with_values`] but can fail because the object initialization in
265+
/// `AsyncInitable::init` failed.
138266
#[doc(alias = "g_async_initable_new_async")]
139267
#[track_caller]
140268
pub fn with_values_future(
@@ -168,4 +296,171 @@ impl AsyncInitable {
168296
))
169297
}
170298
}
299+
300+
// rustdoc-stripper-ignore-next
301+
/// Create a new instance of an async initable object of the given type with the given properties as mutable values.
302+
///
303+
/// Similar to [`Object::with_mut_values`] but can fail because the object initialization in
304+
/// `AsyncInitable::init` failed.
305+
#[doc(alias = "g_async_initable_new_async")]
306+
#[track_caller]
307+
pub fn with_mut_values<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
308+
type_: Type,
309+
properties: &mut [(&str, glib::Value)],
310+
io_priority: glib::Priority,
311+
cancellable: Option<&impl IsA<Cancellable>>,
312+
callback: Q,
313+
) {
314+
if !type_.is_a(AsyncInitable::static_type()) {
315+
panic!("Type '{type_}' is not async initable");
316+
}
317+
318+
unsafe {
319+
let obj = Object::new_internal(type_, properties);
320+
obj.unsafe_cast_ref::<Self>().init_async(
321+
io_priority,
322+
cancellable,
323+
glib::clone!(@strong obj => move |res| {
324+
callback(res.map(|_| obj));
325+
}),
326+
)
327+
};
328+
}
329+
330+
// rustdoc-stripper-ignore-next
331+
/// Create a new instance of an async initable object of the given type with the given properties as mutable values as a future.
332+
///
333+
/// Similar to [`Object::with_mut_values`] but can fail because the object initialization in
334+
/// `AsyncInitable::init` failed.
335+
#[doc(alias = "g_async_initable_new_async")]
336+
#[track_caller]
337+
pub fn with_mut_values_future(
338+
type_: Type,
339+
properties: &mut [(&str, glib::Value)],
340+
io_priority: glib::Priority,
341+
) -> Pin<Box_<dyn std::future::Future<Output = Result<Object, glib::Error>> + 'static>> {
342+
if !type_.is_a(AsyncInitable::static_type()) {
343+
panic!("Type '{type_}' is not async initable");
344+
}
345+
346+
unsafe {
347+
// FIXME: object construction should ideally happen as part of the future
348+
let obj = Object::new_internal(type_, properties);
349+
Box_::pin(crate::GioFuture::new(
350+
&obj,
351+
move |obj, cancellable, send| {
352+
obj.unsafe_cast_ref::<Self>().init_async(
353+
io_priority,
354+
Some(cancellable),
355+
glib::clone!(@strong obj => move |res| {
356+
send.resolve(res.map(|_| obj));
357+
}),
358+
);
359+
},
360+
))
361+
}
362+
}
363+
364+
// rustdoc-stripper-ignore-next
365+
/// Create a new object builder for a specific type.
366+
pub fn builder<'a, O: IsA<Object> + IsClass + IsA<AsyncInitable>>(
367+
) -> AsyncInitableBuilder<'a, O> {
368+
AsyncInitableBuilder::new(O::static_type())
369+
}
370+
371+
// rustdoc-stripper-ignore-next
372+
/// Create a new object builder for a specific type.
373+
pub fn builder_with_type<'a>(type_: Type) -> AsyncInitableBuilder<'a, Object> {
374+
if !type_.is_a(AsyncInitable::static_type()) {
375+
panic!("Type '{type_}' is not async initable");
376+
}
377+
378+
AsyncInitableBuilder::new(type_)
379+
}
380+
}
381+
382+
#[must_use = "builder doesn't do anything unless built"]
383+
pub struct AsyncInitableBuilder<'a, O> {
384+
type_: Type,
385+
properties: smallvec::SmallVec<[(&'a str, glib::Value); 16]>,
386+
phantom: PhantomData<O>,
387+
}
388+
389+
impl<'a, O: IsA<Object> + IsClass> AsyncInitableBuilder<'a, O> {
390+
#[inline]
391+
fn new(type_: Type) -> Self {
392+
AsyncInitableBuilder {
393+
type_,
394+
properties: smallvec::SmallVec::new(),
395+
phantom: PhantomData,
396+
}
397+
}
398+
399+
// rustdoc-stripper-ignore-next
400+
/// Gets the type of this builder.
401+
#[inline]
402+
pub fn type_(&self) -> Type {
403+
self.type_
404+
}
405+
406+
// rustdoc-stripper-ignore-next
407+
/// Set property `name` to the given value `value`.
408+
#[inline]
409+
pub fn property(self, name: &'a str, value: impl Into<glib::Value>) -> Self {
410+
let AsyncInitableBuilder {
411+
type_,
412+
mut properties,
413+
..
414+
} = self;
415+
properties.push((name, value.into()));
416+
417+
AsyncInitableBuilder {
418+
type_,
419+
properties,
420+
phantom: PhantomData,
421+
}
422+
}
423+
424+
// rustdoc-stripper-ignore-next
425+
/// Build the object with the provided properties.
426+
///
427+
/// # Panics
428+
///
429+
/// This panics if the object is not instantiable, doesn't have all the given properties or
430+
/// property values of the wrong type are provided.
431+
#[track_caller]
432+
#[inline]
433+
pub fn build<Q: FnOnce(Result<O, glib::Error>) + 'static>(
434+
mut self,
435+
io_priority: glib::Priority,
436+
cancellable: Option<&impl IsA<Cancellable>>,
437+
callback: Q,
438+
) {
439+
AsyncInitable::with_mut_values(
440+
self.type_,
441+
&mut self.properties,
442+
io_priority,
443+
cancellable,
444+
move |res| callback(res.map(|o| unsafe { o.unsafe_cast() })),
445+
);
446+
}
447+
448+
// rustdoc-stripper-ignore-next
449+
/// Build the object with the provided properties.
450+
///
451+
/// # Panics
452+
///
453+
/// This panics if the object is not instantiable, doesn't have all the given properties or
454+
/// property values of the wrong type are provided.
455+
#[track_caller]
456+
#[inline]
457+
pub fn build_future(
458+
mut self,
459+
io_priority: glib::Priority,
460+
) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
461+
Box::pin(
462+
AsyncInitable::with_mut_values_future(self.type_, &mut self.properties, io_priority)
463+
.map_ok(|o| unsafe { o.unsafe_cast() }),
464+
)
465+
}
171466
}

0 commit comments

Comments
 (0)