1use 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}