1use crate::{ffi, AsyncResult, Cancellable, InputStream, OutputStream};
6use glib::{
7 prelude::*,
8 signal::{connect_raw, SignalHandlerId},
9 translate::*,
10};
11use std::{boxed::Box as Box_, pin::Pin};
12
13glib::wrapper! {
14 #[doc(alias = "GIOStream")]
15 pub struct IOStream(Object<ffi::GIOStream, ffi::GIOStreamClass>);
16
17 match fn {
18 type_ => || ffi::g_io_stream_get_type(),
19 }
20}
21
22impl IOStream {
23 pub const NONE: Option<&'static IOStream> = None;
24}
25
26pub trait IOStreamExt: IsA<IOStream> + 'static {
27 #[doc(alias = "g_io_stream_clear_pending")]
28 fn clear_pending(&self) {
29 unsafe {
30 ffi::g_io_stream_clear_pending(self.as_ref().to_glib_none().0);
31 }
32 }
33
34 #[doc(alias = "g_io_stream_close")]
35 fn close(&self, cancellable: Option<&impl IsA<Cancellable>>) -> Result<(), glib::Error> {
36 unsafe {
37 let mut error = std::ptr::null_mut();
38 let is_ok = ffi::g_io_stream_close(
39 self.as_ref().to_glib_none().0,
40 cancellable.map(|p| p.as_ref()).to_glib_none().0,
41 &mut error,
42 );
43 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
44 if error.is_null() {
45 Ok(())
46 } else {
47 Err(from_glib_full(error))
48 }
49 }
50 }
51
52 #[doc(alias = "g_io_stream_close_async")]
53 fn close_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
54 &self,
55 io_priority: glib::Priority,
56 cancellable: Option<&impl IsA<Cancellable>>,
57 callback: P,
58 ) {
59 let main_context = glib::MainContext::ref_thread_default();
60 let is_main_context_owner = main_context.is_owner();
61 let has_acquired_main_context = (!is_main_context_owner)
62 .then(|| main_context.acquire().ok())
63 .flatten();
64 assert!(
65 is_main_context_owner || has_acquired_main_context.is_some(),
66 "Async operations only allowed if the thread is owning the MainContext"
67 );
68
69 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
70 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
71 unsafe extern "C" fn close_async_trampoline<
72 P: FnOnce(Result<(), glib::Error>) + 'static,
73 >(
74 _source_object: *mut glib::gobject_ffi::GObject,
75 res: *mut crate::ffi::GAsyncResult,
76 user_data: glib::ffi::gpointer,
77 ) {
78 let mut error = std::ptr::null_mut();
79 ffi::g_io_stream_close_finish(_source_object as *mut _, res, &mut error);
80 let result = if error.is_null() {
81 Ok(())
82 } else {
83 Err(from_glib_full(error))
84 };
85 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
86 Box_::from_raw(user_data as *mut _);
87 let callback: P = callback.into_inner();
88 callback(result);
89 }
90 let callback = close_async_trampoline::<P>;
91 unsafe {
92 ffi::g_io_stream_close_async(
93 self.as_ref().to_glib_none().0,
94 io_priority.into_glib(),
95 cancellable.map(|p| p.as_ref()).to_glib_none().0,
96 Some(callback),
97 Box_::into_raw(user_data) as *mut _,
98 );
99 }
100 }
101
102 fn close_future(
103 &self,
104 io_priority: glib::Priority,
105 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
106 Box_::pin(crate::GioFuture::new(
107 self,
108 move |obj, cancellable, send| {
109 obj.close_async(io_priority, Some(cancellable), move |res| {
110 send.resolve(res);
111 });
112 },
113 ))
114 }
115
116 #[doc(alias = "g_io_stream_get_input_stream")]
117 #[doc(alias = "get_input_stream")]
118 #[doc(alias = "input-stream")]
119 fn input_stream(&self) -> InputStream {
120 unsafe {
121 from_glib_none(ffi::g_io_stream_get_input_stream(
122 self.as_ref().to_glib_none().0,
123 ))
124 }
125 }
126
127 #[doc(alias = "g_io_stream_get_output_stream")]
128 #[doc(alias = "get_output_stream")]
129 #[doc(alias = "output-stream")]
130 fn output_stream(&self) -> OutputStream {
131 unsafe {
132 from_glib_none(ffi::g_io_stream_get_output_stream(
133 self.as_ref().to_glib_none().0,
134 ))
135 }
136 }
137
138 #[doc(alias = "g_io_stream_has_pending")]
139 fn has_pending(&self) -> bool {
140 unsafe { from_glib(ffi::g_io_stream_has_pending(self.as_ref().to_glib_none().0)) }
141 }
142
143 #[doc(alias = "g_io_stream_is_closed")]
144 #[doc(alias = "closed")]
145 fn is_closed(&self) -> bool {
146 unsafe { from_glib(ffi::g_io_stream_is_closed(self.as_ref().to_glib_none().0)) }
147 }
148
149 #[doc(alias = "g_io_stream_set_pending")]
150 fn set_pending(&self) -> Result<(), glib::Error> {
151 unsafe {
152 let mut error = std::ptr::null_mut();
153 let is_ok = ffi::g_io_stream_set_pending(self.as_ref().to_glib_none().0, &mut error);
154 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
155 if error.is_null() {
156 Ok(())
157 } else {
158 Err(from_glib_full(error))
159 }
160 }
161 }
162
163 #[doc(alias = "closed")]
164 fn connect_closed_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
165 unsafe extern "C" fn notify_closed_trampoline<P: IsA<IOStream>, F: Fn(&P) + 'static>(
166 this: *mut ffi::GIOStream,
167 _param_spec: glib::ffi::gpointer,
168 f: glib::ffi::gpointer,
169 ) {
170 let f: &F = &*(f as *const F);
171 f(IOStream::from_glib_borrow(this).unsafe_cast_ref())
172 }
173 unsafe {
174 let f: Box_<F> = Box_::new(f);
175 connect_raw(
176 self.as_ptr() as *mut _,
177 c"notify::closed".as_ptr() as *const _,
178 Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
179 notify_closed_trampoline::<Self, F> as *const (),
180 )),
181 Box_::into_raw(f),
182 )
183 }
184 }
185}
186
187impl<O: IsA<IOStream>> IOStreamExt for O {}