Skip to main content

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