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