gio/subclass/
output_stream.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*, Error};
6
7use crate::{ffi, Cancellable, InputStream, OutputStream, OutputStreamSpliceFlags};
8
9pub trait OutputStreamImpl: ObjectImpl + OutputStreamImplExt + Send {
10    fn write(&self, buffer: &[u8], cancellable: Option<&Cancellable>) -> Result<usize, Error> {
11        self.parent_write(buffer, cancellable)
12    }
13
14    fn close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
15        self.parent_close(cancellable)
16    }
17
18    /// Forces a write of all user-space buffered data for the given
19    /// @self. Will block during the operation. Closing the stream will
20    /// implicitly cause a flush.
21    ///
22    /// This function is optional for inherited classes.
23    ///
24    /// If @cancellable is not [`None`], then the operation can be cancelled by
25    /// triggering the cancellable object from another thread. If the operation
26    /// was cancelled, the error [`IOErrorEnum::Cancelled`][crate::IOErrorEnum::Cancelled] will be returned.
27    /// ## `cancellable`
28    /// optional cancellable object
29    ///
30    /// # Returns
31    ///
32    /// [`true`] on success, [`false`] on error
33    fn flush(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
34        self.parent_flush(cancellable)
35    }
36
37    /// Splices an input stream into an output stream.
38    /// ## `source`
39    /// a #GInputStream.
40    /// ## `flags`
41    /// a set of #GOutputStreamSpliceFlags.
42    /// ## `cancellable`
43    /// optional #GCancellable object, [`None`] to ignore.
44    ///
45    /// # Returns
46    ///
47    /// a #gssize containing the size of the data spliced, or
48    ///     -1 if an error occurred. Note that if the number of bytes
49    ///     spliced is greater than `G_MAXSSIZE`, then that will be
50    ///     returned, and there is no way to determine the actual number
51    ///     of bytes spliced.
52    fn splice(
53        &self,
54        input_stream: &InputStream,
55        flags: OutputStreamSpliceFlags,
56        cancellable: Option<&Cancellable>,
57    ) -> Result<usize, Error> {
58        self.parent_splice(input_stream, flags, cancellable)
59    }
60}
61
62mod sealed {
63    pub trait Sealed {}
64    impl<T: super::OutputStreamImplExt> Sealed for T {}
65}
66
67pub trait OutputStreamImplExt: sealed::Sealed + ObjectSubclass {
68    fn parent_write(
69        &self,
70        buffer: &[u8],
71        cancellable: Option<&Cancellable>,
72    ) -> Result<usize, Error> {
73        unsafe {
74            let data = Self::type_data();
75            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
76            let f = (*parent_class)
77                .write_fn
78                .expect("No parent class implementation for \"write\"");
79            let mut err = ptr::null_mut();
80            let res = f(
81                self.obj()
82                    .unsafe_cast_ref::<OutputStream>()
83                    .to_glib_none()
84                    .0,
85                mut_override(buffer.as_ptr()),
86                buffer.len(),
87                cancellable.to_glib_none().0,
88                &mut err,
89            );
90            if res == -1 {
91                Err(from_glib_full(err))
92            } else {
93                debug_assert!(res >= 0);
94                let res = res as usize;
95                debug_assert!(res <= buffer.len());
96                Ok(res)
97            }
98        }
99    }
100
101    fn parent_close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
102        unsafe {
103            let data = Self::type_data();
104            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
105            let mut err = ptr::null_mut();
106            if let Some(f) = (*parent_class).close_fn {
107                if from_glib(f(
108                    self.obj()
109                        .unsafe_cast_ref::<OutputStream>()
110                        .to_glib_none()
111                        .0,
112                    cancellable.to_glib_none().0,
113                    &mut err,
114                )) {
115                    Ok(())
116                } else {
117                    Err(from_glib_full(err))
118                }
119            } else {
120                Ok(())
121            }
122        }
123    }
124
125    fn parent_flush(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
126        unsafe {
127            let data = Self::type_data();
128            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
129            let mut err = ptr::null_mut();
130            if let Some(f) = (*parent_class).flush {
131                if from_glib(f(
132                    self.obj()
133                        .unsafe_cast_ref::<OutputStream>()
134                        .to_glib_none()
135                        .0,
136                    cancellable.to_glib_none().0,
137                    &mut err,
138                )) {
139                    Ok(())
140                } else {
141                    Err(from_glib_full(err))
142                }
143            } else {
144                Ok(())
145            }
146        }
147    }
148
149    fn parent_splice(
150        &self,
151        input_stream: &InputStream,
152        flags: OutputStreamSpliceFlags,
153        cancellable: Option<&Cancellable>,
154    ) -> Result<usize, Error> {
155        unsafe {
156            let data = Self::type_data();
157            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
158            let mut err = ptr::null_mut();
159            let f = (*parent_class)
160                .splice
161                .expect("No parent class implementation for \"splice\"");
162            let res = f(
163                self.obj()
164                    .unsafe_cast_ref::<OutputStream>()
165                    .to_glib_none()
166                    .0,
167                input_stream.to_glib_none().0,
168                flags.into_glib(),
169                cancellable.to_glib_none().0,
170                &mut err,
171            );
172            if res == -1 {
173                Err(from_glib_full(err))
174            } else {
175                debug_assert!(res >= 0);
176                let res = res as usize;
177                Ok(res)
178            }
179        }
180    }
181}
182
183impl<T: OutputStreamImpl> OutputStreamImplExt for T {}
184
185unsafe impl<T: OutputStreamImpl> IsSubclassable<T> for OutputStream {
186    fn class_init(class: &mut ::glib::Class<Self>) {
187        Self::parent_class_init::<T>(class);
188
189        let klass = class.as_mut();
190        klass.write_fn = Some(stream_write::<T>);
191        klass.close_fn = Some(stream_close::<T>);
192        klass.flush = Some(stream_flush::<T>);
193        klass.splice = Some(stream_splice::<T>);
194    }
195}
196
197unsafe extern "C" fn stream_write<T: OutputStreamImpl>(
198    ptr: *mut ffi::GOutputStream,
199    buffer: *mut u8,
200    count: usize,
201    cancellable: *mut ffi::GCancellable,
202    err: *mut *mut glib::ffi::GError,
203) -> isize {
204    debug_assert!(count <= isize::MAX as usize);
205
206    let instance = &*(ptr as *mut T::Instance);
207    let imp = instance.imp();
208
209    match imp.write(
210        if count == 0 {
211            &[]
212        } else {
213            std::slice::from_raw_parts(buffer as *const u8, count)
214        },
215        Option::<Cancellable>::from_glib_borrow(cancellable)
216            .as_ref()
217            .as_ref(),
218    ) {
219        Ok(res) => {
220            assert!(res <= isize::MAX as usize);
221            assert!(res <= count);
222            res as isize
223        }
224        Err(e) => {
225            if !err.is_null() {
226                *err = e.into_glib_ptr();
227            }
228            -1
229        }
230    }
231}
232
233unsafe extern "C" fn stream_close<T: OutputStreamImpl>(
234    ptr: *mut ffi::GOutputStream,
235    cancellable: *mut ffi::GCancellable,
236    err: *mut *mut glib::ffi::GError,
237) -> glib::ffi::gboolean {
238    let instance = &*(ptr as *mut T::Instance);
239    let imp = instance.imp();
240
241    match imp.close(
242        Option::<Cancellable>::from_glib_borrow(cancellable)
243            .as_ref()
244            .as_ref(),
245    ) {
246        Ok(_) => glib::ffi::GTRUE,
247        Err(e) => {
248            if !err.is_null() {
249                *err = e.into_glib_ptr();
250            }
251            glib::ffi::GFALSE
252        }
253    }
254}
255
256unsafe extern "C" fn stream_flush<T: OutputStreamImpl>(
257    ptr: *mut ffi::GOutputStream,
258    cancellable: *mut ffi::GCancellable,
259    err: *mut *mut glib::ffi::GError,
260) -> glib::ffi::gboolean {
261    let instance = &*(ptr as *mut T::Instance);
262    let imp = instance.imp();
263
264    match imp.flush(
265        Option::<Cancellable>::from_glib_borrow(cancellable)
266            .as_ref()
267            .as_ref(),
268    ) {
269        Ok(_) => glib::ffi::GTRUE,
270        Err(e) => {
271            if !err.is_null() {
272                *err = e.into_glib_ptr();
273            }
274            glib::ffi::GFALSE
275        }
276    }
277}
278
279unsafe extern "C" fn stream_splice<T: OutputStreamImpl>(
280    ptr: *mut ffi::GOutputStream,
281    input_stream: *mut ffi::GInputStream,
282    flags: ffi::GOutputStreamSpliceFlags,
283    cancellable: *mut ffi::GCancellable,
284    err: *mut *mut glib::ffi::GError,
285) -> isize {
286    let instance = &*(ptr as *mut T::Instance);
287    let imp = instance.imp();
288
289    match imp.splice(
290        &from_glib_borrow(input_stream),
291        from_glib(flags),
292        Option::<Cancellable>::from_glib_borrow(cancellable)
293            .as_ref()
294            .as_ref(),
295    ) {
296        Ok(res) => {
297            assert!(res <= isize::MAX as usize);
298            res as isize
299        }
300        Err(e) => {
301            if !err.is_null() {
302                *err = e.into_glib_ptr();
303            }
304            -1
305        }
306    }
307}
308
309#[cfg(test)]
310mod tests {
311    use std::cell::RefCell;
312
313    use super::*;
314    use crate::prelude::*;
315
316    mod imp {
317        use super::*;
318
319        #[derive(Default)]
320        pub struct SimpleOutputStream {
321            pub sum: RefCell<usize>,
322        }
323
324        #[glib::object_subclass]
325        impl ObjectSubclass for SimpleOutputStream {
326            const NAME: &'static str = "SimpleOutputStream";
327            type Type = super::SimpleOutputStream;
328            type ParentType = OutputStream;
329        }
330
331        impl ObjectImpl for SimpleOutputStream {}
332
333        impl OutputStreamImpl for SimpleOutputStream {
334            fn write(
335                &self,
336                buffer: &[u8],
337                _cancellable: Option<&Cancellable>,
338            ) -> Result<usize, Error> {
339                let mut sum = self.sum.borrow_mut();
340                for b in buffer {
341                    *sum += *b as usize;
342                }
343
344                Ok(buffer.len())
345            }
346        }
347    }
348
349    glib::wrapper! {
350        pub struct SimpleOutputStream(ObjectSubclass<imp::SimpleOutputStream>)
351            @extends OutputStream;
352    }
353
354    #[test]
355    fn test_simple_stream() {
356        let stream = glib::Object::new::<SimpleOutputStream>();
357
358        assert_eq!(*stream.imp().sum.borrow(), 0);
359        assert_eq!(
360            stream.write(&[1, 2, 3, 4, 5], crate::Cancellable::NONE),
361            Ok(5)
362        );
363        assert_eq!(*stream.imp().sum.borrow(), 15);
364    }
365}