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