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