1use std::ptr;
4
5use glib::{Error, prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{Cancellable, InputStream, OutputStream, OutputStreamSpliceFlags, ffi};
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 unsafe {
200 debug_assert!(count <= isize::MAX as usize);
201
202 let instance = &*(ptr as *mut T::Instance);
203 let imp = instance.imp();
204
205 match imp.write(
206 if count == 0 {
207 &[]
208 } else {
209 std::slice::from_raw_parts(buffer as *const u8, count)
210 },
211 Option::<Cancellable>::from_glib_borrow(cancellable)
212 .as_ref()
213 .as_ref(),
214 ) {
215 Ok(res) => {
216 assert!(res <= isize::MAX as usize);
217 assert!(res <= count);
218 res as isize
219 }
220 Err(e) => {
221 if !err.is_null() {
222 *err = e.into_glib_ptr();
223 }
224 -1
225 }
226 }
227 }
228}
229
230unsafe extern "C" fn stream_close<T: OutputStreamImpl>(
231 ptr: *mut ffi::GOutputStream,
232 cancellable: *mut ffi::GCancellable,
233 err: *mut *mut glib::ffi::GError,
234) -> glib::ffi::gboolean {
235 unsafe {
236 let instance = &*(ptr as *mut T::Instance);
237 let imp = instance.imp();
238
239 match imp.close(
240 Option::<Cancellable>::from_glib_borrow(cancellable)
241 .as_ref()
242 .as_ref(),
243 ) {
244 Ok(_) => glib::ffi::GTRUE,
245 Err(e) => {
246 if !err.is_null() {
247 *err = e.into_glib_ptr();
248 }
249 glib::ffi::GFALSE
250 }
251 }
252 }
253}
254
255unsafe extern "C" fn stream_flush<T: OutputStreamImpl>(
256 ptr: *mut ffi::GOutputStream,
257 cancellable: *mut ffi::GCancellable,
258 err: *mut *mut glib::ffi::GError,
259) -> glib::ffi::gboolean {
260 unsafe {
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}
279
280unsafe extern "C" fn stream_splice<T: OutputStreamImpl>(
281 ptr: *mut ffi::GOutputStream,
282 input_stream: *mut ffi::GInputStream,
283 flags: ffi::GOutputStreamSpliceFlags,
284 cancellable: *mut ffi::GCancellable,
285 err: *mut *mut glib::ffi::GError,
286) -> isize {
287 unsafe {
288 let instance = &*(ptr as *mut T::Instance);
289 let imp = instance.imp();
290
291 match imp.splice(
292 &from_glib_borrow(input_stream),
293 from_glib(flags),
294 Option::<Cancellable>::from_glib_borrow(cancellable)
295 .as_ref()
296 .as_ref(),
297 ) {
298 Ok(res) => {
299 assert!(res <= isize::MAX as usize);
300 res as isize
301 }
302 Err(e) => {
303 if !err.is_null() {
304 *err = e.into_glib_ptr();
305 }
306 -1
307 }
308 }
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use std::cell::RefCell;
315
316 use super::*;
317 use crate::prelude::*;
318
319 mod imp {
320 use super::*;
321
322 #[derive(Default)]
323 pub struct SimpleOutputStream {
324 pub sum: RefCell<usize>,
325 }
326
327 #[glib::object_subclass]
328 impl ObjectSubclass for SimpleOutputStream {
329 const NAME: &'static str = "SimpleOutputStream";
330 type Type = super::SimpleOutputStream;
331 type ParentType = OutputStream;
332 }
333
334 impl ObjectImpl for SimpleOutputStream {}
335
336 impl OutputStreamImpl for SimpleOutputStream {
337 fn write(
338 &self,
339 buffer: &[u8],
340 _cancellable: Option<&Cancellable>,
341 ) -> Result<usize, Error> {
342 let mut sum = self.sum.borrow_mut();
343 for b in buffer {
344 *sum += *b as usize;
345 }
346
347 Ok(buffer.len())
348 }
349 }
350 }
351
352 glib::wrapper! {
353 pub struct SimpleOutputStream(ObjectSubclass<imp::SimpleOutputStream>)
354 @extends OutputStream;
355 }
356
357 #[test]
358 fn test_simple_stream() {
359 let stream = glib::Object::new::<SimpleOutputStream>();
360
361 assert_eq!(*stream.imp().sum.borrow(), 0);
362 assert_eq!(
363 stream.write(&[1, 2, 3, 4, 5], crate::Cancellable::NONE),
364 Ok(5)
365 );
366 assert_eq!(*stream.imp().sum.borrow(), 15);
367 }
368}