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