gio/auto/async_initable.rs
1// This file was generated by gir (https://github.com/gtk-rs/gir)
2// from gir-files (https://github.com/gtk-rs/gir-files)
3// DO NOT EDIT
4
5use crate::{ffi, AsyncResult, Cancellable};
6use glib::{prelude::*, translate::*};
7use std::{boxed::Box as Box_, pin::Pin};
8
9glib::wrapper! {
10 /// `GAsyncInitable` is an interface for asynchronously initializable objects.
11 ///
12 /// This is the asynchronous version of [`Initable`][crate::Initable]; it behaves the same
13 /// in all ways except that initialization is asynchronous. For more details
14 /// see the descriptions on `GInitable`.
15 ///
16 /// A class may implement both the `GInitable` and `GAsyncInitable` interfaces.
17 ///
18 /// Users of objects implementing this are not intended to use the interface
19 /// method directly; instead it will be used automatically in various ways.
20 /// For C applications you generally just call [`new_async()`][Self::new_async()]
21 /// directly, or indirectly via a foo_thing_new_async() wrapper. This will call
22 /// [`AsyncInitableExt::init_async()`][crate::prelude::AsyncInitableExt::init_async()] under the covers, calling back with `NULL`
23 /// and a set `GError` on failure.
24 ///
25 /// A typical implementation might look something like this:
26 ///
27 /// **⚠️ The following code is in c ⚠️**
28 ///
29 /// ```c
30 /// enum {
31 /// NOT_INITIALIZED,
32 /// INITIALIZING,
33 /// INITIALIZED
34 /// };
35 ///
36 /// static void
37 /// _foo_ready_cb (Foo *self)
38 /// {
39 /// GList *l;
40 ///
41 /// self->priv->state = INITIALIZED;
42 ///
43 /// for (l = self->priv->init_results; l != NULL; l = l->next)
44 /// {
45 /// GTask *task = l->data;
46 ///
47 /// if (self->priv->success)
48 /// g_task_return_boolean (task, TRUE);
49 /// else
50 /// g_task_return_new_error (task, ...);
51 /// g_object_unref (task);
52 /// }
53 ///
54 /// g_list_free (self->priv->init_results);
55 /// self->priv->init_results = NULL;
56 /// }
57 ///
58 /// static void
59 /// foo_init_async (GAsyncInitable *initable,
60 /// int io_priority,
61 /// GCancellable *cancellable,
62 /// GAsyncReadyCallback callback,
63 /// gpointer user_data)
64 /// {
65 /// Foo *self = FOO (initable);
66 /// GTask *task;
67 ///
68 /// task = g_task_new (initable, cancellable, callback, user_data);
69 /// g_task_set_name (task, G_STRFUNC);
70 ///
71 /// switch (self->priv->state)
72 /// {
73 /// case NOT_INITIALIZED:
74 /// _foo_get_ready (self);
75 /// self->priv->init_results = g_list_append (self->priv->init_results,
76 /// task);
77 /// self->priv->state = INITIALIZING;
78 /// break;
79 /// case INITIALIZING:
80 /// self->priv->init_results = g_list_append (self->priv->init_results,
81 /// task);
82 /// break;
83 /// case INITIALIZED:
84 /// if (!self->priv->success)
85 /// g_task_return_new_error (task, ...);
86 /// else
87 /// g_task_return_boolean (task, TRUE);
88 /// g_object_unref (task);
89 /// break;
90 /// }
91 /// }
92 ///
93 /// static gboolean
94 /// foo_init_finish (GAsyncInitable *initable,
95 /// GAsyncResult *result,
96 /// GError **error)
97 /// {
98 /// g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);
99 ///
100 /// return g_task_propagate_boolean (G_TASK (result), error);
101 /// }
102 ///
103 /// static void
104 /// foo_async_initable_iface_init (gpointer g_iface,
105 /// gpointer data)
106 /// {
107 /// GAsyncInitableIface *iface = g_iface;
108 ///
109 /// iface->init_async = foo_init_async;
110 /// iface->init_finish = foo_init_finish;
111 /// }
112 /// ```
113 ///
114 /// # Implements
115 ///
116 /// [`AsyncInitableExt`][trait@crate::prelude::AsyncInitableExt]
117 #[doc(alias = "GAsyncInitable")]
118 pub struct AsyncInitable(Interface<ffi::GAsyncInitable, ffi::GAsyncInitableIface>);
119
120 match fn {
121 type_ => || ffi::g_async_initable_get_type(),
122 }
123}
124
125impl AsyncInitable {
126 pub const NONE: Option<&'static AsyncInitable> = None;
127}
128
129mod sealed {
130 pub trait Sealed {}
131 impl<T: super::IsA<super::AsyncInitable>> Sealed for T {}
132}
133
134/// Trait containing all [`struct@AsyncInitable`] methods.
135///
136/// # Implementors
137///
138/// [`AsyncInitable`][struct@crate::AsyncInitable], [`DBusConnection`][struct@crate::DBusConnection], [`DBusProxy`][struct@crate::DBusProxy]
139pub trait AsyncInitableExt: IsA<AsyncInitable> + sealed::Sealed + 'static {
140 /// Starts asynchronous initialization of the object implementing the
141 /// interface. This must be done before any real use of the object after
142 /// initial construction. If the object also implements #GInitable you can
143 /// optionally call g_initable_init() instead.
144 ///
145 /// This method is intended for language bindings. If writing in C,
146 /// g_async_initable_new_async() should typically be used instead.
147 ///
148 /// When the initialization is finished, @callback will be called. You can
149 /// then call g_async_initable_init_finish() to get the result of the
150 /// initialization.
151 ///
152 /// Implementations may also support cancellation. If @cancellable is not
153 /// [`None`], then initialization can be cancelled by triggering the cancellable
154 /// object from another thread. If the operation was cancelled, the error
155 /// [`IOErrorEnum::Cancelled`][crate::IOErrorEnum::Cancelled] will be returned. If @cancellable is not [`None`], and
156 /// the object doesn't support cancellable initialization, the error
157 /// [`IOErrorEnum::NotSupported`][crate::IOErrorEnum::NotSupported] will be returned.
158 ///
159 /// As with #GInitable, if the object is not initialized, or initialization
160 /// returns with an error, then all operations on the object except
161 /// g_object_ref() and g_object_unref() are considered to be invalid, and
162 /// have undefined behaviour. They will often fail with g_critical() or
163 /// g_warning(), but this must not be relied on.
164 ///
165 /// Callers should not assume that a class which implements #GAsyncInitable can
166 /// be initialized multiple times; for more information, see g_initable_init().
167 /// If a class explicitly supports being initialized multiple times,
168 /// implementation requires yielding all subsequent calls to init_async() on the
169 /// results of the first call.
170 ///
171 /// For classes that also support the #GInitable interface, the default
172 /// implementation of this method will run the g_initable_init() function
173 /// in a thread, so if you want to support asynchronous initialization via
174 /// threads, just implement the #GAsyncInitable interface without overriding
175 /// any interface methods.
176 /// ## `io_priority`
177 /// the [I/O priority](iface.AsyncResult.html#io-priority) of the operation
178 /// ## `cancellable`
179 /// optional #GCancellable object, [`None`] to ignore.
180 /// ## `callback`
181 /// a #GAsyncReadyCallback to call when the request is satisfied
182 #[doc(alias = "g_async_initable_init_async")]
183 unsafe fn init_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
184 &self,
185 io_priority: glib::Priority,
186 cancellable: Option<&impl IsA<Cancellable>>,
187 callback: P,
188 ) {
189 let main_context = glib::MainContext::ref_thread_default();
190 let is_main_context_owner = main_context.is_owner();
191 let has_acquired_main_context = (!is_main_context_owner)
192 .then(|| main_context.acquire().ok())
193 .flatten();
194 assert!(
195 is_main_context_owner || has_acquired_main_context.is_some(),
196 "Async operations only allowed if the thread is owning the MainContext"
197 );
198
199 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
200 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
201 unsafe extern "C" fn init_async_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
202 _source_object: *mut glib::gobject_ffi::GObject,
203 res: *mut crate::ffi::GAsyncResult,
204 user_data: glib::ffi::gpointer,
205 ) {
206 let mut error = std::ptr::null_mut();
207 let _ = ffi::g_async_initable_init_finish(_source_object as *mut _, res, &mut error);
208 let result = if error.is_null() {
209 Ok(())
210 } else {
211 Err(from_glib_full(error))
212 };
213 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
214 Box_::from_raw(user_data as *mut _);
215 let callback: P = callback.into_inner();
216 callback(result);
217 }
218 let callback = init_async_trampoline::<P>;
219 ffi::g_async_initable_init_async(
220 self.as_ref().to_glib_none().0,
221 io_priority.into_glib(),
222 cancellable.map(|p| p.as_ref()).to_glib_none().0,
223 Some(callback),
224 Box_::into_raw(user_data) as *mut _,
225 );
226 }
227
228 unsafe fn init_future(
229 &self,
230 io_priority: glib::Priority,
231 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
232 Box_::pin(crate::GioFuture::new(
233 self,
234 move |obj, cancellable, send| {
235 obj.init_async(io_priority, Some(cancellable), move |res| {
236 send.resolve(res);
237 });
238 },
239 ))
240 }
241}
242
243impl<O: IsA<AsyncInitable>> AsyncInitableExt for O {}