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