1use 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 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 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}