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