1use std::{cell::RefCell, mem::transmute, pin::Pin, ptr, time::Duration};
4
5use futures_core::stream::Stream;
6use glib::{prelude::*, translate::*};
7
8use crate::{ffi, Cancellable, DatagramBased, InputMessage, OutputMessage};
9
10mod sealed {
11 pub trait Sealed {}
12 impl<T: super::IsA<super::DatagramBased>> Sealed for T {}
13}
14
15pub trait DatagramBasedExtManual: sealed::Sealed + IsA<DatagramBased> + Sized {
16 #[doc(alias = "g_datagram_based_create_source")]
17 fn create_source<F, C>(
18 &self,
19 condition: glib::IOCondition,
20 cancellable: Option<&C>,
21 name: Option<&str>,
22 priority: glib::Priority,
23 func: F,
24 ) -> glib::Source
25 where
26 F: FnMut(&Self, glib::IOCondition) -> glib::ControlFlow + 'static,
27 C: IsA<Cancellable>,
28 {
29 unsafe extern "C" fn trampoline<
30 O: IsA<DatagramBased>,
31 F: FnMut(&O, glib::IOCondition) -> glib::ControlFlow + 'static,
32 >(
33 datagram_based: *mut ffi::GDatagramBased,
34 condition: glib::ffi::GIOCondition,
35 func: glib::ffi::gpointer,
36 ) -> glib::ffi::gboolean {
37 let func: &RefCell<F> = &*(func as *const RefCell<F>);
38 let mut func = func.borrow_mut();
39 (*func)(
40 DatagramBased::from_glib_borrow(datagram_based).unsafe_cast_ref(),
41 from_glib(condition),
42 )
43 .into_glib()
44 }
45 unsafe extern "C" fn destroy_closure<F>(ptr: glib::ffi::gpointer) {
46 let _ = Box::<RefCell<F>>::from_raw(ptr as *mut _);
47 }
48 let cancellable = cancellable.map(|c| c.as_ref());
49 let gcancellable = cancellable.to_glib_none();
50 unsafe {
51 let source = ffi::g_datagram_based_create_source(
52 self.as_ref().to_glib_none().0,
53 condition.into_glib(),
54 gcancellable.0,
55 );
56 let trampoline = trampoline::<Self, F> as glib::ffi::gpointer;
57 glib::ffi::g_source_set_callback(
58 source,
59 Some(transmute::<
60 glib::ffi::gpointer,
61 unsafe extern "C" fn(glib::ffi::gpointer) -> glib::ffi::gboolean,
62 >(trampoline)),
63 Box::into_raw(Box::new(RefCell::new(func))) as glib::ffi::gpointer,
64 Some(destroy_closure::<F>),
65 );
66 glib::ffi::g_source_set_priority(source, priority.into_glib());
67
68 if let Some(name) = name {
69 glib::ffi::g_source_set_name(source, name.to_glib_none().0);
70 }
71
72 from_glib_full(source)
73 }
74 }
75
76 fn create_source_future<C: IsA<Cancellable>>(
77 &self,
78 condition: glib::IOCondition,
79 cancellable: Option<&C>,
80 priority: glib::Priority,
81 ) -> Pin<Box<dyn std::future::Future<Output = glib::IOCondition> + 'static>> {
82 let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
83
84 let obj = self.clone();
85 Box::pin(glib::SourceFuture::new(move |send| {
86 let mut send = Some(send);
87 obj.create_source(
88 condition,
89 cancellable.as_ref(),
90 None,
91 priority,
92 move |_, condition| {
93 let _ = send.take().unwrap().send(condition);
94 glib::ControlFlow::Break
95 },
96 )
97 }))
98 }
99
100 fn create_source_stream<C: IsA<Cancellable>>(
101 &self,
102 condition: glib::IOCondition,
103 cancellable: Option<&C>,
104 priority: glib::Priority,
105 ) -> Pin<Box<dyn Stream<Item = glib::IOCondition> + 'static>> {
106 let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
107
108 let obj = self.clone();
109 Box::pin(glib::SourceStream::new(move |send| {
110 let send = Some(send);
111 obj.create_source(
112 condition,
113 cancellable.as_ref(),
114 None,
115 priority,
116 move |_, condition| {
117 if send.as_ref().unwrap().unbounded_send(condition).is_err() {
118 glib::ControlFlow::Break
119 } else {
120 glib::ControlFlow::Continue
121 }
122 },
123 )
124 }))
125 }
126
127 #[doc(alias = "g_datagram_based_condition_wait")]
128 fn condition_wait(
129 &self,
130 condition: glib::IOCondition,
131 timeout: Option<Duration>,
132 cancellable: Option<&impl IsA<Cancellable>>,
133 ) -> Result<(), glib::Error> {
134 unsafe {
135 let mut error = ptr::null_mut();
136 let is_ok = ffi::g_datagram_based_condition_wait(
137 self.as_ref().to_glib_none().0,
138 condition.into_glib(),
139 timeout
140 .map(|t| t.as_micros().try_into().unwrap())
141 .unwrap_or(-1),
142 cancellable.map(|p| p.as_ref()).to_glib_none().0,
143 &mut error,
144 );
145 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
146 if error.is_null() {
147 Ok(())
148 } else {
149 Err(from_glib_full(error))
150 }
151 }
152 }
153
154 #[doc(alias = "g_datagram_based_receive_messages")]
155 fn receive_messages<'v, V: IntoIterator<Item = &'v mut [&'v mut [u8]]>, C: IsA<Cancellable>>(
156 &self,
157 messages: &mut [InputMessage],
158 flags: i32,
159 timeout: Option<Duration>,
160 cancellable: Option<&C>,
161 ) -> Result<usize, glib::Error> {
162 let cancellable = cancellable.map(|c| c.as_ref());
163 unsafe {
164 let mut error = ptr::null_mut();
165
166 let count = ffi::g_datagram_based_receive_messages(
167 self.as_ref().to_glib_none().0,
168 messages.as_mut_ptr() as *mut _,
169 messages.len().try_into().unwrap(),
170 flags,
171 timeout
172 .map(|t| t.as_micros().try_into().unwrap())
173 .unwrap_or(-1),
174 cancellable.to_glib_none().0,
175 &mut error,
176 );
177 if error.is_null() {
178 Ok(count as usize)
179 } else {
180 Err(from_glib_full(error))
181 }
182 }
183 }
184
185 #[doc(alias = "g_datagram_based_send_messages")]
186 fn send_messages<C: IsA<Cancellable>>(
187 &self,
188 messages: &mut [OutputMessage],
189 flags: i32,
190 timeout: Option<Duration>,
191 cancellable: Option<&C>,
192 ) -> Result<usize, glib::Error> {
193 let cancellable = cancellable.map(|c| c.as_ref());
194 unsafe {
195 let mut error = ptr::null_mut();
196 let count = ffi::g_datagram_based_send_messages(
197 self.as_ref().to_glib_none().0,
198 messages.as_mut_ptr() as *mut _,
199 messages.len().try_into().unwrap(),
200 flags,
201 timeout
202 .map(|t| t.as_micros().try_into().unwrap())
203 .unwrap_or(-1),
204 cancellable.to_glib_none().0,
205 &mut error,
206 );
207 if error.is_null() {
208 Ok(count as usize)
209 } else {
210 Err(from_glib_full(error))
211 }
212 }
213 }
214}
215
216impl<O: IsA<DatagramBased>> DatagramBasedExtManual for O {}