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