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
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 {}