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: 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    debug_assert!(count <= isize::MAX as usize);
200
201    let instance = &*(ptr as *mut T::Instance);
202    let imp = instance.imp();
203
204    match imp.write(
205        if count == 0 {
206            &[]
207        } else {
208            std::slice::from_raw_parts(buffer as *const u8, count)
209        },
210        Option::<Cancellable>::from_glib_borrow(cancellable)
211            .as_ref()
212            .as_ref(),
213    ) {
214        Ok(res) => {
215            assert!(res <= isize::MAX as usize);
216            assert!(res <= count);
217            res as isize
218        }
219        Err(e) => {
220            if !err.is_null() {
221                *err = e.into_glib_ptr();
222            }
223            -1
224        }
225    }
226}
227
228unsafe extern "C" fn stream_close<T: OutputStreamImpl>(
229    ptr: *mut ffi::GOutputStream,
230    cancellable: *mut ffi::GCancellable,
231    err: *mut *mut glib::ffi::GError,
232) -> glib::ffi::gboolean {
233    let instance = &*(ptr as *mut T::Instance);
234    let imp = instance.imp();
235
236    match imp.close(
237        Option::<Cancellable>::from_glib_borrow(cancellable)
238            .as_ref()
239            .as_ref(),
240    ) {
241        Ok(_) => glib::ffi::GTRUE,
242        Err(e) => {
243            if !err.is_null() {
244                *err = e.into_glib_ptr();
245            }
246            glib::ffi::GFALSE
247        }
248    }
249}
250
251unsafe extern "C" fn stream_flush<T: OutputStreamImpl>(
252    ptr: *mut ffi::GOutputStream,
253    cancellable: *mut ffi::GCancellable,
254    err: *mut *mut glib::ffi::GError,
255) -> glib::ffi::gboolean {
256    let instance = &*(ptr as *mut T::Instance);
257    let imp = instance.imp();
258
259    match imp.flush(
260        Option::<Cancellable>::from_glib_borrow(cancellable)
261            .as_ref()
262            .as_ref(),
263    ) {
264        Ok(_) => glib::ffi::GTRUE,
265        Err(e) => {
266            if !err.is_null() {
267                *err = e.into_glib_ptr();
268            }
269            glib::ffi::GFALSE
270        }
271    }
272}
273
274unsafe extern "C" fn stream_splice<T: OutputStreamImpl>(
275    ptr: *mut ffi::GOutputStream,
276    input_stream: *mut ffi::GInputStream,
277    flags: ffi::GOutputStreamSpliceFlags,
278    cancellable: *mut ffi::GCancellable,
279    err: *mut *mut glib::ffi::GError,
280) -> isize {
281    let instance = &*(ptr as *mut T::Instance);
282    let imp = instance.imp();
283
284    match imp.splice(
285        &from_glib_borrow(input_stream),
286        from_glib(flags),
287        Option::<Cancellable>::from_glib_borrow(cancellable)
288            .as_ref()
289            .as_ref(),
290    ) {
291        Ok(res) => {
292            assert!(res <= isize::MAX as usize);
293            res as isize
294        }
295        Err(e) => {
296            if !err.is_null() {
297                *err = e.into_glib_ptr();
298            }
299            -1
300        }
301    }
302}
303
304#[cfg(test)]
305mod tests {
306    use std::cell::RefCell;
307
308    use super::*;
309    use crate::prelude::*;
310
311    mod imp {
312        use super::*;
313
314        #[derive(Default)]
315        pub struct SimpleOutputStream {
316            pub sum: RefCell<usize>,
317        }
318
319        #[glib::object_subclass]
320        impl ObjectSubclass for SimpleOutputStream {
321            const NAME: &'static str = "SimpleOutputStream";
322            type Type = super::SimpleOutputStream;
323            type ParentType = OutputStream;
324        }
325
326        impl ObjectImpl for SimpleOutputStream {}
327
328        impl OutputStreamImpl for SimpleOutputStream {
329            fn write(
330                &self,
331                buffer: &[u8],
332                _cancellable: Option<&Cancellable>,
333            ) -> Result<usize, Error> {
334                let mut sum = self.sum.borrow_mut();
335                for b in buffer {
336                    *sum += *b as usize;
337                }
338
339                Ok(buffer.len())
340            }
341        }
342    }
343
344    glib::wrapper! {
345        pub struct SimpleOutputStream(ObjectSubclass<imp::SimpleOutputStream>)
346            @extends OutputStream;
347    }
348
349    #[test]
350    fn test_simple_stream() {
351        let stream = glib::Object::new::<SimpleOutputStream>();
352
353        assert_eq!(*stream.imp().sum.borrow(), 0);
354        assert_eq!(
355            stream.write(&[1, 2, 3, 4, 5], crate::Cancellable::NONE),
356            Ok(5)
357        );
358        assert_eq!(*stream.imp().sum.borrow(), 15);
359    }
360}