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