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