Skip to main content

gio/
output_stream.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{io, mem, pin::Pin, ptr};
4
5use glib::{Priority, prelude::*, translate::*};
6
7#[cfg(feature = "v2_60")]
8use crate::OutputVector;
9use crate::{Cancellable, OutputStream, Seekable, error::to_std_io_result, ffi, prelude::*};
10
11pub trait OutputStreamExtManual: IsA<OutputStream> + Sized {
12    /// Request an asynchronous write of @count bytes from @buffer into
13    /// the stream. When the operation is finished @callback will be called.
14    /// You can then call g_output_stream_write_finish() to get the result of the
15    /// operation.
16    ///
17    /// During an async request no other sync and async calls are allowed,
18    /// and will result in [`IOErrorEnum::Pending`][crate::IOErrorEnum::Pending] errors.
19    ///
20    /// A value of @count larger than `G_MAXSSIZE` will cause a
21    /// [`IOErrorEnum::InvalidArgument`][crate::IOErrorEnum::InvalidArgument] error.
22    ///
23    /// On success, the number of bytes written will be passed to the
24    /// @callback. It is not an error if this is not the same as the
25    /// requested size, as it can happen e.g. on a partial I/O error,
26    /// but generally we try to write as many bytes as requested.
27    ///
28    /// You are guaranteed that this method will never fail with
29    /// [`IOErrorEnum::WouldBlock`][crate::IOErrorEnum::WouldBlock] - if @self can't accept more data, the
30    /// method will just wait until this changes.
31    ///
32    /// Any outstanding I/O request with higher priority (lower numerical
33    /// value) will be executed before an outstanding request with lower
34    /// priority. Default priority is `G_PRIORITY_DEFAULT`.
35    ///
36    /// The asynchronous methods have a default fallback that uses threads
37    /// to implement asynchronicity, so they are optional for inheriting
38    /// classes. However, if you override one you must override all.
39    ///
40    /// For the synchronous, blocking version of this function, see
41    /// g_output_stream_write().
42    ///
43    /// Note that no copy of @buffer will be made, so it must stay valid
44    /// until @callback is called. See g_output_stream_write_bytes_async()
45    /// for a #GBytes version that will automatically hold a reference to
46    /// the contents (without copying) for the duration of the call.
47    /// ## `buffer`
48    /// the buffer containing the data to write.
49    /// ## `io_priority`
50    /// the io priority of the request.
51    /// ## `cancellable`
52    /// optional #GCancellable object, [`None`] to ignore.
53    /// ## `callback`
54    /// a #GAsyncReadyCallback
55    ///     to call when the request is satisfied
56    #[doc(alias = "g_output_stream_write_async")]
57    fn write_async<
58        B: AsRef<[u8]> + Send + 'static,
59        Q: FnOnce(Result<(B, usize), (B, glib::Error)>) + 'static,
60        C: IsA<Cancellable>,
61    >(
62        &self,
63        buffer: B,
64        io_priority: Priority,
65        cancellable: Option<&C>,
66        callback: Q,
67    ) {
68        let main_context = glib::MainContext::ref_thread_default();
69        let is_main_context_owner = main_context.is_owner();
70        let has_acquired_main_context = (!is_main_context_owner)
71            .then(|| main_context.acquire().ok())
72            .flatten();
73        assert!(
74            is_main_context_owner || has_acquired_main_context.is_some(),
75            "Async operations only allowed if the thread is owning the MainContext"
76        );
77
78        let cancellable = cancellable.map(|c| c.as_ref());
79        let gcancellable = cancellable.to_glib_none();
80        let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
81            Box::new((glib::thread_guard::ThreadGuard::new(callback), buffer));
82        // Need to do this after boxing as the contents pointer might change by moving into the box
83        let (count, buffer_ptr) = {
84            let buffer = &user_data.1;
85            let slice = buffer.as_ref();
86            (slice.len(), slice.as_ptr())
87        };
88        unsafe extern "C" fn write_async_trampoline<
89            B: AsRef<[u8]> + Send + 'static,
90            Q: FnOnce(Result<(B, usize), (B, glib::Error)>) + 'static,
91        >(
92            _source_object: *mut glib::gobject_ffi::GObject,
93            res: *mut ffi::GAsyncResult,
94            user_data: glib::ffi::gpointer,
95        ) {
96            unsafe {
97                let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
98                    Box::from_raw(user_data as *mut _);
99                let (callback, buffer) = *user_data;
100                let callback = callback.into_inner();
101
102                let mut error = ptr::null_mut();
103                let ret =
104                    ffi::g_output_stream_write_finish(_source_object as *mut _, res, &mut error);
105                let result = if error.is_null() {
106                    Ok((buffer, ret as usize))
107                } else {
108                    Err((buffer, from_glib_full(error)))
109                };
110                callback(result);
111            }
112        }
113        let callback = write_async_trampoline::<B, Q>;
114        unsafe {
115            ffi::g_output_stream_write_async(
116                self.as_ref().to_glib_none().0,
117                mut_override(buffer_ptr),
118                count,
119                io_priority.into_glib(),
120                gcancellable.0,
121                Some(callback),
122                Box::into_raw(user_data) as *mut _,
123            );
124        }
125    }
126
127    /// Tries to write @count bytes from @buffer into the stream. Will block
128    /// during the operation.
129    ///
130    /// This function is similar to g_output_stream_write(), except it tries to
131    /// write as many bytes as requested, only stopping on an error.
132    ///
133    /// On a successful write of @count bytes, [`true`] is returned, and @bytes_written
134    /// is set to @count.
135    ///
136    /// If there is an error during the operation [`false`] is returned and @error
137    /// is set to indicate the error status.
138    ///
139    /// As a special exception to the normal conventions for functions that
140    /// use #GError, if this function returns [`false`] (and sets @error) then
141    /// @bytes_written will be set to the number of bytes that were
142    /// successfully written before the error was encountered.  This
143    /// functionality is only available from C.  If you need it from another
144    /// language then you must write your own loop around
145    /// g_output_stream_write().
146    /// ## `buffer`
147    /// the buffer containing the data to write.
148    /// ## `cancellable`
149    /// optional #GCancellable object, [`None`] to ignore.
150    ///
151    /// # Returns
152    ///
153    /// [`true`] on success, [`false`] if there was an error
154    ///
155    /// ## `bytes_written`
156    /// location to store the number of bytes that was
157    ///     written to the stream
158    #[doc(alias = "g_output_stream_write_all")]
159    fn write_all<C: IsA<Cancellable>>(
160        &self,
161        buffer: &[u8],
162        cancellable: Option<&C>,
163    ) -> Result<(usize, Option<glib::Error>), glib::Error> {
164        let cancellable = cancellable.map(|c| c.as_ref());
165        let gcancellable = cancellable.to_glib_none();
166        let count = buffer.len();
167        unsafe {
168            let mut bytes_written = mem::MaybeUninit::uninit();
169            let mut error = ptr::null_mut();
170            let _ = ffi::g_output_stream_write_all(
171                self.as_ref().to_glib_none().0,
172                buffer.to_glib_none().0,
173                count,
174                bytes_written.as_mut_ptr(),
175                gcancellable.0,
176                &mut error,
177            );
178
179            let bytes_written = bytes_written.assume_init();
180            if error.is_null() {
181                Ok((bytes_written, None))
182            } else if bytes_written != 0 {
183                Ok((bytes_written, Some(from_glib_full(error))))
184            } else {
185                Err(from_glib_full(error))
186            }
187        }
188    }
189
190    /// Request an asynchronous write of @count bytes from @buffer into
191    /// the stream. When the operation is finished @callback will be called.
192    /// You can then call g_output_stream_write_all_finish() to get the result of the
193    /// operation.
194    ///
195    /// This is the asynchronous version of g_output_stream_write_all().
196    ///
197    /// Call g_output_stream_write_all_finish() to collect the result.
198    ///
199    /// Any outstanding I/O request with higher priority (lower numerical
200    /// value) will be executed before an outstanding request with lower
201    /// priority. Default priority is `G_PRIORITY_DEFAULT`.
202    ///
203    /// Note that no copy of @buffer will be made, so it must stay valid
204    /// until @callback is called.
205    /// ## `buffer`
206    /// the buffer containing the data to write
207    /// ## `io_priority`
208    /// the io priority of the request
209    /// ## `cancellable`
210    /// optional #GCancellable object, [`None`] to ignore
211    /// ## `callback`
212    /// a #GAsyncReadyCallback
213    ///     to call when the request is satisfied
214    #[doc(alias = "g_output_stream_write_all_async")]
215    fn write_all_async<
216        B: AsRef<[u8]> + Send + 'static,
217        Q: FnOnce(Result<(B, usize), (B, usize, glib::Error)>) + 'static,
218        C: IsA<Cancellable>,
219    >(
220        &self,
221        buffer: B,
222        io_priority: Priority,
223        cancellable: Option<&C>,
224        callback: Q,
225    ) {
226        let main_context = glib::MainContext::ref_thread_default();
227        let is_main_context_owner = main_context.is_owner();
228        let has_acquired_main_context = (!is_main_context_owner)
229            .then(|| main_context.acquire().ok())
230            .flatten();
231        assert!(
232            is_main_context_owner || has_acquired_main_context.is_some(),
233            "Async operations only allowed if the thread is owning the MainContext"
234        );
235
236        let cancellable = cancellable.map(|c| c.as_ref());
237        let gcancellable = cancellable.to_glib_none();
238        let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
239            Box::new((glib::thread_guard::ThreadGuard::new(callback), buffer));
240        // Need to do this after boxing as the contents pointer might change by moving into the box
241        let (count, buffer_ptr) = {
242            let buffer = &user_data.1;
243            let slice = buffer.as_ref();
244            (slice.len(), slice.as_ptr())
245        };
246        unsafe extern "C" fn write_all_async_trampoline<
247            B: AsRef<[u8]> + Send + 'static,
248            Q: FnOnce(Result<(B, usize), (B, usize, glib::Error)>) + 'static,
249        >(
250            _source_object: *mut glib::gobject_ffi::GObject,
251            res: *mut ffi::GAsyncResult,
252            user_data: glib::ffi::gpointer,
253        ) {
254            unsafe {
255                let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
256                    Box::from_raw(user_data as *mut _);
257                let (callback, buffer) = *user_data;
258                let callback = callback.into_inner();
259
260                let mut error = ptr::null_mut();
261                let mut bytes_written = mem::MaybeUninit::uninit();
262                let _ = ffi::g_output_stream_write_all_finish(
263                    _source_object as *mut _,
264                    res,
265                    bytes_written.as_mut_ptr(),
266                    &mut error,
267                );
268                let bytes_written = bytes_written.assume_init();
269                let result = if error.is_null() {
270                    Ok((buffer, bytes_written))
271                } else {
272                    Err((buffer, bytes_written, from_glib_full(error)))
273                };
274                callback(result);
275            }
276        }
277        let callback = write_all_async_trampoline::<B, Q>;
278        unsafe {
279            ffi::g_output_stream_write_all_async(
280                self.as_ref().to_glib_none().0,
281                mut_override(buffer_ptr),
282                count,
283                io_priority.into_glib(),
284                gcancellable.0,
285                Some(callback),
286                Box::into_raw(user_data) as *mut _,
287            );
288        }
289    }
290
291    fn write_future<B: AsRef<[u8]> + Send + 'static>(
292        &self,
293        buffer: B,
294        io_priority: Priority,
295    ) -> Pin<Box<dyn std::future::Future<Output = Result<(B, usize), (B, glib::Error)>> + 'static>>
296    {
297        Box::pin(crate::GioFuture::new(
298            self,
299            move |obj, cancellable, send| {
300                obj.write_async(buffer, io_priority, Some(cancellable), move |res| {
301                    send.resolve(res);
302                });
303            },
304        ))
305    }
306
307    fn write_all_future<B: AsRef<[u8]> + Send + 'static>(
308        &self,
309        buffer: B,
310        io_priority: Priority,
311    ) -> Pin<
312        Box<
313            dyn std::future::Future<Output = Result<(B, usize), (B, usize, glib::Error)>> + 'static,
314        >,
315    > {
316        Box::pin(crate::GioFuture::new(
317            self,
318            move |obj, cancellable, send| {
319                obj.write_all_async(buffer, io_priority, Some(cancellable), move |res| {
320                    send.resolve(res);
321                });
322            },
323        ))
324    }
325
326    /// Tries to write the bytes contained in the @n_vectors @vectors into the
327    /// stream. Will block during the operation.
328    ///
329    /// If @n_vectors is 0 or the sum of all bytes in @vectors is 0, returns 0 and
330    /// does nothing.
331    ///
332    /// On success, the number of bytes written to the stream is returned.
333    /// It is not an error if this is not the same as the requested size, as it
334    /// can happen e.g. on a partial I/O error, or if there is not enough
335    /// storage in the stream. All writes block until at least one byte
336    /// is written or an error occurs; 0 is never returned (unless
337    /// @n_vectors is 0 or the sum of all bytes in @vectors is 0).
338    ///
339    /// If @cancellable is not [`None`], then the operation can be cancelled by
340    /// triggering the cancellable object from another thread. If the operation
341    /// was cancelled, the error [`IOErrorEnum::Cancelled`][crate::IOErrorEnum::Cancelled] will be returned. If an
342    /// operation was partially finished when the operation was cancelled the
343    /// partial result will be returned, without an error.
344    ///
345    /// Some implementations of g_output_stream_writev() may have limitations on the
346    /// aggregate buffer size, and will return [`IOErrorEnum::InvalidArgument`][crate::IOErrorEnum::InvalidArgument] if these
347    /// are exceeded. For example, when writing to a local file on UNIX platforms,
348    /// the aggregate buffer size must not exceed `G_MAXSSIZE` bytes.
349    /// ## `vectors`
350    /// the buffer containing the #GOutputVectors to write.
351    /// ## `cancellable`
352    /// optional cancellable object
353    ///
354    /// # Returns
355    ///
356    /// [`true`] on success, [`false`] if there was an error
357    ///
358    /// ## `bytes_written`
359    /// location to store the number of bytes that were
360    ///     written to the stream
361    #[cfg(feature = "v2_60")]
362    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
363    #[doc(alias = "g_output_stream_writev")]
364    fn writev(
365        &self,
366        vectors: &[OutputVector],
367        cancellable: Option<&impl IsA<Cancellable>>,
368    ) -> Result<usize, glib::Error> {
369        unsafe {
370            let mut error = ptr::null_mut();
371            let mut bytes_written = mem::MaybeUninit::uninit();
372
373            ffi::g_output_stream_writev(
374                self.as_ref().to_glib_none().0,
375                vectors.as_ptr() as *const _,
376                vectors.len(),
377                bytes_written.as_mut_ptr(),
378                cancellable.map(|p| p.as_ref()).to_glib_none().0,
379                &mut error,
380            );
381            if error.is_null() {
382                Ok(bytes_written.assume_init())
383            } else {
384                Err(from_glib_full(error))
385            }
386        }
387    }
388
389    /// Request an asynchronous write of the bytes contained in @n_vectors @vectors into
390    /// the stream. When the operation is finished @callback will be called.
391    /// You can then call g_output_stream_writev_finish() to get the result of the
392    /// operation.
393    ///
394    /// During an async request no other sync and async calls are allowed,
395    /// and will result in [`IOErrorEnum::Pending`][crate::IOErrorEnum::Pending] errors.
396    ///
397    /// On success, the number of bytes written will be passed to the
398    /// @callback. It is not an error if this is not the same as the
399    /// requested size, as it can happen e.g. on a partial I/O error,
400    /// but generally we try to write as many bytes as requested.
401    ///
402    /// You are guaranteed that this method will never fail with
403    /// [`IOErrorEnum::WouldBlock`][crate::IOErrorEnum::WouldBlock] — if @self can't accept more data, the
404    /// method will just wait until this changes.
405    ///
406    /// Any outstanding I/O request with higher priority (lower numerical
407    /// value) will be executed before an outstanding request with lower
408    /// priority. Default priority is `G_PRIORITY_DEFAULT`.
409    ///
410    /// The asynchronous methods have a default fallback that uses threads
411    /// to implement asynchronicity, so they are optional for inheriting
412    /// classes. However, if you override one you must override all.
413    ///
414    /// For the synchronous, blocking version of this function, see
415    /// g_output_stream_writev().
416    ///
417    /// Note that no copy of @vectors will be made, so it must stay valid
418    /// until @callback is called.
419    /// ## `vectors`
420    /// the buffer containing the #GOutputVectors to write.
421    /// ## `io_priority`
422    /// the I/O priority of the request.
423    /// ## `cancellable`
424    /// optional #GCancellable object, [`None`] to ignore.
425    /// ## `callback`
426    /// a #GAsyncReadyCallback
427    ///     to call when the request is satisfied
428    #[cfg(feature = "v2_60")]
429    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
430    #[doc(alias = "g_output_stream_writev_async")]
431    fn writev_async<
432        B: AsRef<[u8]> + Send + 'static,
433        P: FnOnce(Result<(Vec<B>, usize), (Vec<B>, glib::Error)>) + 'static,
434    >(
435        &self,
436        vectors: impl IntoIterator<Item = B> + 'static,
437        io_priority: glib::Priority,
438        cancellable: Option<&impl IsA<Cancellable>>,
439        callback: P,
440    ) {
441        let main_context = glib::MainContext::ref_thread_default();
442        let is_main_context_owner = main_context.is_owner();
443        let has_acquired_main_context = (!is_main_context_owner)
444            .then(|| main_context.acquire().ok())
445            .flatten();
446        assert!(
447            is_main_context_owner || has_acquired_main_context.is_some(),
448            "Async operations only allowed if the thread is owning the MainContext"
449        );
450
451        let cancellable = cancellable.map(|c| c.as_ref());
452        let gcancellable = cancellable.to_glib_none();
453        let buffers = vectors.into_iter().collect::<Vec<_>>();
454        let vectors = buffers
455            .iter()
456            .map(|v| ffi::GOutputVector {
457                buffer: v.as_ref().as_ptr() as *const _,
458                size: v.as_ref().len(),
459            })
460            .collect::<Vec<_>>();
461        let vectors_ptr = vectors.as_ptr();
462        let num_vectors = vectors.len();
463        let user_data: Box<(
464            glib::thread_guard::ThreadGuard<P>,
465            Vec<B>,
466            Vec<ffi::GOutputVector>,
467        )> = Box::new((
468            glib::thread_guard::ThreadGuard::new(callback),
469            buffers,
470            vectors,
471        ));
472
473        unsafe extern "C" fn writev_async_trampoline<
474            B: AsRef<[u8]> + Send + 'static,
475            P: FnOnce(Result<(Vec<B>, usize), (Vec<B>, glib::Error)>) + 'static,
476        >(
477            _source_object: *mut glib::gobject_ffi::GObject,
478            res: *mut ffi::GAsyncResult,
479            user_data: glib::ffi::gpointer,
480        ) {
481            unsafe {
482                let user_data: Box<(
483                    glib::thread_guard::ThreadGuard<P>,
484                    Vec<B>,
485                    Vec<ffi::GOutputVector>,
486                )> = Box::from_raw(user_data as *mut _);
487                let (callback, buffers, _) = *user_data;
488                let callback = callback.into_inner();
489
490                let mut error = ptr::null_mut();
491                let mut bytes_written = mem::MaybeUninit::uninit();
492                ffi::g_output_stream_writev_finish(
493                    _source_object as *mut _,
494                    res,
495                    bytes_written.as_mut_ptr(),
496                    &mut error,
497                );
498                let bytes_written = bytes_written.assume_init();
499                let result = if error.is_null() {
500                    Ok((buffers, bytes_written))
501                } else {
502                    Err((buffers, from_glib_full(error)))
503                };
504                callback(result);
505            }
506        }
507        let callback = writev_async_trampoline::<B, P>;
508        unsafe {
509            ffi::g_output_stream_writev_async(
510                self.as_ref().to_glib_none().0,
511                vectors_ptr,
512                num_vectors,
513                io_priority.into_glib(),
514                gcancellable.0,
515                Some(callback),
516                Box::into_raw(user_data) as *mut _,
517            );
518        }
519    }
520
521    #[cfg(feature = "v2_60")]
522    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
523    fn writev_future<B: AsRef<[u8]> + Send + 'static>(
524        &self,
525        vectors: impl IntoIterator<Item = B> + 'static,
526        io_priority: glib::Priority,
527    ) -> Pin<
528        Box<
529            dyn std::future::Future<Output = Result<(Vec<B>, usize), (Vec<B>, glib::Error)>>
530                + 'static,
531        >,
532    > {
533        Box::pin(crate::GioFuture::new(
534            self,
535            move |obj, cancellable, send| {
536                obj.writev_async(vectors, io_priority, Some(cancellable), move |res| {
537                    send.resolve(res);
538                });
539            },
540        ))
541    }
542
543    /// Tries to write the bytes contained in the @n_vectors @vectors into the
544    /// stream. Will block during the operation.
545    ///
546    /// This function is similar to g_output_stream_writev(), except it tries to
547    /// write as many bytes as requested, only stopping on an error.
548    ///
549    /// On a successful write of all @n_vectors vectors, [`true`] is returned, and
550    /// @bytes_written is set to the sum of all the sizes of @vectors.
551    ///
552    /// If there is an error during the operation [`false`] is returned and @error
553    /// is set to indicate the error status.
554    ///
555    /// As a special exception to the normal conventions for functions that
556    /// use #GError, if this function returns [`false`] (and sets @error) then
557    /// @bytes_written will be set to the number of bytes that were
558    /// successfully written before the error was encountered.  This
559    /// functionality is only available from C. If you need it from another
560    /// language then you must write your own loop around
561    /// g_output_stream_write().
562    ///
563    /// The content of the individual elements of @vectors might be changed by this
564    /// function.
565    /// ## `vectors`
566    /// the buffer containing the #GOutputVectors to write.
567    /// ## `cancellable`
568    /// optional #GCancellable object, [`None`] to ignore.
569    ///
570    /// # Returns
571    ///
572    /// [`true`] on success, [`false`] if there was an error
573    ///
574    /// ## `bytes_written`
575    /// location to store the number of bytes that were
576    ///     written to the stream
577    #[cfg(feature = "v2_60")]
578    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
579    #[doc(alias = "g_output_stream_writev_all")]
580    fn writev_all(
581        &self,
582        vectors: &[OutputVector],
583        cancellable: Option<&impl IsA<Cancellable>>,
584    ) -> Result<(usize, Option<glib::Error>), glib::Error> {
585        unsafe {
586            let mut error = ptr::null_mut();
587            let mut bytes_written = mem::MaybeUninit::uninit();
588
589            ffi::g_output_stream_writev_all(
590                self.as_ref().to_glib_none().0,
591                mut_override(vectors.as_ptr() as *const _),
592                vectors.len(),
593                bytes_written.as_mut_ptr(),
594                cancellable.map(|p| p.as_ref()).to_glib_none().0,
595                &mut error,
596            );
597            let bytes_written = bytes_written.assume_init();
598            if error.is_null() {
599                Ok((bytes_written, None))
600            } else if bytes_written != 0 {
601                Ok((bytes_written, Some(from_glib_full(error))))
602            } else {
603                Err(from_glib_full(error))
604            }
605        }
606    }
607
608    /// Request an asynchronous write of the bytes contained in the @n_vectors @vectors into
609    /// the stream. When the operation is finished @callback will be called.
610    /// You can then call g_output_stream_writev_all_finish() to get the result of the
611    /// operation.
612    ///
613    /// This is the asynchronous version of g_output_stream_writev_all().
614    ///
615    /// Call g_output_stream_writev_all_finish() to collect the result.
616    ///
617    /// Any outstanding I/O request with higher priority (lower numerical
618    /// value) will be executed before an outstanding request with lower
619    /// priority. Default priority is `G_PRIORITY_DEFAULT`.
620    ///
621    /// Note that no copy of @vectors will be made, so it must stay valid
622    /// until @callback is called. The content of the individual elements
623    /// of @vectors might be changed by this function.
624    /// ## `vectors`
625    /// the buffer containing the #GOutputVectors to write.
626    /// ## `io_priority`
627    /// the I/O priority of the request
628    /// ## `cancellable`
629    /// optional #GCancellable object, [`None`] to ignore
630    /// ## `callback`
631    /// a #GAsyncReadyCallback
632    ///     to call when the request is satisfied
633    #[cfg(feature = "v2_60")]
634    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
635    #[doc(alias = "g_output_stream_writev_all_async")]
636    fn writev_all_async<
637        B: AsRef<[u8]> + Send + 'static,
638        P: FnOnce(Result<(Vec<B>, usize, Option<glib::Error>), (Vec<B>, glib::Error)>) + 'static,
639    >(
640        &self,
641        vectors: impl IntoIterator<Item = B> + 'static,
642        io_priority: glib::Priority,
643        cancellable: Option<&impl IsA<Cancellable>>,
644        callback: P,
645    ) {
646        let main_context = glib::MainContext::ref_thread_default();
647        let is_main_context_owner = main_context.is_owner();
648        let has_acquired_main_context = (!is_main_context_owner)
649            .then(|| main_context.acquire().ok())
650            .flatten();
651        assert!(
652            is_main_context_owner || has_acquired_main_context.is_some(),
653            "Async operations only allowed if the thread is owning the MainContext"
654        );
655
656        let cancellable = cancellable.map(|c| c.as_ref());
657        let gcancellable = cancellable.to_glib_none();
658        let buffers = vectors.into_iter().collect::<Vec<_>>();
659        let vectors = buffers
660            .iter()
661            .map(|v| ffi::GOutputVector {
662                buffer: v.as_ref().as_ptr() as *const _,
663                size: v.as_ref().len(),
664            })
665            .collect::<Vec<_>>();
666        let vectors_ptr = vectors.as_ptr();
667        let num_vectors = vectors.len();
668        let user_data: Box<(
669            glib::thread_guard::ThreadGuard<P>,
670            Vec<B>,
671            Vec<ffi::GOutputVector>,
672        )> = Box::new((
673            glib::thread_guard::ThreadGuard::new(callback),
674            buffers,
675            vectors,
676        ));
677
678        unsafe extern "C" fn writev_all_async_trampoline<
679            B: AsRef<[u8]> + Send + 'static,
680            P: FnOnce(Result<(Vec<B>, usize, Option<glib::Error>), (Vec<B>, glib::Error)>) + 'static,
681        >(
682            _source_object: *mut glib::gobject_ffi::GObject,
683            res: *mut ffi::GAsyncResult,
684            user_data: glib::ffi::gpointer,
685        ) {
686            unsafe {
687                let user_data: Box<(
688                    glib::thread_guard::ThreadGuard<P>,
689                    Vec<B>,
690                    Vec<ffi::GOutputVector>,
691                )> = Box::from_raw(user_data as *mut _);
692                let (callback, buffers, _) = *user_data;
693                let callback = callback.into_inner();
694
695                let mut error = ptr::null_mut();
696                let mut bytes_written = mem::MaybeUninit::uninit();
697                ffi::g_output_stream_writev_all_finish(
698                    _source_object as *mut _,
699                    res,
700                    bytes_written.as_mut_ptr(),
701                    &mut error,
702                );
703                let bytes_written = bytes_written.assume_init();
704                let result = if error.is_null() {
705                    Ok((buffers, bytes_written, None))
706                } else if bytes_written != 0 {
707                    Ok((buffers, bytes_written, from_glib_full(error)))
708                } else {
709                    Err((buffers, from_glib_full(error)))
710                };
711                callback(result);
712            }
713        }
714        let callback = writev_all_async_trampoline::<B, P>;
715        unsafe {
716            ffi::g_output_stream_writev_all_async(
717                self.as_ref().to_glib_none().0,
718                mut_override(vectors_ptr),
719                num_vectors,
720                io_priority.into_glib(),
721                gcancellable.0,
722                Some(callback),
723                Box::into_raw(user_data) as *mut _,
724            );
725        }
726    }
727
728    #[cfg(feature = "v2_60")]
729    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
730    fn writev_all_future<B: AsRef<[u8]> + Send + 'static>(
731        &self,
732        vectors: impl IntoIterator<Item = B> + 'static,
733        io_priority: glib::Priority,
734    ) -> Pin<
735        Box<
736            dyn std::future::Future<
737                    Output = Result<(Vec<B>, usize, Option<glib::Error>), (Vec<B>, glib::Error)>,
738                > + 'static,
739        >,
740    > {
741        Box::pin(crate::GioFuture::new(
742            self,
743            move |obj, cancellable, send| {
744                obj.writev_all_async(vectors, io_priority, Some(cancellable), move |res| {
745                    send.resolve(res);
746                });
747            },
748        ))
749    }
750
751    fn into_write(self) -> OutputStreamWrite<Self>
752    where
753        Self: IsA<OutputStream>,
754    {
755        OutputStreamWrite(self)
756    }
757}
758
759impl<O: IsA<OutputStream>> OutputStreamExtManual for O {}
760
761#[derive(Debug)]
762pub struct OutputStreamWrite<T: IsA<OutputStream>>(T);
763
764impl<T: IsA<OutputStream>> OutputStreamWrite<T> {
765    pub fn into_output_stream(self) -> T {
766        self.0
767    }
768
769    pub fn output_stream(&self) -> &T {
770        &self.0
771    }
772}
773
774impl<T: IsA<OutputStream>> io::Write for OutputStreamWrite<T> {
775    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
776        let result = self
777            .0
778            .as_ref()
779            .write(buf, crate::Cancellable::NONE)
780            .map(|size| size as usize);
781        to_std_io_result(result)
782    }
783
784    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
785        let result = self
786            .0
787            .as_ref()
788            .write_all(buf, crate::Cancellable::NONE)
789            .and_then(|(_, e)| e.map(Err).unwrap_or(Ok(())));
790        to_std_io_result(result)
791    }
792
793    #[cfg(feature = "v2_60")]
794    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
795    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
796        let vectors = bufs
797            .iter()
798            .map(|v| OutputVector::new(v))
799            .collect::<smallvec::SmallVec<[_; 2]>>();
800        let result = self.0.as_ref().writev(&vectors, crate::Cancellable::NONE);
801        to_std_io_result(result)
802    }
803
804    fn flush(&mut self) -> io::Result<()> {
805        let gio_result = self.0.as_ref().flush(crate::Cancellable::NONE);
806        to_std_io_result(gio_result)
807    }
808}
809
810impl<T: IsA<OutputStream> + IsA<Seekable>> io::Seek for OutputStreamWrite<T> {
811    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
812        let (pos, type_) = match pos {
813            io::SeekFrom::Start(pos) => (pos as i64, glib::SeekType::Set),
814            io::SeekFrom::End(pos) => (pos, glib::SeekType::End),
815            io::SeekFrom::Current(pos) => (pos, glib::SeekType::Cur),
816        };
817        let seekable: &Seekable = self.0.as_ref();
818        let gio_result = seekable
819            .seek(pos, type_, crate::Cancellable::NONE)
820            .map(|_| seekable.tell() as u64);
821        to_std_io_result(gio_result)
822    }
823}
824
825#[cfg(test)]
826mod tests {
827    use std::io::Write;
828
829    use glib::Bytes;
830
831    #[cfg(feature = "v2_60")]
832    use crate::OutputVector;
833    use crate::{MemoryInputStream, MemoryOutputStream, prelude::*, test_util::run_async};
834
835    #[test]
836    fn splice_async() {
837        let ret = run_async(|tx, l| {
838            let input = MemoryInputStream::new();
839            let b = Bytes::from_owned(vec![1, 2, 3]);
840            input.add_bytes(&b);
841
842            let strm = MemoryOutputStream::new_resizable();
843            strm.splice_async(
844                &input,
845                crate::OutputStreamSpliceFlags::CLOSE_SOURCE,
846                glib::Priority::DEFAULT_IDLE,
847                crate::Cancellable::NONE,
848                move |ret| {
849                    tx.send(ret).unwrap();
850                    l.quit();
851                },
852            );
853        });
854
855        assert_eq!(ret.unwrap(), 3);
856    }
857
858    #[test]
859    fn write_async() {
860        let ret = run_async(|tx, l| {
861            let strm = MemoryOutputStream::new_resizable();
862
863            let buf = vec![1, 2, 3];
864            strm.write_async(
865                buf,
866                glib::Priority::DEFAULT_IDLE,
867                crate::Cancellable::NONE,
868                move |ret| {
869                    tx.send(ret).unwrap();
870                    l.quit();
871                },
872            );
873        });
874
875        let (buf, size) = ret.unwrap();
876        assert_eq!(buf, vec![1, 2, 3]);
877        assert_eq!(size, 3);
878    }
879
880    #[test]
881    fn write_all_async() {
882        let ret = run_async(|tx, l| {
883            let strm = MemoryOutputStream::new_resizable();
884
885            let buf = vec![1, 2, 3];
886            strm.write_all_async(
887                buf,
888                glib::Priority::DEFAULT_IDLE,
889                crate::Cancellable::NONE,
890                move |ret| {
891                    tx.send(ret).unwrap();
892                    l.quit();
893                },
894            );
895        });
896
897        let (buf, size) = ret.unwrap();
898        assert_eq!(buf, vec![1, 2, 3]);
899        assert_eq!(size, 3);
900    }
901
902    #[test]
903    fn write_all_future() {
904        let c = glib::MainContext::new();
905        let strm = MemoryOutputStream::new_resizable();
906
907        let (buf, size) = c
908            .block_on(strm.write_all_future(vec![1, 2, 3], glib::Priority::default()))
909            .unwrap();
910
911        assert_eq!(buf, vec![1, 2, 3]);
912        assert_eq!(size, 3);
913    }
914
915    #[test]
916    fn write_all_async_cancelled() {
917        let ret = run_async(|tx, l| {
918            let strm = MemoryOutputStream::new_resizable();
919            let cancellable = crate::Cancellable::new();
920            cancellable.cancel();
921
922            let buf = vec![1, 2, 3];
923            strm.write_all_async(
924                buf,
925                glib::Priority::DEFAULT_IDLE,
926                Some(&cancellable),
927                move |ret| {
928                    tx.send(ret).unwrap();
929                    l.quit();
930                },
931            );
932        });
933
934        let (buf, size, err) = ret.unwrap_err();
935        assert_eq!(buf, vec![1, 2, 3]);
936        assert_eq!(size, 0);
937        assert!(err.matches::<crate::IOErrorEnum>(crate::IOErrorEnum::Cancelled));
938    }
939
940    #[test]
941    fn write_bytes_async() {
942        let ret = run_async(|tx, l| {
943            let strm = MemoryOutputStream::new_resizable();
944
945            let b = Bytes::from_owned(vec![1, 2, 3]);
946            strm.write_bytes_async(
947                &b,
948                glib::Priority::DEFAULT_IDLE,
949                crate::Cancellable::NONE,
950                move |ret| {
951                    tx.send(ret).unwrap();
952                    l.quit();
953                },
954            );
955        });
956
957        assert_eq!(ret.unwrap(), 3);
958    }
959
960    #[test]
961    fn std_io_write() {
962        let b = Bytes::from_owned(vec![1, 2, 3]);
963        let mut write = MemoryOutputStream::new_resizable().into_write();
964
965        let ret = write.write(&b);
966
967        let stream = write.into_output_stream();
968        stream.close(crate::Cancellable::NONE).unwrap();
969        assert_eq!(ret.unwrap(), 3);
970        assert_eq!(stream.steal_as_bytes(), [1, 2, 3].as_ref());
971    }
972
973    #[test]
974    fn into_output_stream() {
975        let stream = MemoryOutputStream::new_resizable();
976        let stream_clone = stream.clone();
977        let stream = stream.into_write().into_output_stream();
978
979        assert_eq!(stream, stream_clone);
980    }
981
982    #[test]
983    #[cfg(feature = "v2_60")]
984    fn writev() {
985        let stream = MemoryOutputStream::new_resizable();
986
987        let ret = stream.writev(
988            &[OutputVector::new(&[1, 2, 3]), OutputVector::new(&[4, 5, 6])],
989            crate::Cancellable::NONE,
990        );
991        assert_eq!(ret.unwrap(), 6);
992        stream.close(crate::Cancellable::NONE).unwrap();
993        assert_eq!(stream.steal_as_bytes(), [1, 2, 3, 4, 5, 6].as_ref());
994    }
995
996    #[test]
997    #[cfg(feature = "v2_60")]
998    fn writev_async() {
999        let ret = run_async(|tx, l| {
1000            let strm = MemoryOutputStream::new_resizable();
1001
1002            let strm_clone = strm.clone();
1003            strm.writev_async(
1004                [vec![1, 2, 3], vec![4, 5, 6]],
1005                glib::Priority::DEFAULT_IDLE,
1006                crate::Cancellable::NONE,
1007                move |ret| {
1008                    tx.send(ret).unwrap();
1009                    strm_clone.close(crate::Cancellable::NONE).unwrap();
1010                    assert_eq!(strm_clone.steal_as_bytes(), [1, 2, 3, 4, 5, 6].as_ref());
1011                    l.quit();
1012                },
1013            );
1014        });
1015
1016        let (buf, size) = ret.unwrap();
1017        assert_eq!(buf, [[1, 2, 3], [4, 5, 6]]);
1018        assert_eq!(size, 6);
1019    }
1020
1021    #[test]
1022    #[cfg(feature = "v2_60")]
1023    fn writev_all_async() {
1024        let ret = run_async(|tx, l| {
1025            let strm = MemoryOutputStream::new_resizable();
1026
1027            let strm_clone = strm.clone();
1028            strm.writev_all_async(
1029                [vec![1, 2, 3], vec![4, 5, 6]],
1030                glib::Priority::DEFAULT_IDLE,
1031                crate::Cancellable::NONE,
1032                move |ret| {
1033                    tx.send(ret).unwrap();
1034                    strm_clone.close(crate::Cancellable::NONE).unwrap();
1035                    assert_eq!(strm_clone.steal_as_bytes(), [1, 2, 3, 4, 5, 6].as_ref());
1036                    l.quit();
1037                },
1038            );
1039        });
1040
1041        let (buf, size, err) = ret.unwrap();
1042        assert_eq!(buf, [[1, 2, 3], [4, 5, 6]]);
1043        assert_eq!(size, 6);
1044        assert!(err.is_none());
1045    }
1046}