1use std::ptr;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*, Error};
6
7use crate::{ffi, Cancellable, InputStream, OutputStream, OutputStreamSpliceFlags};
8
9pub trait OutputStreamImpl: ObjectImpl + OutputStreamImplExt + Send {
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> {
34 self.parent_flush(cancellable)
35 }
36
37 fn splice(
53 &self,
54 input_stream: &InputStream,
55 flags: OutputStreamSpliceFlags,
56 cancellable: Option<&Cancellable>,
57 ) -> Result<usize, Error> {
58 self.parent_splice(input_stream, flags, cancellable)
59 }
60}
61
62mod sealed {
63 pub trait Sealed {}
64 impl<T: super::OutputStreamImplExt> Sealed for T {}
65}
66
67pub trait OutputStreamImplExt: sealed::Sealed + ObjectSubclass {
68 fn parent_write(
69 &self,
70 buffer: &[u8],
71 cancellable: Option<&Cancellable>,
72 ) -> Result<usize, Error> {
73 unsafe {
74 let data = Self::type_data();
75 let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
76 let f = (*parent_class)
77 .write_fn
78 .expect("No parent class implementation for \"write\"");
79 let mut err = ptr::null_mut();
80 let res = f(
81 self.obj()
82 .unsafe_cast_ref::<OutputStream>()
83 .to_glib_none()
84 .0,
85 mut_override(buffer.as_ptr()),
86 buffer.len(),
87 cancellable.to_glib_none().0,
88 &mut err,
89 );
90 if res == -1 {
91 Err(from_glib_full(err))
92 } else {
93 debug_assert!(res >= 0);
94 let res = res as usize;
95 debug_assert!(res <= buffer.len());
96 Ok(res)
97 }
98 }
99 }
100
101 fn parent_close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
102 unsafe {
103 let data = Self::type_data();
104 let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
105 let mut err = ptr::null_mut();
106 if let Some(f) = (*parent_class).close_fn {
107 if from_glib(f(
108 self.obj()
109 .unsafe_cast_ref::<OutputStream>()
110 .to_glib_none()
111 .0,
112 cancellable.to_glib_none().0,
113 &mut err,
114 )) {
115 Ok(())
116 } else {
117 Err(from_glib_full(err))
118 }
119 } else {
120 Ok(())
121 }
122 }
123 }
124
125 fn parent_flush(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
126 unsafe {
127 let data = Self::type_data();
128 let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
129 let mut err = ptr::null_mut();
130 if let Some(f) = (*parent_class).flush {
131 if from_glib(f(
132 self.obj()
133 .unsafe_cast_ref::<OutputStream>()
134 .to_glib_none()
135 .0,
136 cancellable.to_glib_none().0,
137 &mut err,
138 )) {
139 Ok(())
140 } else {
141 Err(from_glib_full(err))
142 }
143 } else {
144 Ok(())
145 }
146 }
147 }
148
149 fn parent_splice(
150 &self,
151 input_stream: &InputStream,
152 flags: OutputStreamSpliceFlags,
153 cancellable: Option<&Cancellable>,
154 ) -> Result<usize, Error> {
155 unsafe {
156 let data = Self::type_data();
157 let parent_class = data.as_ref().parent_class() as *mut ffi::GOutputStreamClass;
158 let mut err = ptr::null_mut();
159 let f = (*parent_class)
160 .splice
161 .expect("No parent class implementation for \"splice\"");
162 let res = f(
163 self.obj()
164 .unsafe_cast_ref::<OutputStream>()
165 .to_glib_none()
166 .0,
167 input_stream.to_glib_none().0,
168 flags.into_glib(),
169 cancellable.to_glib_none().0,
170 &mut err,
171 );
172 if res == -1 {
173 Err(from_glib_full(err))
174 } else {
175 debug_assert!(res >= 0);
176 let res = res as usize;
177 Ok(res)
178 }
179 }
180 }
181}
182
183impl<T: OutputStreamImpl> OutputStreamImplExt for T {}
184
185unsafe impl<T: OutputStreamImpl> IsSubclassable<T> for OutputStream {
186 fn class_init(class: &mut ::glib::Class<Self>) {
187 Self::parent_class_init::<T>(class);
188
189 let klass = class.as_mut();
190 klass.write_fn = Some(stream_write::<T>);
191 klass.close_fn = Some(stream_close::<T>);
192 klass.flush = Some(stream_flush::<T>);
193 klass.splice = Some(stream_splice::<T>);
194 }
195}
196
197unsafe extern "C" fn stream_write<T: OutputStreamImpl>(
198 ptr: *mut ffi::GOutputStream,
199 buffer: *mut u8,
200 count: usize,
201 cancellable: *mut ffi::GCancellable,
202 err: *mut *mut glib::ffi::GError,
203) -> isize {
204 debug_assert!(count <= isize::MAX as usize);
205
206 let instance = &*(ptr as *mut T::Instance);
207 let imp = instance.imp();
208
209 match imp.write(
210 if count == 0 {
211 &[]
212 } else {
213 std::slice::from_raw_parts(buffer as *const u8, count)
214 },
215 Option::<Cancellable>::from_glib_borrow(cancellable)
216 .as_ref()
217 .as_ref(),
218 ) {
219 Ok(res) => {
220 assert!(res <= isize::MAX as usize);
221 assert!(res <= count);
222 res as isize
223 }
224 Err(e) => {
225 if !err.is_null() {
226 *err = e.into_glib_ptr();
227 }
228 -1
229 }
230 }
231}
232
233unsafe extern "C" fn stream_close<T: OutputStreamImpl>(
234 ptr: *mut ffi::GOutputStream,
235 cancellable: *mut ffi::GCancellable,
236 err: *mut *mut glib::ffi::GError,
237) -> glib::ffi::gboolean {
238 let instance = &*(ptr as *mut T::Instance);
239 let imp = instance.imp();
240
241 match imp.close(
242 Option::<Cancellable>::from_glib_borrow(cancellable)
243 .as_ref()
244 .as_ref(),
245 ) {
246 Ok(_) => glib::ffi::GTRUE,
247 Err(e) => {
248 if !err.is_null() {
249 *err = e.into_glib_ptr();
250 }
251 glib::ffi::GFALSE
252 }
253 }
254}
255
256unsafe extern "C" fn stream_flush<T: OutputStreamImpl>(
257 ptr: *mut ffi::GOutputStream,
258 cancellable: *mut ffi::GCancellable,
259 err: *mut *mut glib::ffi::GError,
260) -> glib::ffi::gboolean {
261 let instance = &*(ptr as *mut T::Instance);
262 let imp = instance.imp();
263
264 match imp.flush(
265 Option::<Cancellable>::from_glib_borrow(cancellable)
266 .as_ref()
267 .as_ref(),
268 ) {
269 Ok(_) => glib::ffi::GTRUE,
270 Err(e) => {
271 if !err.is_null() {
272 *err = e.into_glib_ptr();
273 }
274 glib::ffi::GFALSE
275 }
276 }
277}
278
279unsafe extern "C" fn stream_splice<T: OutputStreamImpl>(
280 ptr: *mut ffi::GOutputStream,
281 input_stream: *mut ffi::GInputStream,
282 flags: ffi::GOutputStreamSpliceFlags,
283 cancellable: *mut ffi::GCancellable,
284 err: *mut *mut glib::ffi::GError,
285) -> isize {
286 let instance = &*(ptr as *mut T::Instance);
287 let imp = instance.imp();
288
289 match imp.splice(
290 &from_glib_borrow(input_stream),
291 from_glib(flags),
292 Option::<Cancellable>::from_glib_borrow(cancellable)
293 .as_ref()
294 .as_ref(),
295 ) {
296 Ok(res) => {
297 assert!(res <= isize::MAX as usize);
298 res as isize
299 }
300 Err(e) => {
301 if !err.is_null() {
302 *err = e.into_glib_ptr();
303 }
304 -1
305 }
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use std::cell::RefCell;
312
313 use super::*;
314 use crate::prelude::*;
315
316 mod imp {
317 use super::*;
318
319 #[derive(Default)]
320 pub struct SimpleOutputStream {
321 pub sum: RefCell<usize>,
322 }
323
324 #[glib::object_subclass]
325 impl ObjectSubclass for SimpleOutputStream {
326 const NAME: &'static str = "SimpleOutputStream";
327 type Type = super::SimpleOutputStream;
328 type ParentType = OutputStream;
329 }
330
331 impl ObjectImpl for SimpleOutputStream {}
332
333 impl OutputStreamImpl for SimpleOutputStream {
334 fn write(
335 &self,
336 buffer: &[u8],
337 _cancellable: Option<&Cancellable>,
338 ) -> Result<usize, Error> {
339 let mut sum = self.sum.borrow_mut();
340 for b in buffer {
341 *sum += *b as usize;
342 }
343
344 Ok(buffer.len())
345 }
346 }
347 }
348
349 glib::wrapper! {
350 pub struct SimpleOutputStream(ObjectSubclass<imp::SimpleOutputStream>)
351 @extends OutputStream;
352 }
353
354 #[test]
355 fn test_simple_stream() {
356 let stream = glib::Object::new::<SimpleOutputStream>();
357
358 assert_eq!(*stream.imp().sum.borrow(), 0);
359 assert_eq!(
360 stream.write(&[1, 2, 3, 4, 5], crate::Cancellable::NONE),
361 Ok(5)
362 );
363 assert_eq!(*stream.imp().sum.borrow(), 15);
364 }
365}