gio/
pollable_input_stream.rs1use 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::{Cancellable, PollableInputStream, ffi, prelude::*};
13
14pub trait PollableInputStreamExtManual: IsA<PollableInputStream> + Sized {
15 #[doc(alias = "g_pollable_input_stream_create_source")]
16 fn create_source<F, C>(
17 &self,
18 cancellable: Option<&C>,
19 name: Option<&str>,
20 priority: glib::Priority,
21 func: F,
22 ) -> glib::Source
23 where
24 F: FnMut(&Self) -> glib::ControlFlow + 'static,
25 C: IsA<Cancellable>,
26 {
27 unsafe extern "C" fn trampoline<
28 O: IsA<PollableInputStream>,
29 F: FnMut(&O) -> glib::ControlFlow + 'static,
30 >(
31 stream: *mut ffi::GPollableInputStream,
32 func: glib::ffi::gpointer,
33 ) -> glib::ffi::gboolean {
34 unsafe {
35 let func: &RefCell<F> = &*(func as *const RefCell<F>);
36 let mut func = func.borrow_mut();
37 (*func)(PollableInputStream::from_glib_borrow(stream).unsafe_cast_ref()).into_glib()
38 }
39 }
40 unsafe extern "C" fn destroy_closure<F>(ptr: glib::ffi::gpointer) {
41 unsafe {
42 let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
43 }
44 }
45 let cancellable = cancellable.map(|c| c.as_ref());
46 let gcancellable = cancellable.to_glib_none();
47 unsafe {
48 let source = ffi::g_pollable_input_stream_create_source(
49 self.as_ref().to_glib_none().0,
50 gcancellable.0,
51 );
52
53 let trampoline = trampoline::<Self, F> as glib::ffi::gpointer;
54 glib::ffi::g_source_set_callback(
55 source,
56 Some(transmute::<
57 glib::ffi::gpointer,
58 unsafe extern "C" fn(glib::ffi::gpointer) -> glib::ffi::gboolean,
59 >(trampoline)),
60 Box::into_raw(Box::new(RefCell::new(func))) as glib::ffi::gpointer,
61 Some(destroy_closure::<F>),
62 );
63 glib::ffi::g_source_set_priority(source, priority.into_glib());
64
65 if let Some(name) = name {
66 glib::ffi::g_source_set_name(source, name.to_glib_none().0);
67 }
68
69 from_glib_full(source)
70 }
71 }
72
73 fn create_source_future<C: IsA<Cancellable>>(
74 &self,
75 cancellable: Option<&C>,
76 priority: glib::Priority,
77 ) -> Pin<Box<dyn std::future::Future<Output = ()> + 'static>> {
78 let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
79
80 let obj = self.clone();
81 Box::pin(glib::SourceFuture::new(move |send| {
82 let mut send = Some(send);
83 obj.create_source(cancellable.as_ref(), None, priority, move |_| {
84 let _ = send.take().unwrap().send(());
85 glib::ControlFlow::Break
86 })
87 }))
88 }
89
90 fn create_source_stream<C: IsA<Cancellable>>(
91 &self,
92 cancellable: Option<&C>,
93 priority: glib::Priority,
94 ) -> Pin<Box<dyn Stream<Item = ()> + 'static>> {
95 let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
96
97 let obj = self.clone();
98 Box::pin(glib::SourceStream::new(move |send| {
99 obj.create_source(cancellable.as_ref(), None, priority, move |_| {
100 if send.unbounded_send(()).is_err() {
101 glib::ControlFlow::Break
102 } else {
103 glib::ControlFlow::Continue
104 }
105 })
106 }))
107 }
108
109 #[doc(alias = "g_pollable_input_stream_read_nonblocking")]
110 fn read_nonblocking<C: IsA<Cancellable>>(
111 &self,
112 buffer: &mut [u8],
113 cancellable: Option<&C>,
114 ) -> Result<isize, glib::Error> {
115 let cancellable = cancellable.map(|c| c.as_ref());
116 let gcancellable = cancellable.to_glib_none();
117 let count = buffer.len();
118 unsafe {
119 let mut error = ptr::null_mut();
120 let ret = ffi::g_pollable_input_stream_read_nonblocking(
121 self.as_ref().to_glib_none().0,
122 buffer.to_glib_none().0,
123 count,
124 gcancellable.0,
125 &mut error,
126 );
127 if error.is_null() {
128 Ok(ret)
129 } else {
130 Err(from_glib_full(error))
131 }
132 }
133 }
134
135 fn into_async_read(self) -> Result<InputStreamAsyncRead<Self>, Self>
136 where
137 Self: IsA<PollableInputStream>,
138 {
139 if self.can_poll() {
140 Ok(InputStreamAsyncRead(self))
141 } else {
142 Err(self)
143 }
144 }
145}
146
147impl<O: IsA<PollableInputStream>> PollableInputStreamExtManual for O {}
148
149#[derive(Debug)]
150pub struct InputStreamAsyncRead<T: IsA<PollableInputStream>>(T);
151
152impl<T: IsA<PollableInputStream>> InputStreamAsyncRead<T> {
153 pub fn into_input_stream(self) -> T {
154 self.0
155 }
156
157 pub fn input_stream(&self) -> &T {
158 &self.0
159 }
160}
161
162impl<T: IsA<PollableInputStream>> AsyncRead for InputStreamAsyncRead<T> {
163 fn poll_read(
164 self: Pin<&mut Self>,
165 cx: &mut Context,
166 buf: &mut [u8],
167 ) -> Poll<io::Result<usize>> {
168 let stream = Pin::get_ref(self.as_ref());
169 let gio_result = stream
170 .0
171 .as_ref()
172 .read_nonblocking(buf, crate::Cancellable::NONE);
173
174 match gio_result {
175 Ok(size) => Poll::Ready(Ok(size as usize)),
176 Err(err) => {
177 let kind = err
178 .kind::<crate::IOErrorEnum>()
179 .unwrap_or(crate::IOErrorEnum::Failed);
180 if kind == crate::IOErrorEnum::WouldBlock {
181 let mut waker = Some(cx.waker().clone());
182 let source = stream.0.as_ref().create_source(
183 crate::Cancellable::NONE,
184 None,
185 glib::Priority::default(),
186 move |_| {
187 if let Some(waker) = waker.take() {
188 waker.wake();
189 }
190 glib::ControlFlow::Break
191 },
192 );
193 let main_context = glib::MainContext::ref_thread_default();
194 source.attach(Some(&main_context));
195
196 Poll::Pending
197 } else {
198 Poll::Ready(Err(io::Error::new(io::ErrorKind::from(kind), err)))
199 }
200 }
201 }
202 }
203}