1 // Copyright 2019, The Gtk-rs Project Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution.
3 // Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4 
5 use gio_sys;
6 use glib_sys;
7 
8 use glib::subclass::prelude::*;
9 use glib::translate::*;
10 
11 use glib::Error;
12 
13 use Cancellable;
14 use InputStream;
15 use OutputStream;
16 use OutputStreamClass;
17 use OutputStreamSpliceFlags;
18 
19 use std::mem;
20 use std::ptr;
21 
22 pub trait OutputStreamImpl: OutputStreamImplExt + Send + 'static {
write( &self, stream: &OutputStream, buffer: &[u8], cancellable: Option<&Cancellable>, ) -> Result<usize, Error>23     fn write(
24         &self,
25         stream: &OutputStream,
26         buffer: &[u8],
27         cancellable: Option<&Cancellable>,
28     ) -> Result<usize, Error> {
29         self.parent_write(stream, buffer, cancellable)
30     }
31 
close(&self, stream: &OutputStream, cancellable: Option<&Cancellable>) -> Result<(), Error>32     fn close(&self, stream: &OutputStream, cancellable: Option<&Cancellable>) -> Result<(), Error> {
33         self.parent_close(stream, cancellable)
34     }
35 
flush(&self, stream: &OutputStream, cancellable: Option<&Cancellable>) -> Result<(), Error>36     fn flush(&self, stream: &OutputStream, cancellable: Option<&Cancellable>) -> Result<(), Error> {
37         self.parent_flush(stream, cancellable)
38     }
39 
splice( &self, stream: &OutputStream, input_stream: &InputStream, flags: OutputStreamSpliceFlags, cancellable: Option<&Cancellable>, ) -> Result<usize, Error>40     fn splice(
41         &self,
42         stream: &OutputStream,
43         input_stream: &InputStream,
44         flags: OutputStreamSpliceFlags,
45         cancellable: Option<&Cancellable>,
46     ) -> Result<usize, Error> {
47         self.parent_splice(stream, input_stream, flags, cancellable)
48     }
49 }
50 
51 pub trait OutputStreamImplExt {
parent_write( &self, stream: &OutputStream, buffer: &[u8], cancellable: Option<&Cancellable>, ) -> Result<usize, Error>52     fn parent_write(
53         &self,
54         stream: &OutputStream,
55         buffer: &[u8],
56         cancellable: Option<&Cancellable>,
57     ) -> Result<usize, Error>;
58 
parent_close( &self, stream: &OutputStream, cancellable: Option<&Cancellable>, ) -> Result<(), Error>59     fn parent_close(
60         &self,
61         stream: &OutputStream,
62         cancellable: Option<&Cancellable>,
63     ) -> Result<(), Error>;
64 
parent_flush( &self, stream: &OutputStream, cancellable: Option<&Cancellable>, ) -> Result<(), Error>65     fn parent_flush(
66         &self,
67         stream: &OutputStream,
68         cancellable: Option<&Cancellable>,
69     ) -> Result<(), Error>;
70 
parent_splice( &self, stream: &OutputStream, input_stream: &InputStream, flags: OutputStreamSpliceFlags, cancellable: Option<&Cancellable>, ) -> Result<usize, Error>71     fn parent_splice(
72         &self,
73         stream: &OutputStream,
74         input_stream: &InputStream,
75         flags: OutputStreamSpliceFlags,
76         cancellable: Option<&Cancellable>,
77     ) -> Result<usize, Error>;
78 }
79 
80 impl<T: OutputStreamImpl + ObjectImpl> OutputStreamImplExt for T {
parent_write( &self, stream: &OutputStream, buffer: &[u8], cancellable: Option<&Cancellable>, ) -> Result<usize, Error>81     fn parent_write(
82         &self,
83         stream: &OutputStream,
84         buffer: &[u8],
85         cancellable: Option<&Cancellable>,
86     ) -> Result<usize, Error> {
87         unsafe {
88             let data = self.get_type_data();
89             let parent_class = data.as_ref().get_parent_class() as *mut gio_sys::GOutputStreamClass;
90             let f = (*parent_class)
91                 .write_fn
92                 .expect("No parent class implementation for \"write\"");
93             let mut err = ptr::null_mut();
94             let res = f(
95                 stream.to_glib_none().0,
96                 mut_override(buffer.as_ptr()),
97                 buffer.len(),
98                 cancellable.to_glib_none().0,
99                 &mut err,
100             );
101             if res == -1 {
102                 Err(from_glib_full(err))
103             } else {
104                 assert!(res >= 0);
105                 let res = res as usize;
106                 assert!(res <= buffer.len());
107                 Ok(res)
108             }
109         }
110     }
111 
parent_close( &self, stream: &OutputStream, cancellable: Option<&Cancellable>, ) -> Result<(), Error>112     fn parent_close(
113         &self,
114         stream: &OutputStream,
115         cancellable: Option<&Cancellable>,
116     ) -> Result<(), Error> {
117         unsafe {
118             let data = self.get_type_data();
119             let parent_class = data.as_ref().get_parent_class() as *mut gio_sys::GOutputStreamClass;
120             let mut err = ptr::null_mut();
121             if let Some(f) = (*parent_class).close_fn {
122                 if from_glib(f(
123                     stream.to_glib_none().0,
124                     cancellable.to_glib_none().0,
125                     &mut err,
126                 )) {
127                     Ok(())
128                 } else {
129                     Err(from_glib_full(err))
130                 }
131             } else {
132                 Ok(())
133             }
134         }
135     }
136 
parent_flush( &self, stream: &OutputStream, cancellable: Option<&Cancellable>, ) -> Result<(), Error>137     fn parent_flush(
138         &self,
139         stream: &OutputStream,
140         cancellable: Option<&Cancellable>,
141     ) -> Result<(), Error> {
142         unsafe {
143             let data = self.get_type_data();
144             let parent_class = data.as_ref().get_parent_class() as *mut gio_sys::GOutputStreamClass;
145             let mut err = ptr::null_mut();
146             if let Some(f) = (*parent_class).flush {
147                 if from_glib(f(
148                     stream.to_glib_none().0,
149                     cancellable.to_glib_none().0,
150                     &mut err,
151                 )) {
152                     Ok(())
153                 } else {
154                     Err(from_glib_full(err))
155                 }
156             } else {
157                 Ok(())
158             }
159         }
160     }
161 
parent_splice( &self, stream: &OutputStream, input_stream: &InputStream, flags: OutputStreamSpliceFlags, cancellable: Option<&Cancellable>, ) -> Result<usize, Error>162     fn parent_splice(
163         &self,
164         stream: &OutputStream,
165         input_stream: &InputStream,
166         flags: OutputStreamSpliceFlags,
167         cancellable: Option<&Cancellable>,
168     ) -> Result<usize, Error> {
169         unsafe {
170             let data = self.get_type_data();
171             let parent_class = data.as_ref().get_parent_class() as *mut gio_sys::GOutputStreamClass;
172             let mut err = ptr::null_mut();
173             let f = (*parent_class)
174                 .splice
175                 .expect("No parent class implementation for \"splice\"");
176             let res = f(
177                 stream.to_glib_none().0,
178                 input_stream.to_glib_none().0,
179                 flags.to_glib(),
180                 cancellable.to_glib_none().0,
181                 &mut err,
182             );
183             if res == -1 {
184                 Err(from_glib_full(err))
185             } else {
186                 assert!(res >= 0);
187                 let res = res as usize;
188                 Ok(res)
189             }
190         }
191     }
192 }
193 
194 unsafe impl<T: ObjectSubclass + OutputStreamImpl> IsSubclassable<T> for OutputStreamClass {
override_vfuncs(&mut self)195     fn override_vfuncs(&mut self) {
196         <glib::ObjectClass as IsSubclassable<T>>::override_vfuncs(self);
197         unsafe {
198             let klass = &mut *(self as *mut Self as *mut gio_sys::GOutputStreamClass);
199             klass.write_fn = Some(stream_write::<T>);
200             klass.close_fn = Some(stream_close::<T>);
201             klass.flush = Some(stream_flush::<T>);
202             klass.splice = Some(stream_splice::<T>);
203         }
204     }
205 }
206 
stream_write<T: ObjectSubclass>( ptr: *mut gio_sys::GOutputStream, buffer: *mut u8, count: usize, cancellable: *mut gio_sys::GCancellable, err: *mut *mut glib_sys::GError, ) -> isize where T: OutputStreamImpl,207 unsafe extern "C" fn stream_write<T: ObjectSubclass>(
208     ptr: *mut gio_sys::GOutputStream,
209     buffer: *mut u8,
210     count: usize,
211     cancellable: *mut gio_sys::GCancellable,
212     err: *mut *mut glib_sys::GError,
213 ) -> isize
214 where
215     T: OutputStreamImpl,
216 {
217     use std::isize;
218     use std::slice;
219 
220     assert!(count <= isize::MAX as usize);
221 
222     let instance = &*(ptr as *mut T::Instance);
223     let imp = instance.get_impl();
224     let wrap: OutputStream = from_glib_borrow(ptr);
225 
226     match imp.write(
227         &wrap,
228         slice::from_raw_parts(buffer as *const u8, count),
229         Option::<Cancellable>::from_glib_borrow(cancellable).as_ref(),
230     ) {
231         Ok(res) => {
232             assert!(res <= isize::MAX as usize);
233             assert!(res <= count);
234             res as isize
235         }
236         Err(mut e) => {
237             *err = e.to_glib_none_mut().0;
238             mem::forget(e);
239             -1
240         }
241     }
242 }
243 
stream_close<T: ObjectSubclass>( ptr: *mut gio_sys::GOutputStream, cancellable: *mut gio_sys::GCancellable, err: *mut *mut glib_sys::GError, ) -> glib_sys::gboolean where T: OutputStreamImpl,244 unsafe extern "C" fn stream_close<T: ObjectSubclass>(
245     ptr: *mut gio_sys::GOutputStream,
246     cancellable: *mut gio_sys::GCancellable,
247     err: *mut *mut glib_sys::GError,
248 ) -> glib_sys::gboolean
249 where
250     T: OutputStreamImpl,
251 {
252     let instance = &*(ptr as *mut T::Instance);
253     let imp = instance.get_impl();
254     let wrap: OutputStream = from_glib_borrow(ptr);
255 
256     match imp.close(
257         &wrap,
258         Option::<Cancellable>::from_glib_borrow(cancellable).as_ref(),
259     ) {
260         Ok(_) => glib_sys::GTRUE,
261         Err(mut e) => {
262             *err = e.to_glib_none_mut().0;
263             mem::forget(e);
264             glib_sys::GFALSE
265         }
266     }
267 }
268 
stream_flush<T: ObjectSubclass>( ptr: *mut gio_sys::GOutputStream, cancellable: *mut gio_sys::GCancellable, err: *mut *mut glib_sys::GError, ) -> glib_sys::gboolean where T: OutputStreamImpl,269 unsafe extern "C" fn stream_flush<T: ObjectSubclass>(
270     ptr: *mut gio_sys::GOutputStream,
271     cancellable: *mut gio_sys::GCancellable,
272     err: *mut *mut glib_sys::GError,
273 ) -> glib_sys::gboolean
274 where
275     T: OutputStreamImpl,
276 {
277     let instance = &*(ptr as *mut T::Instance);
278     let imp = instance.get_impl();
279     let wrap: OutputStream = from_glib_borrow(ptr);
280 
281     match imp.flush(
282         &wrap,
283         Option::<Cancellable>::from_glib_borrow(cancellable).as_ref(),
284     ) {
285         Ok(_) => glib_sys::GTRUE,
286         Err(mut e) => {
287             *err = e.to_glib_none_mut().0;
288             mem::forget(e);
289             glib_sys::GFALSE
290         }
291     }
292 }
293 
stream_splice<T: ObjectSubclass>( ptr: *mut gio_sys::GOutputStream, input_stream: *mut gio_sys::GInputStream, flags: gio_sys::GOutputStreamSpliceFlags, cancellable: *mut gio_sys::GCancellable, err: *mut *mut glib_sys::GError, ) -> isize where T: OutputStreamImpl,294 unsafe extern "C" fn stream_splice<T: ObjectSubclass>(
295     ptr: *mut gio_sys::GOutputStream,
296     input_stream: *mut gio_sys::GInputStream,
297     flags: gio_sys::GOutputStreamSpliceFlags,
298     cancellable: *mut gio_sys::GCancellable,
299     err: *mut *mut glib_sys::GError,
300 ) -> isize
301 where
302     T: OutputStreamImpl,
303 {
304     let instance = &*(ptr as *mut T::Instance);
305     let imp = instance.get_impl();
306     let wrap: OutputStream = from_glib_borrow(ptr);
307 
308     match imp.splice(
309         &wrap,
310         &from_glib_borrow(input_stream),
311         from_glib(flags),
312         Option::<Cancellable>::from_glib_borrow(cancellable).as_ref(),
313     ) {
314         Ok(res) => {
315             use std::isize;
316             assert!(res <= isize::MAX as usize);
317             res as isize
318         }
319         Err(mut e) => {
320             *err = e.to_glib_none_mut().0;
321             mem::forget(e);
322             -1
323         }
324     }
325 }
326 
327 #[cfg(test)]
328 mod tests {
329     use super::*;
330     use crate::prelude::*;
331     use glib;
332     use glib::subclass;
333     use std::cell::RefCell;
334 
335     struct SimpleOutputStream {
336         sum: RefCell<usize>,
337     }
338 
339     impl ObjectSubclass for SimpleOutputStream {
340         const NAME: &'static str = "SimpleOutputStream";
341         type ParentType = OutputStream;
342         type Instance = subclass::simple::InstanceStruct<Self>;
343         type Class = subclass::simple::ClassStruct<Self>;
344 
345         glib_object_subclass!();
346 
new() -> Self347         fn new() -> Self {
348             Self {
349                 sum: RefCell::new(0),
350             }
351         }
352     }
353 
354     impl ObjectImpl for SimpleOutputStream {
355         glib_object_impl!();
356     }
357 
358     impl OutputStreamImpl for SimpleOutputStream {
write( &self, _stream: &OutputStream, buffer: &[u8], _cancellable: Option<&Cancellable>, ) -> Result<usize, Error>359         fn write(
360             &self,
361             _stream: &OutputStream,
362             buffer: &[u8],
363             _cancellable: Option<&Cancellable>,
364         ) -> Result<usize, Error> {
365             let mut sum = self.sum.borrow_mut();
366             for b in buffer {
367                 *sum += *b as usize;
368             }
369 
370             Ok(buffer.len())
371         }
372     }
373 
374     #[test]
test_simple_stream()375     fn test_simple_stream() {
376         let stream = glib::Object::new(SimpleOutputStream::get_type(), &[])
377             .unwrap()
378             .downcast::<::OutputStream>()
379             .unwrap();
380 
381         assert_eq!(*SimpleOutputStream::from_instance(&stream).sum.borrow(), 0);
382         assert_eq!(
383             stream.write(&[1, 2, 3, 4, 5], crate::NONE_CANCELLABLE),
384             Ok(5)
385         );
386         assert_eq!(*SimpleOutputStream::from_instance(&stream).sum.borrow(), 15);
387     }
388 }
389