gio/
pollable_input_stream.rs
1use std::{cell::RefCell, io, mem::transmute, pin::Pin, ptr};
4
5use futures_core::{
6 stream::Stream,
7 task::{Context, Poll},
8};
9use futures_io::AsyncRead;
10use glib::{prelude::*, translate::*};
11
12use crate::{ffi, prelude::*, Cancellable, PollableInputStream};
13
14pub trait PollableInputStreamExtManual: IsA<PollableInputStream> + Sized {
15 #[doc(alias = "g_pollable_input_stream_create_source")]
33 fn create_source<F, C>(
34 &self,
35 cancellable: Option<&C>,
36 name: Option<&str>,
37 priority: glib::Priority,
38 func: F,
39 ) -> glib::Source
40 where
41 F: FnMut(&Self) -> glib::ControlFlow + 'static,
42 C: IsA<Cancellable>,
43 {
44 unsafe extern "C" fn trampoline<
45 O: IsA<PollableInputStream>,
46 F: FnMut(&O) -> glib::ControlFlow + 'static,
47 >(
48 stream: *mut ffi::GPollableInputStream,
49 func: glib::ffi::gpointer,
50 ) -> glib::ffi::gboolean {
51 let func: &RefCell<F> = &*(func as *const RefCell<F>);
52 let mut func = func.borrow_mut();
53 (*func)(PollableInputStream::from_glib_borrow(stream).unsafe_cast_ref()).into_glib()
54 }
55 unsafe extern "C" fn destroy_closure<F>(ptr: glib::ffi::gpointer) {
56 let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
57 }
58 let cancellable = cancellable.map(|c| c.as_ref());
59 let gcancellable = cancellable.to_glib_none();
60 unsafe {
61 let source = ffi::g_pollable_input_stream_create_source(
62 self.as_ref().to_glib_none().0,
63 gcancellable.0,
64 );
65
66 let trampoline = trampoline::<Self, F> as glib::ffi::gpointer;
67 glib::ffi::g_source_set_callback(
68 source,
69 Some(transmute::<
70 glib::ffi::gpointer,
71 unsafe extern "C" fn(glib::ffi::gpointer) -> glib::ffi::gboolean,
72 >(trampoline)),
73 Box::into_raw(Box::new(RefCell::new(func))) as glib::ffi::gpointer,
74 Some(destroy_closure::<F>),
75 );
76 glib::ffi::g_source_set_priority(source, priority.into_glib());
77
78 if let Some(name) = name {
79 glib::ffi::g_source_set_name(source, name.to_glib_none().0);
80 }
81
82 from_glib_full(source)
83 }
84 }
85
86 fn create_source_future<C: IsA<Cancellable>>(
87 &self,
88 cancellable: Option<&C>,
89 priority: glib::Priority,
90 ) -> Pin<Box<dyn std::future::Future<Output = ()> + 'static>> {
91 let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
92
93 let obj = self.clone();
94 Box::pin(glib::SourceFuture::new(move |send| {
95 let mut send = Some(send);
96 obj.create_source(cancellable.as_ref(), None, priority, move |_| {
97 let _ = send.take().unwrap().send(());
98 glib::ControlFlow::Break
99 })
100 }))
101 }
102
103 fn create_source_stream<C: IsA<Cancellable>>(
104 &self,
105 cancellable: Option<&C>,
106 priority: glib::Priority,
107 ) -> Pin<Box<dyn Stream<Item = ()> + 'static>> {
108 let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
109
110 let obj = self.clone();
111 Box::pin(glib::SourceStream::new(move |send| {
112 obj.create_source(cancellable.as_ref(), None, priority, move |_| {
113 if send.unbounded_send(()).is_err() {
114 glib::ControlFlow::Break
115 } else {
116 glib::ControlFlow::Continue
117 }
118 })
119 }))
120 }
121
122 #[doc(alias = "g_pollable_input_stream_read_nonblocking")]
148 fn read_nonblocking<C: IsA<Cancellable>>(
149 &self,
150 buffer: &mut [u8],
151 cancellable: Option<&C>,
152 ) -> Result<isize, glib::Error> {
153 let cancellable = cancellable.map(|c| c.as_ref());
154 let gcancellable = cancellable.to_glib_none();
155 let count = buffer.len();
156 unsafe {
157 let mut error = ptr::null_mut();
158 let ret = ffi::g_pollable_input_stream_read_nonblocking(
159 self.as_ref().to_glib_none().0,
160 buffer.to_glib_none().0,
161 count,
162 gcancellable.0,
163 &mut error,
164 );
165 if error.is_null() {
166 Ok(ret)
167 } else {
168 Err(from_glib_full(error))
169 }
170 }
171 }
172
173 fn into_async_read(self) -> Result<InputStreamAsyncRead<Self>, Self>
174 where
175 Self: IsA<PollableInputStream>,
176 {
177 if self.can_poll() {
178 Ok(InputStreamAsyncRead(self))
179 } else {
180 Err(self)
181 }
182 }
183}
184
185impl<O: IsA<PollableInputStream>> PollableInputStreamExtManual for O {}
186
187#[derive(Debug)]
188pub struct InputStreamAsyncRead<T: IsA<PollableInputStream>>(T);
189
190impl<T: IsA<PollableInputStream>> InputStreamAsyncRead<T> {
191 pub fn into_input_stream(self) -> T {
192 self.0
193 }
194
195 pub fn input_stream(&self) -> &T {
196 &self.0
197 }
198}
199
200impl<T: IsA<PollableInputStream>> AsyncRead for InputStreamAsyncRead<T> {
201 fn poll_read(
202 self: Pin<&mut Self>,
203 cx: &mut Context,
204 buf: &mut [u8],
205 ) -> Poll<io::Result<usize>> {
206 let stream = Pin::get_ref(self.as_ref());
207 let gio_result = stream
208 .0
209 .as_ref()
210 .read_nonblocking(buf, crate::Cancellable::NONE);
211
212 match gio_result {
213 Ok(size) => Poll::Ready(Ok(size as usize)),
214 Err(err) => {
215 let kind = err
216 .kind::<crate::IOErrorEnum>()
217 .unwrap_or(crate::IOErrorEnum::Failed);
218 if kind == crate::IOErrorEnum::WouldBlock {
219 let mut waker = Some(cx.waker().clone());
220 let source = stream.0.as_ref().create_source(
221 crate::Cancellable::NONE,
222 None,
223 glib::Priority::default(),
224 move |_| {
225 if let Some(waker) = waker.take() {
226 waker.wake();
227 }
228 glib::ControlFlow::Break
229 },
230 );
231 let main_context = glib::MainContext::ref_thread_default();
232 source.attach(Some(&main_context));
233
234 Poll::Pending
235 } else {
236 Poll::Ready(Err(io::Error::new(io::ErrorKind::from(kind), err)))
237 }
238 }
239 }
240 }
241}