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::{Error, prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{Cancellable, InputStream, OutputStream, OutputStreamSpliceFlags, ffi};
8
9pub trait OutputStreamImpl: Send + ObjectImpl + ObjectSubclass<Type: IsA<OutputStream>> {
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
62pub trait OutputStreamImplExt: OutputStreamImpl {
63    fn parent_write(
64        &self,
65        buffer: &[u8],
66        cancellable: Option<&Cancellable>,
67    ) -> Result<usize, Error> {
68        unsafe {
69            let data = Self::type_data();
70            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
71            let f = (*parent_class)
72                .write_fn
73                .expect("No parent class implementation for \"write\"");
74            let mut err = ptr::null_mut();
75            let res = f(
76                self.obj()
77                    .unsafe_cast_ref::<OutputStream>()
78                    .to_glib_none()
79                    .0,
80                mut_override(buffer.as_ptr()),
81                buffer.len(),
82                cancellable.to_glib_none().0,
83                &mut err,
84            );
85            if res == -1 {
86                Err(from_glib_full(err))
87            } else {
88                debug_assert!(res >= 0);
89                let res = res as usize;
90                debug_assert!(res <= buffer.len());
91                Ok(res)
92            }
93        }
94    }
95
96    fn parent_close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
97        unsafe {
98            let data = Self::type_data();
99            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
100            let mut err = ptr::null_mut();
101            if let Some(f) = (*parent_class).close_fn {
102                if from_glib(f(
103                    self.obj()
104                        .unsafe_cast_ref::<OutputStream>()
105                        .to_glib_none()
106                        .0,
107                    cancellable.to_glib_none().0,
108                    &mut err,
109                )) {
110                    Ok(())
111                } else {
112                    Err(from_glib_full(err))
113                }
114            } else {
115                Ok(())
116            }
117        }
118    }
119
120    fn parent_flush(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
121        unsafe {
122            let data = Self::type_data();
123            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
124            let mut err = ptr::null_mut();
125            if let Some(f) = (*parent_class).flush {
126                if from_glib(f(
127                    self.obj()
128                        .unsafe_cast_ref::<OutputStream>()
129                        .to_glib_none()
130                        .0,
131                    cancellable.to_glib_none().0,
132                    &mut err,
133                )) {
134                    Ok(())
135                } else {
136                    Err(from_glib_full(err))
137                }
138            } else {
139                Ok(())
140            }
141        }
142    }
143
144    fn parent_splice(
145        &self,
146        input_stream: &InputStream,
147        flags: OutputStreamSpliceFlags,
148        cancellable: Option<&Cancellable>,
149    ) -> Result<usize, Error> {
150        unsafe {
151            let data = Self::type_data();
152            let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
153            let mut err = ptr::null_mut();
154            let f = (*parent_class)
155                .splice
156                .expect("No parent class implementation for \"splice\"");
157            let res = f(
158                self.obj()
159                    .unsafe_cast_ref::<OutputStream>()
160                    .to_glib_none()
161                    .0,
162                input_stream.to_glib_none().0,
163                flags.into_glib(),
164                cancellable.to_glib_none().0,
165                &mut err,
166            );
167            if res == -1 {
168                Err(from_glib_full(err))
169            } else {
170                debug_assert!(res >= 0);
171                let res = res as usize;
172                Ok(res)
173            }
174        }
175    }
176}
177
178impl<T: OutputStreamImpl> OutputStreamImplExt for T {}
179
180unsafe impl<T: OutputStreamImpl> IsSubclassable<T> for OutputStream {
181    fn class_init(class: &mut ::glib::Class<Self>) {
182        Self::parent_class_init::<T>(class);
183
184        let klass = class.as_mut();
185        klass.write_fn = Some(stream_write::<T>);
186        klass.close_fn = Some(stream_close::<T>);
187        klass.flush = Some(stream_flush::<T>);
188        klass.splice = Some(stream_splice::<T>);
189    }
190}
191
192unsafe extern "C" fn stream_write<T: OutputStreamImpl>(
193    ptr: *mut ffi::GOutputStream,
194    buffer: *mut u8,
195    count: usize,
196    cancellable: *mut ffi::GCancellable,
197    err: *mut *mut glib::ffi::GError,
198) -> isize {
199    unsafe {
200        debug_assert!(count <= isize::MAX as usize);
201
202        let instance = &*(ptr as *mut T::Instance);
203        let imp = instance.imp();
204
205        match imp.write(
206            if count == 0 {
207                &[]
208            } else {
209                std::slice::from_raw_parts(buffer as *const u8, count)
210            },
211            Option::<Cancellable>::from_glib_borrow(cancellable)
212                .as_ref()
213                .as_ref(),
214        ) {
215            Ok(res) => {
216                assert!(res <= isize::MAX as usize);
217                assert!(res <= count);
218                res as isize
219            }
220            Err(e) => {
221                if !err.is_null() {
222                    *err = e.into_glib_ptr();
223                }
224                -1
225            }
226        }
227    }
228}
229
230unsafe extern "C" fn stream_close<T: OutputStreamImpl>(
231    ptr: *mut ffi::GOutputStream,
232    cancellable: *mut ffi::GCancellable,
233    err: *mut *mut glib::ffi::GError,
234) -> glib::ffi::gboolean {
235    unsafe {
236        let instance = &*(ptr as *mut T::Instance);
237        let imp = instance.imp();
238
239        match imp.close(
240            Option::<Cancellable>::from_glib_borrow(cancellable)
241                .as_ref()
242                .as_ref(),
243        ) {
244            Ok(_) => glib::ffi::GTRUE,
245            Err(e) => {
246                if !err.is_null() {
247                    *err = e.into_glib_ptr();
248                }
249                glib::ffi::GFALSE
250            }
251        }
252    }
253}
254
255unsafe extern "C" fn stream_flush<T: OutputStreamImpl>(
256    ptr: *mut ffi::GOutputStream,
257    cancellable: *mut ffi::GCancellable,
258    err: *mut *mut glib::ffi::GError,
259) -> glib::ffi::gboolean {
260    unsafe {
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}
279
280unsafe extern "C" fn stream_splice<T: OutputStreamImpl>(
281    ptr: *mut ffi::GOutputStream,
282    input_stream: *mut ffi::GInputStream,
283    flags: ffi::GOutputStreamSpliceFlags,
284    cancellable: *mut ffi::GCancellable,
285    err: *mut *mut glib::ffi::GError,
286) -> isize {
287    unsafe {
288        let instance = &*(ptr as *mut T::Instance);
289        let imp = instance.imp();
290
291        match imp.splice(
292            &from_glib_borrow(input_stream),
293            from_glib(flags),
294            Option::<Cancellable>::from_glib_borrow(cancellable)
295                .as_ref()
296                .as_ref(),
297        ) {
298            Ok(res) => {
299                assert!(res <= isize::MAX as usize);
300                res as isize
301            }
302            Err(e) => {
303                if !err.is_null() {
304                    *err = e.into_glib_ptr();
305                }
306                -1
307            }
308        }
309    }
310}
311
312#[cfg(test)]
313mod tests {
314    use std::cell::RefCell;
315
316    use super::*;
317    use crate::prelude::*;
318
319    mod imp {
320        use super::*;
321
322        #[derive(Default)]
323        pub struct SimpleOutputStream {
324            pub sum: RefCell<usize>,
325        }
326
327        #[glib::object_subclass]
328        impl ObjectSubclass for SimpleOutputStream {
329            const NAME: &'static str = "SimpleOutputStream";
330            type Type = super::SimpleOutputStream;
331            type ParentType = OutputStream;
332        }
333
334        impl ObjectImpl for SimpleOutputStream {}
335
336        impl OutputStreamImpl for SimpleOutputStream {
337            fn write(
338                &self,
339                buffer: &[u8],
340                _cancellable: Option<&Cancellable>,
341            ) -> Result<usize, Error> {
342                let mut sum = self.sum.borrow_mut();
343                for b in buffer {
344                    *sum += *b as usize;
345                }
346
347                Ok(buffer.len())
348            }
349        }
350    }
351
352    glib::wrapper! {
353        pub struct SimpleOutputStream(ObjectSubclass<imp::SimpleOutputStream>)
354            @extends OutputStream;
355    }
356
357    #[test]
358    fn test_simple_stream() {
359        let stream = glib::Object::new::<SimpleOutputStream>();
360
361        assert_eq!(*stream.imp().sum.borrow(), 0);
362        assert_eq!(
363            stream.write(&[1, 2, 3, 4, 5], crate::Cancellable::NONE),
364            Ok(5)
365        );
366        assert_eq!(*stream.imp().sum.borrow(), 15);
367    }
368}