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