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