gio/subclass/
io_stream.rs1use std::{ptr, sync::OnceLock};
4
5use glib::{Error, prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{Cancellable, IOStream, InputStream, OutputStream, ffi};
8
9pub trait IOStreamImpl: Send + ObjectImpl + ObjectSubclass<Type: IsA<IOStream>> {
10 fn input_stream(&self) -> InputStream {
18 self.parent_input_stream()
19 }
20
21 fn output_stream(&self) -> OutputStream {
29 self.parent_output_stream()
30 }
31
32 fn close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
33 self.parent_close(cancellable)
34 }
35}
36
37pub trait IOStreamImplExt: IOStreamImpl {
38 fn parent_input_stream(&self) -> InputStream {
39 unsafe {
40 let data = Self::type_data();
41 let parent_class = data.as_ref().parent_class() as *mut ffi::GIOStreamClass;
42 let f = (*parent_class)
43 .get_input_stream
44 .expect("No parent class implementation for \"input_stream\"");
45 from_glib_none(f(self.obj().unsafe_cast_ref::<IOStream>().to_glib_none().0))
46 }
47 }
48
49 fn parent_output_stream(&self) -> OutputStream {
50 unsafe {
51 let data = Self::type_data();
52 let parent_class = data.as_ref().parent_class() as *mut ffi::GIOStreamClass;
53 let f = (*parent_class)
54 .get_output_stream
55 .expect("No parent class implementation for \"output_stream\"");
56 from_glib_none(f(self.obj().unsafe_cast_ref::<IOStream>().to_glib_none().0))
57 }
58 }
59
60 fn parent_close(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
61 unsafe {
62 let data = Self::type_data();
63 let parent_class = data.as_ref().parent_class() as *mut ffi::GIOStreamClass;
64 let mut err = ptr::null_mut();
65 if let Some(f) = (*parent_class).close_fn {
66 if from_glib(f(
67 self.obj().unsafe_cast_ref::<IOStream>().to_glib_none().0,
68 cancellable.to_glib_none().0,
69 &mut err,
70 )) {
71 Ok(())
72 } else {
73 Err(from_glib_full(err))
74 }
75 } else {
76 Ok(())
77 }
78 }
79 }
80}
81
82impl<T: IOStreamImpl> IOStreamImplExt for T {}
83
84unsafe impl<T: IOStreamImpl> IsSubclassable<T> for IOStream {
85 fn class_init(class: &mut ::glib::Class<Self>) {
86 Self::parent_class_init::<T>(class);
87
88 let klass = class.as_mut();
89 klass.get_input_stream = Some(stream_get_input_stream::<T>);
90 klass.get_output_stream = Some(stream_get_output_stream::<T>);
91 klass.close_fn = Some(stream_close::<T>);
92 }
93}
94
95unsafe extern "C" fn stream_get_input_stream<T: IOStreamImpl>(
96 ptr: *mut ffi::GIOStream,
97) -> *mut ffi::GInputStream {
98 unsafe {
99 let instance = &*(ptr as *mut T::Instance);
100 let imp = instance.imp();
101
102 let ret = imp.input_stream();
103
104 let instance = imp.obj();
105 let input_stream_quark = {
109 static QUARK: OnceLock<glib::Quark> = OnceLock::new();
110 *QUARK.get_or_init(|| glib::Quark::from_str("gtk-rs-subclass-input-stream"))
111 };
112 if let Some(old_stream) = instance.qdata::<InputStream>(input_stream_quark) {
113 assert_eq!(
114 old_stream.as_ref(),
115 &ret,
116 "Did not return same input stream again"
117 );
118 }
119 instance.set_qdata(input_stream_quark, ret.clone());
120 ret.to_glib_none().0
121 }
122}
123
124unsafe extern "C" fn stream_get_output_stream<T: IOStreamImpl>(
125 ptr: *mut ffi::GIOStream,
126) -> *mut ffi::GOutputStream {
127 unsafe {
128 let instance = &*(ptr as *mut T::Instance);
129 let imp = instance.imp();
130
131 let ret = imp.output_stream();
132
133 let instance = imp.obj();
134 let output_stream_quark = {
138 static QUARK: OnceLock<glib::Quark> = OnceLock::new();
139 *QUARK.get_or_init(|| glib::Quark::from_str("gtk-rs-subclass-output-stream"))
140 };
141 if let Some(old_stream) = instance.qdata::<OutputStream>(output_stream_quark) {
142 assert_eq!(
143 old_stream.as_ref(),
144 &ret,
145 "Did not return same output stream again"
146 );
147 }
148 instance.set_qdata(output_stream_quark, ret.clone());
149 ret.to_glib_none().0
150 }
151}
152
153unsafe extern "C" fn stream_close<T: IOStreamImpl>(
154 ptr: *mut ffi::GIOStream,
155 cancellable: *mut ffi::GCancellable,
156 err: *mut *mut glib::ffi::GError,
157) -> glib::ffi::gboolean {
158 unsafe {
159 let instance = &*(ptr as *mut T::Instance);
160 let imp = instance.imp();
161
162 match imp.close(
163 Option::<Cancellable>::from_glib_borrow(cancellable)
164 .as_ref()
165 .as_ref(),
166 ) {
167 Ok(_) => glib::ffi::GTRUE,
168 Err(e) => {
169 if !err.is_null() {
170 *err = e.into_glib_ptr();
171 }
172 glib::ffi::GFALSE
173 }
174 }
175 }
176}