gio/
datagram_based.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use 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 {}