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