1use std::{boxed::Box as Box_, marker::PhantomData, pin::Pin};
4
5use futures_util::TryFutureExt;
6use glib::{object::IsClass, prelude::*, Object, Type};
7
8use crate::{prelude::*, AsyncInitable, Cancellable};
9
10impl AsyncInitable {
11 #[doc(alias = "g_async_initable_new_async")]
17 #[track_caller]
18 #[allow(clippy::new_ret_no_self)]
19 pub fn new<
20 O: IsClass + IsA<Object> + IsA<AsyncInitable>,
21 Q: FnOnce(Result<O, glib::Error>) + 'static,
22 >(
23 io_priority: glib::Priority,
24 cancellable: Option<&impl IsA<Cancellable>>,
25 callback: Q,
26 ) {
27 Self::with_type(O::static_type(), io_priority, cancellable, move |res| {
28 callback(res.map(|o| unsafe { o.unsafe_cast() }))
29 })
30 }
31
32 #[doc(alias = "g_async_initable_new_async")]
38 #[track_caller]
39 pub fn new_future<O: IsClass + IsA<Object> + IsA<AsyncInitable>>(
40 io_priority: glib::Priority,
41 ) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
42 Box::pin(
43 Self::with_type_future(O::static_type(), io_priority)
44 .map_ok(|o| unsafe { o.unsafe_cast() }),
45 )
46 }
47
48 #[doc(alias = "g_async_initable_new_async")]
55 #[track_caller]
56 pub fn with_type<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
57 type_: Type,
58 io_priority: glib::Priority,
59 cancellable: Option<&impl IsA<Cancellable>>,
60 callback: Q,
61 ) {
62 if !type_.is_a(AsyncInitable::static_type()) {
63 panic!("Type '{type_}' is not async initable");
64 }
65
66 unsafe {
67 let obj = Object::new_internal(type_, &mut []);
68 obj.unsafe_cast_ref::<Self>().init_async(
69 io_priority,
70 cancellable,
71 glib::clone!(
72 #[strong]
73 obj,
74 move |res| {
75 callback(res.map(|_| obj));
76 }
77 ),
78 )
79 };
80 }
81
82 #[doc(alias = "g_async_initable_new_async")]
88 #[track_caller]
89 pub fn with_type_future(
90 type_: Type,
91 io_priority: glib::Priority,
92 ) -> Pin<Box_<dyn std::future::Future<Output = Result<Object, glib::Error>> + 'static>> {
93 if !type_.is_a(AsyncInitable::static_type()) {
94 panic!("Type '{type_}' is not async initable");
95 }
96
97 unsafe {
98 Box_::pin(crate::GioFuture::new(
99 &(),
100 move |_obj, cancellable, send| {
101 let obj = Object::new_internal(type_, &mut []);
102 obj.unsafe_cast_ref::<Self>().init_async(
103 io_priority,
104 Some(cancellable),
105 glib::clone!(
106 #[strong]
107 obj,
108 move |res| {
109 send.resolve(res.map(|_| obj));
110 }
111 ),
112 );
113 },
114 ))
115 }
116 }
117
118 #[doc(alias = "g_async_initable_new_async")]
124 #[track_caller]
125 pub fn with_mut_values<Q: FnOnce(Result<Object, glib::Error>) + 'static>(
126 type_: Type,
127 properties: &mut [(&str, glib::Value)],
128 io_priority: glib::Priority,
129 cancellable: Option<&impl IsA<Cancellable>>,
130 callback: Q,
131 ) {
132 if !type_.is_a(AsyncInitable::static_type()) {
133 panic!("Type '{type_}' is not async initable");
134 }
135
136 unsafe {
137 let obj = Object::new_internal(type_, properties);
138 obj.unsafe_cast_ref::<Self>().init_async(
139 io_priority,
140 cancellable,
141 glib::clone!(
142 #[strong]
143 obj,
144 move |res| {
145 callback(res.map(|_| obj));
146 }
147 ),
148 )
149 };
150 }
151
152 #[doc(alias = "g_async_initable_new_async")]
158 #[track_caller]
159 pub fn with_mut_values_future(
160 type_: Type,
161 properties: &mut [(&str, glib::Value)],
162 io_priority: glib::Priority,
163 ) -> Pin<Box_<dyn std::future::Future<Output = Result<Object, glib::Error>> + 'static>> {
164 if !type_.is_a(AsyncInitable::static_type()) {
165 panic!("Type '{type_}' is not async initable");
166 }
167
168 unsafe {
169 let obj = Object::new_internal(type_, properties);
171 Box_::pin(crate::GioFuture::new(
172 &obj,
173 move |obj, cancellable, send| {
174 obj.unsafe_cast_ref::<Self>().init_async(
175 io_priority,
176 Some(cancellable),
177 glib::clone!(
178 #[strong]
179 obj,
180 move |res| {
181 send.resolve(res.map(|_| obj));
182 }
183 ),
184 );
185 },
186 ))
187 }
188 }
189
190 pub fn builder<'a, O: IsA<Object> + IsClass + IsA<AsyncInitable>>(
193 ) -> AsyncInitableBuilder<'a, O> {
194 AsyncInitableBuilder::new(O::static_type())
195 }
196
197 pub fn builder_with_type<'a>(type_: Type) -> AsyncInitableBuilder<'a, Object> {
200 if !type_.is_a(AsyncInitable::static_type()) {
201 panic!("Type '{type_}' is not async initable");
202 }
203
204 AsyncInitableBuilder::new(type_)
205 }
206}
207
208#[must_use = "builder doesn't do anything unless built"]
209pub struct AsyncInitableBuilder<'a, O> {
210 type_: Type,
211 properties: smallvec::SmallVec<[(&'a str, glib::Value); 16]>,
212 phantom: PhantomData<O>,
213}
214
215impl<'a, O: IsA<Object> + IsClass> AsyncInitableBuilder<'a, O> {
216 #[inline]
217 fn new(type_: Type) -> Self {
218 AsyncInitableBuilder {
219 type_,
220 properties: smallvec::SmallVec::new(),
221 phantom: PhantomData,
222 }
223 }
224
225 #[inline]
228 pub fn type_(&self) -> Type {
229 self.type_
230 }
231
232 #[inline]
235 pub fn property(self, name: &'a str, value: impl Into<glib::Value>) -> Self {
236 let AsyncInitableBuilder {
237 type_,
238 mut properties,
239 ..
240 } = self;
241 properties.push((name, value.into()));
242
243 AsyncInitableBuilder {
244 type_,
245 properties,
246 phantom: PhantomData,
247 }
248 }
249
250 #[track_caller]
258 #[inline]
259 pub fn build<Q: FnOnce(Result<O, glib::Error>) + 'static>(
260 mut self,
261 io_priority: glib::Priority,
262 cancellable: Option<&impl IsA<Cancellable>>,
263 callback: Q,
264 ) {
265 AsyncInitable::with_mut_values(
266 self.type_,
267 &mut self.properties,
268 io_priority,
269 cancellable,
270 move |res| callback(res.map(|o| unsafe { o.unsafe_cast() })),
271 );
272 }
273
274 #[track_caller]
282 #[inline]
283 pub fn build_future(
284 mut self,
285 io_priority: glib::Priority,
286 ) -> Pin<Box_<dyn std::future::Future<Output = Result<O, glib::Error>> + 'static>> {
287 Box::pin(
288 AsyncInitable::with_mut_values_future(self.type_, &mut self.properties, io_priority)
289 .map_ok(|o| unsafe { o.unsafe_cast() }),
290 )
291 }
292}