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::{prelude::*, translate::*, Priority};
6
7#[cfg(feature = "v2_60")]
8use crate::OutputVector;
9use crate::{error::to_std_io_result, ffi, prelude::*, Cancellable, OutputStream, Seekable};
10
11mod sealed {
12    pub trait Sealed {}
13    impl<T: super::IsA<super::OutputStream>> Sealed for T {}
14}
15
16pub trait OutputStreamExtManual: sealed::Sealed + IsA<OutputStream> + Sized {
17    #[doc(alias = "g_output_stream_write_async")]
18    fn write_async<
19        B: AsRef<[u8]> + Send + 'static,
20        Q: FnOnce(Result<(B, usize), (B, glib::Error)>) + 'static,
21        C: IsA<Cancellable>,
22    >(
23        &self,
24        buffer: B,
25        io_priority: Priority,
26        cancellable: Option<&C>,
27        callback: Q,
28    ) {
29        let main_context = glib::MainContext::ref_thread_default();
30        let is_main_context_owner = main_context.is_owner();
31        let has_acquired_main_context = (!is_main_context_owner)
32            .then(|| main_context.acquire().ok())
33            .flatten();
34        assert!(
35            is_main_context_owner || has_acquired_main_context.is_some(),
36            "Async operations only allowed if the thread is owning the MainContext"
37        );
38
39        let cancellable = cancellable.map(|c| c.as_ref());
40        let gcancellable = cancellable.to_glib_none();
41        let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
42            Box::new((glib::thread_guard::ThreadGuard::new(callback), buffer));
43        // Need to do this after boxing as the contents pointer might change by moving into the box
44        let (count, buffer_ptr) = {
45            let buffer = &user_data.1;
46            let slice = buffer.as_ref();
47            (slice.len(), slice.as_ptr())
48        };
49        unsafe extern "C" fn write_async_trampoline<
50            B: AsRef<[u8]> + Send + 'static,
51            Q: FnOnce(Result<(B, usize), (B, glib::Error)>) + 'static,
52        >(
53            _source_object: *mut glib::gobject_ffi::GObject,
54            res: *mut ffi::GAsyncResult,
55            user_data: glib::ffi::gpointer,
56        ) {
57            let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
58                Box::from_raw(user_data as *mut _);
59            let (callback, buffer) = *user_data;
60            let callback = callback.into_inner();
61
62            let mut error = ptr::null_mut();
63            let ret = ffi::g_output_stream_write_finish(_source_object as *mut _, res, &mut error);
64            let result = if error.is_null() {
65                Ok((buffer, ret as usize))
66            } else {
67                Err((buffer, from_glib_full(error)))
68            };
69            callback(result);
70        }
71        let callback = write_async_trampoline::<B, Q>;
72        unsafe {
73            ffi::g_output_stream_write_async(
74                self.as_ref().to_glib_none().0,
75                mut_override(buffer_ptr),
76                count,
77                io_priority.into_glib(),
78                gcancellable.0,
79                Some(callback),
80                Box::into_raw(user_data) as *mut _,
81            );
82        }
83    }
84
85    #[doc(alias = "g_output_stream_write_all")]
86    fn write_all<C: IsA<Cancellable>>(
87        &self,
88        buffer: &[u8],
89        cancellable: Option<&C>,
90    ) -> Result<(usize, Option<glib::Error>), glib::Error> {
91        let cancellable = cancellable.map(|c| c.as_ref());
92        let gcancellable = cancellable.to_glib_none();
93        let count = buffer.len();
94        unsafe {
95            let mut bytes_written = mem::MaybeUninit::uninit();
96            let mut error = ptr::null_mut();
97            let _ = ffi::g_output_stream_write_all(
98                self.as_ref().to_glib_none().0,
99                buffer.to_glib_none().0,
100                count,
101                bytes_written.as_mut_ptr(),
102                gcancellable.0,
103                &mut error,
104            );
105
106            let bytes_written = bytes_written.assume_init();
107            if error.is_null() {
108                Ok((bytes_written, None))
109            } else if bytes_written != 0 {
110                Ok((bytes_written, Some(from_glib_full(error))))
111            } else {
112                Err(from_glib_full(error))
113            }
114        }
115    }
116
117    #[doc(alias = "g_output_stream_write_all_async")]
118    fn write_all_async<
119        B: AsRef<[u8]> + Send + 'static,
120        Q: FnOnce(Result<(B, usize, Option<glib::Error>), (B, glib::Error)>) + 'static,
121        C: IsA<Cancellable>,
122    >(
123        &self,
124        buffer: B,
125        io_priority: Priority,
126        cancellable: Option<&C>,
127        callback: Q,
128    ) {
129        let main_context = glib::MainContext::ref_thread_default();
130        let is_main_context_owner = main_context.is_owner();
131        let has_acquired_main_context = (!is_main_context_owner)
132            .then(|| main_context.acquire().ok())
133            .flatten();
134        assert!(
135            is_main_context_owner || has_acquired_main_context.is_some(),
136            "Async operations only allowed if the thread is owning the MainContext"
137        );
138
139        let cancellable = cancellable.map(|c| c.as_ref());
140        let gcancellable = cancellable.to_glib_none();
141        let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
142            Box::new((glib::thread_guard::ThreadGuard::new(callback), buffer));
143        // Need to do this after boxing as the contents pointer might change by moving into the box
144        let (count, buffer_ptr) = {
145            let buffer = &user_data.1;
146            let slice = buffer.as_ref();
147            (slice.len(), slice.as_ptr())
148        };
149        unsafe extern "C" fn write_all_async_trampoline<
150            B: AsRef<[u8]> + Send + 'static,
151            Q: FnOnce(Result<(B, usize, Option<glib::Error>), (B, glib::Error)>) + 'static,
152        >(
153            _source_object: *mut glib::gobject_ffi::GObject,
154            res: *mut ffi::GAsyncResult,
155            user_data: glib::ffi::gpointer,
156        ) {
157            let user_data: Box<(glib::thread_guard::ThreadGuard<Q>, B)> =
158                Box::from_raw(user_data as *mut _);
159            let (callback, buffer) = *user_data;
160            let callback = callback.into_inner();
161
162            let mut error = ptr::null_mut();
163            let mut bytes_written = mem::MaybeUninit::uninit();
164            let _ = ffi::g_output_stream_write_all_finish(
165                _source_object as *mut _,
166                res,
167                bytes_written.as_mut_ptr(),
168                &mut error,
169            );
170            let bytes_written = bytes_written.assume_init();
171            let result = if error.is_null() {
172                Ok((buffer, bytes_written, None))
173            } else if bytes_written != 0 {
174                Ok((buffer, bytes_written, from_glib_full(error)))
175            } else {
176                Err((buffer, from_glib_full(error)))
177            };
178            callback(result);
179        }
180        let callback = write_all_async_trampoline::<B, Q>;
181        unsafe {
182            ffi::g_output_stream_write_all_async(
183                self.as_ref().to_glib_none().0,
184                mut_override(buffer_ptr),
185                count,
186                io_priority.into_glib(),
187                gcancellable.0,
188                Some(callback),
189                Box::into_raw(user_data) as *mut _,
190            );
191        }
192    }
193
194    fn write_future<B: AsRef<[u8]> + Send + 'static>(
195        &self,
196        buffer: B,
197        io_priority: Priority,
198    ) -> Pin<Box<dyn std::future::Future<Output = Result<(B, usize), (B, glib::Error)>> + 'static>>
199    {
200        Box::pin(crate::GioFuture::new(
201            self,
202            move |obj, cancellable, send| {
203                obj.write_async(buffer, io_priority, Some(cancellable), move |res| {
204                    send.resolve(res);
205                });
206            },
207        ))
208    }
209
210    fn write_all_future<B: AsRef<[u8]> + Send + 'static>(
211        &self,
212        buffer: B,
213        io_priority: Priority,
214    ) -> Pin<
215        Box<
216            dyn std::future::Future<
217                    Output = Result<(B, usize, Option<glib::Error>), (B, glib::Error)>,
218                > + 'static,
219        >,
220    > {
221        Box::pin(crate::GioFuture::new(
222            self,
223            move |obj, cancellable, send| {
224                obj.write_all_async(buffer, io_priority, Some(cancellable), move |res| {
225                    send.resolve(res);
226                });
227            },
228        ))
229    }
230
231    #[cfg(feature = "v2_60")]
232    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
233    #[doc(alias = "g_output_stream_writev")]
234    fn writev(
235        &self,
236        vectors: &[OutputVector],
237        cancellable: Option<&impl IsA<Cancellable>>,
238    ) -> Result<usize, glib::Error> {
239        unsafe {
240            let mut error = ptr::null_mut();
241            let mut bytes_written = mem::MaybeUninit::uninit();
242
243            ffi::g_output_stream_writev(
244                self.as_ref().to_glib_none().0,
245                vectors.as_ptr() as *const _,
246                vectors.len(),
247                bytes_written.as_mut_ptr(),
248                cancellable.map(|p| p.as_ref()).to_glib_none().0,
249                &mut error,
250            );
251            if error.is_null() {
252                Ok(bytes_written.assume_init())
253            } else {
254                Err(from_glib_full(error))
255            }
256        }
257    }
258
259    #[cfg(feature = "v2_60")]
260    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
261    #[doc(alias = "g_output_stream_writev_async")]
262    fn writev_async<
263        B: AsRef<[u8]> + Send + 'static,
264        P: FnOnce(Result<(Vec<B>, usize), (Vec<B>, glib::Error)>) + 'static,
265    >(
266        &self,
267        vectors: impl IntoIterator<Item = B> + 'static,
268        io_priority: glib::Priority,
269        cancellable: Option<&impl IsA<Cancellable>>,
270        callback: P,
271    ) {
272        let main_context = glib::MainContext::ref_thread_default();
273        let is_main_context_owner = main_context.is_owner();
274        let has_acquired_main_context = (!is_main_context_owner)
275            .then(|| main_context.acquire().ok())
276            .flatten();
277        assert!(
278            is_main_context_owner || has_acquired_main_context.is_some(),
279            "Async operations only allowed if the thread is owning the MainContext"
280        );
281
282        let cancellable = cancellable.map(|c| c.as_ref());
283        let gcancellable = cancellable.to_glib_none();
284        let buffers = vectors.into_iter().collect::<Vec<_>>();
285        let vectors = buffers
286            .iter()
287            .map(|v| ffi::GOutputVector {
288                buffer: v.as_ref().as_ptr() as *const _,
289                size: v.as_ref().len(),
290            })
291            .collect::<Vec<_>>();
292        let vectors_ptr = vectors.as_ptr();
293        let num_vectors = vectors.len();
294        let user_data: Box<(
295            glib::thread_guard::ThreadGuard<P>,
296            Vec<B>,
297            Vec<ffi::GOutputVector>,
298        )> = Box::new((
299            glib::thread_guard::ThreadGuard::new(callback),
300            buffers,
301            vectors,
302        ));
303
304        unsafe extern "C" fn writev_async_trampoline<
305            B: AsRef<[u8]> + Send + 'static,
306            P: FnOnce(Result<(Vec<B>, usize), (Vec<B>, glib::Error)>) + 'static,
307        >(
308            _source_object: *mut glib::gobject_ffi::GObject,
309            res: *mut ffi::GAsyncResult,
310            user_data: glib::ffi::gpointer,
311        ) {
312            let user_data: Box<(
313                glib::thread_guard::ThreadGuard<P>,
314                Vec<B>,
315                Vec<ffi::GOutputVector>,
316            )> = Box::from_raw(user_data as *mut _);
317            let (callback, buffers, _) = *user_data;
318            let callback = callback.into_inner();
319
320            let mut error = ptr::null_mut();
321            let mut bytes_written = mem::MaybeUninit::uninit();
322            ffi::g_output_stream_writev_finish(
323                _source_object as *mut _,
324                res,
325                bytes_written.as_mut_ptr(),
326                &mut error,
327            );
328            let bytes_written = bytes_written.assume_init();
329            let result = if error.is_null() {
330                Ok((buffers, bytes_written))
331            } else {
332                Err((buffers, from_glib_full(error)))
333            };
334            callback(result);
335        }
336        let callback = writev_async_trampoline::<B, P>;
337        unsafe {
338            ffi::g_output_stream_writev_async(
339                self.as_ref().to_glib_none().0,
340                vectors_ptr,
341                num_vectors,
342                io_priority.into_glib(),
343                gcancellable.0,
344                Some(callback),
345                Box::into_raw(user_data) as *mut _,
346            );
347        }
348    }
349
350    #[cfg(feature = "v2_60")]
351    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
352    fn writev_future<B: AsRef<[u8]> + Send + 'static>(
353        &self,
354        vectors: impl IntoIterator<Item = B> + 'static,
355        io_priority: glib::Priority,
356    ) -> Pin<
357        Box<
358            dyn std::future::Future<Output = Result<(Vec<B>, usize), (Vec<B>, glib::Error)>>
359                + 'static,
360        >,
361    > {
362        Box::pin(crate::GioFuture::new(
363            self,
364            move |obj, cancellable, send| {
365                obj.writev_async(vectors, io_priority, Some(cancellable), move |res| {
366                    send.resolve(res);
367                });
368            },
369        ))
370    }
371
372    #[cfg(feature = "v2_60")]
373    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
374    #[doc(alias = "g_output_stream_writev_all")]
375    fn writev_all(
376        &self,
377        vectors: &[OutputVector],
378        cancellable: Option<&impl IsA<Cancellable>>,
379    ) -> Result<(usize, Option<glib::Error>), glib::Error> {
380        unsafe {
381            let mut error = ptr::null_mut();
382            let mut bytes_written = mem::MaybeUninit::uninit();
383
384            ffi::g_output_stream_writev_all(
385                self.as_ref().to_glib_none().0,
386                mut_override(vectors.as_ptr() as *const _),
387                vectors.len(),
388                bytes_written.as_mut_ptr(),
389                cancellable.map(|p| p.as_ref()).to_glib_none().0,
390                &mut error,
391            );
392            let bytes_written = bytes_written.assume_init();
393            if error.is_null() {
394                Ok((bytes_written, None))
395            } else if bytes_written != 0 {
396                Ok((bytes_written, Some(from_glib_full(error))))
397            } else {
398                Err(from_glib_full(error))
399            }
400        }
401    }
402
403    #[cfg(feature = "v2_60")]
404    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
405    #[doc(alias = "g_output_stream_writev_all_async")]
406    fn writev_all_async<
407        B: AsRef<[u8]> + Send + 'static,
408        P: FnOnce(Result<(Vec<B>, usize, Option<glib::Error>), (Vec<B>, glib::Error)>) + 'static,
409    >(
410        &self,
411        vectors: impl IntoIterator<Item = B> + 'static,
412        io_priority: glib::Priority,
413        cancellable: Option<&impl IsA<Cancellable>>,
414        callback: P,
415    ) {
416        let main_context = glib::MainContext::ref_thread_default();
417        let is_main_context_owner = main_context.is_owner();
418        let has_acquired_main_context = (!is_main_context_owner)
419            .then(|| main_context.acquire().ok())
420            .flatten();
421        assert!(
422            is_main_context_owner || has_acquired_main_context.is_some(),
423            "Async operations only allowed if the thread is owning the MainContext"
424        );
425
426        let cancellable = cancellable.map(|c| c.as_ref());
427        let gcancellable = cancellable.to_glib_none();
428        let buffers = vectors.into_iter().collect::<Vec<_>>();
429        let vectors = buffers
430            .iter()
431            .map(|v| ffi::GOutputVector {
432                buffer: v.as_ref().as_ptr() as *const _,
433                size: v.as_ref().len(),
434            })
435            .collect::<Vec<_>>();
436        let vectors_ptr = vectors.as_ptr();
437        let num_vectors = vectors.len();
438        let user_data: Box<(
439            glib::thread_guard::ThreadGuard<P>,
440            Vec<B>,
441            Vec<ffi::GOutputVector>,
442        )> = Box::new((
443            glib::thread_guard::ThreadGuard::new(callback),
444            buffers,
445            vectors,
446        ));
447
448        unsafe extern "C" fn writev_all_async_trampoline<
449            B: AsRef<[u8]> + Send + 'static,
450            P: FnOnce(Result<(Vec<B>, usize, Option<glib::Error>), (Vec<B>, glib::Error)>) + 'static,
451        >(
452            _source_object: *mut glib::gobject_ffi::GObject,
453            res: *mut ffi::GAsyncResult,
454            user_data: glib::ffi::gpointer,
455        ) {
456            let user_data: Box<(
457                glib::thread_guard::ThreadGuard<P>,
458                Vec<B>,
459                Vec<ffi::GOutputVector>,
460            )> = Box::from_raw(user_data as *mut _);
461            let (callback, buffers, _) = *user_data;
462            let callback = callback.into_inner();
463
464            let mut error = ptr::null_mut();
465            let mut bytes_written = mem::MaybeUninit::uninit();
466            ffi::g_output_stream_writev_all_finish(
467                _source_object as *mut _,
468                res,
469                bytes_written.as_mut_ptr(),
470                &mut error,
471            );
472            let bytes_written = bytes_written.assume_init();
473            let result = if error.is_null() {
474                Ok((buffers, bytes_written, None))
475            } else if bytes_written != 0 {
476                Ok((buffers, bytes_written, from_glib_full(error)))
477            } else {
478                Err((buffers, from_glib_full(error)))
479            };
480            callback(result);
481        }
482        let callback = writev_all_async_trampoline::<B, P>;
483        unsafe {
484            ffi::g_output_stream_writev_all_async(
485                self.as_ref().to_glib_none().0,
486                mut_override(vectors_ptr),
487                num_vectors,
488                io_priority.into_glib(),
489                gcancellable.0,
490                Some(callback),
491                Box::into_raw(user_data) as *mut _,
492            );
493        }
494    }
495
496    #[cfg(feature = "v2_60")]
497    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
498    fn writev_all_future<B: AsRef<[u8]> + Send + 'static>(
499        &self,
500        vectors: impl IntoIterator<Item = B> + 'static,
501        io_priority: glib::Priority,
502    ) -> Pin<
503        Box<
504            dyn std::future::Future<
505                    Output = Result<(Vec<B>, usize, Option<glib::Error>), (Vec<B>, glib::Error)>,
506                > + 'static,
507        >,
508    > {
509        Box::pin(crate::GioFuture::new(
510            self,
511            move |obj, cancellable, send| {
512                obj.writev_all_async(vectors, io_priority, Some(cancellable), move |res| {
513                    send.resolve(res);
514                });
515            },
516        ))
517    }
518
519    fn into_write(self) -> OutputStreamWrite<Self>
520    where
521        Self: IsA<OutputStream>,
522    {
523        OutputStreamWrite(self)
524    }
525}
526
527impl<O: IsA<OutputStream>> OutputStreamExtManual for O {}
528
529#[derive(Debug)]
530pub struct OutputStreamWrite<T: IsA<OutputStream>>(T);
531
532impl<T: IsA<OutputStream>> OutputStreamWrite<T> {
533    pub fn into_output_stream(self) -> T {
534        self.0
535    }
536
537    pub fn output_stream(&self) -> &T {
538        &self.0
539    }
540}
541
542impl<T: IsA<OutputStream>> io::Write for OutputStreamWrite<T> {
543    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
544        let result = self
545            .0
546            .as_ref()
547            .write(buf, crate::Cancellable::NONE)
548            .map(|size| size as usize);
549        to_std_io_result(result)
550    }
551
552    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
553        let result = self
554            .0
555            .as_ref()
556            .write_all(buf, crate::Cancellable::NONE)
557            .and_then(|(_, e)| e.map(Err).unwrap_or(Ok(())));
558        to_std_io_result(result)
559    }
560
561    #[cfg(feature = "v2_60")]
562    #[cfg_attr(docsrs, doc(cfg(feature = "v2_60")))]
563    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
564        let vectors = bufs
565            .iter()
566            .map(|v| OutputVector::new(v))
567            .collect::<smallvec::SmallVec<[_; 2]>>();
568        let result = self.0.as_ref().writev(&vectors, crate::Cancellable::NONE);
569        to_std_io_result(result)
570    }
571
572    fn flush(&mut self) -> io::Result<()> {
573        let gio_result = self.0.as_ref().flush(crate::Cancellable::NONE);
574        to_std_io_result(gio_result)
575    }
576}
577
578impl<T: IsA<OutputStream> + IsA<Seekable>> io::Seek for OutputStreamWrite<T> {
579    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
580        let (pos, type_) = match pos {
581            io::SeekFrom::Start(pos) => (pos as i64, glib::SeekType::Set),
582            io::SeekFrom::End(pos) => (pos, glib::SeekType::End),
583            io::SeekFrom::Current(pos) => (pos, glib::SeekType::Cur),
584        };
585        let seekable: &Seekable = self.0.as_ref();
586        let gio_result = seekable
587            .seek(pos, type_, crate::Cancellable::NONE)
588            .map(|_| seekable.tell() as u64);
589        to_std_io_result(gio_result)
590    }
591}
592
593#[cfg(test)]
594mod tests {
595    use std::io::Write;
596
597    use glib::Bytes;
598
599    #[cfg(feature = "v2_60")]
600    use crate::OutputVector;
601    use crate::{prelude::*, test_util::run_async, MemoryInputStream, MemoryOutputStream};
602
603    #[test]
604    fn splice_async() {
605        let ret = run_async(|tx, l| {
606            let input = MemoryInputStream::new();
607            let b = Bytes::from_owned(vec![1, 2, 3]);
608            input.add_bytes(&b);
609
610            let strm = MemoryOutputStream::new_resizable();
611            strm.splice_async(
612                &input,
613                crate::OutputStreamSpliceFlags::CLOSE_SOURCE,
614                glib::Priority::DEFAULT_IDLE,
615                crate::Cancellable::NONE,
616                move |ret| {
617                    tx.send(ret).unwrap();
618                    l.quit();
619                },
620            );
621        });
622
623        assert_eq!(ret.unwrap(), 3);
624    }
625
626    #[test]
627    fn write_async() {
628        let ret = run_async(|tx, l| {
629            let strm = MemoryOutputStream::new_resizable();
630
631            let buf = vec![1, 2, 3];
632            strm.write_async(
633                buf,
634                glib::Priority::DEFAULT_IDLE,
635                crate::Cancellable::NONE,
636                move |ret| {
637                    tx.send(ret).unwrap();
638                    l.quit();
639                },
640            );
641        });
642
643        let (buf, size) = ret.unwrap();
644        assert_eq!(buf, vec![1, 2, 3]);
645        assert_eq!(size, 3);
646    }
647
648    #[test]
649    fn write_all_async() {
650        let ret = run_async(|tx, l| {
651            let strm = MemoryOutputStream::new_resizable();
652
653            let buf = vec![1, 2, 3];
654            strm.write_all_async(
655                buf,
656                glib::Priority::DEFAULT_IDLE,
657                crate::Cancellable::NONE,
658                move |ret| {
659                    tx.send(ret).unwrap();
660                    l.quit();
661                },
662            );
663        });
664
665        let (buf, size, err) = ret.unwrap();
666        assert_eq!(buf, vec![1, 2, 3]);
667        assert_eq!(size, 3);
668        assert!(err.is_none());
669    }
670
671    #[test]
672    fn write_bytes_async() {
673        let ret = run_async(|tx, l| {
674            let strm = MemoryOutputStream::new_resizable();
675
676            let b = Bytes::from_owned(vec![1, 2, 3]);
677            strm.write_bytes_async(
678                &b,
679                glib::Priority::DEFAULT_IDLE,
680                crate::Cancellable::NONE,
681                move |ret| {
682                    tx.send(ret).unwrap();
683                    l.quit();
684                },
685            );
686        });
687
688        assert_eq!(ret.unwrap(), 3);
689    }
690
691    #[test]
692    fn std_io_write() {
693        let b = Bytes::from_owned(vec![1, 2, 3]);
694        let mut write = MemoryOutputStream::new_resizable().into_write();
695
696        let ret = write.write(&b);
697
698        let stream = write.into_output_stream();
699        stream.close(crate::Cancellable::NONE).unwrap();
700        assert_eq!(ret.unwrap(), 3);
701        assert_eq!(stream.steal_as_bytes(), [1, 2, 3].as_ref());
702    }
703
704    #[test]
705    fn into_output_stream() {
706        let stream = MemoryOutputStream::new_resizable();
707        let stream_clone = stream.clone();
708        let stream = stream.into_write().into_output_stream();
709
710        assert_eq!(stream, stream_clone);
711    }
712
713    #[test]
714    #[cfg(feature = "v2_60")]
715    fn writev() {
716        let stream = MemoryOutputStream::new_resizable();
717
718        let ret = stream.writev(
719            &[OutputVector::new(&[1, 2, 3]), OutputVector::new(&[4, 5, 6])],
720            crate::Cancellable::NONE,
721        );
722        assert_eq!(ret.unwrap(), 6);
723        stream.close(crate::Cancellable::NONE).unwrap();
724        assert_eq!(stream.steal_as_bytes(), [1, 2, 3, 4, 5, 6].as_ref());
725    }
726
727    #[test]
728    #[cfg(feature = "v2_60")]
729    fn writev_async() {
730        let ret = run_async(|tx, l| {
731            let strm = MemoryOutputStream::new_resizable();
732
733            let strm_clone = strm.clone();
734            strm.writev_async(
735                [vec![1, 2, 3], vec![4, 5, 6]],
736                glib::Priority::DEFAULT_IDLE,
737                crate::Cancellable::NONE,
738                move |ret| {
739                    tx.send(ret).unwrap();
740                    strm_clone.close(crate::Cancellable::NONE).unwrap();
741                    assert_eq!(strm_clone.steal_as_bytes(), [1, 2, 3, 4, 5, 6].as_ref());
742                    l.quit();
743                },
744            );
745        });
746
747        let (buf, size) = ret.unwrap();
748        assert_eq!(buf, [[1, 2, 3], [4, 5, 6]]);
749        assert_eq!(size, 6);
750    }
751
752    #[test]
753    #[cfg(feature = "v2_60")]
754    fn writev_all_async() {
755        let ret = run_async(|tx, l| {
756            let strm = MemoryOutputStream::new_resizable();
757
758            let strm_clone = strm.clone();
759            strm.writev_all_async(
760                [vec![1, 2, 3], vec![4, 5, 6]],
761                glib::Priority::DEFAULT_IDLE,
762                crate::Cancellable::NONE,
763                move |ret| {
764                    tx.send(ret).unwrap();
765                    strm_clone.close(crate::Cancellable::NONE).unwrap();
766                    assert_eq!(strm_clone.steal_as_bytes(), [1, 2, 3, 4, 5, 6].as_ref());
767                    l.quit();
768                },
769            );
770        });
771
772        let (buf, size, err) = ret.unwrap();
773        assert_eq!(buf, [[1, 2, 3], [4, 5, 6]]);
774        assert_eq!(size, 6);
775        assert!(err.is_none());
776    }
777}