gio/
data_input_stream.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, mem, pin::Pin, ptr};
4
5use glib::{prelude::*, translate::*, GString};
6
7use crate::{ffi, Cancellable, DataInputStream};
8
9mod sealed {
10    pub trait Sealed {}
11    impl<T: super::IsA<super::DataInputStream>> Sealed for T {}
12}
13
14pub trait DataInputStreamExtManual: sealed::Sealed + IsA<DataInputStream> + 'static {
15    /// Reads a line from the data input stream.  Note that no encoding
16    /// checks or conversion is performed; the input is not guaranteed to
17    /// be UTF-8, and may in fact have embedded NUL characters.
18    ///
19    /// If @cancellable is not [`None`], then the operation can be cancelled by
20    /// triggering the cancellable object from another thread. If the operation
21    /// was cancelled, the error [`IOErrorEnum::Cancelled`][crate::IOErrorEnum::Cancelled] will be returned.
22    /// ## `cancellable`
23    /// optional #GCancellable object, [`None`] to ignore.
24    ///
25    /// # Returns
26    ///
27    ///
28    ///  a NUL terminated byte array with the line that was read in
29    ///  (without the newlines).  Set @length to a #gsize to get the length
30    ///  of the read line.  On an error, it will return [`None`] and @error
31    ///  will be set. If there's no content to read, it will still return
32    ///  [`None`], but @error won't be set.
33    ///
34    /// ## `length`
35    /// a #gsize to get the length of the data read in.
36    #[doc(alias = "g_data_input_stream_read_line")]
37    fn read_line<P: IsA<Cancellable>>(
38        &self,
39        cancellable: Option<&P>,
40    ) -> Result<glib::collections::Slice<u8>, glib::Error> {
41        unsafe {
42            let mut length = mem::MaybeUninit::uninit();
43            let mut error = ptr::null_mut();
44            let ret = ffi::g_data_input_stream_read_line(
45                self.as_ref().to_glib_none().0,
46                length.as_mut_ptr(),
47                cancellable.map(|p| p.as_ref()).to_glib_none().0,
48                &mut error,
49            );
50            let length = length.assume_init();
51            if error.is_null() {
52                Ok(FromGlibContainer::from_glib_full_num(ret, length))
53            } else {
54                Err(from_glib_full(error))
55            }
56        }
57    }
58
59    /// The asynchronous version of g_data_input_stream_read_line().  It is
60    /// an error to have two outstanding calls to this function.
61    ///
62    /// When the operation is finished, @callback will be called. You
63    /// can then call g_data_input_stream_read_line_finish() to get
64    /// the result of the operation.
65    /// ## `io_priority`
66    /// the [I/O priority](iface.AsyncResult.html#io-priority) of the request
67    /// ## `cancellable`
68    /// optional #GCancellable object, [`None`] to ignore.
69    /// ## `callback`
70    /// callback to call when the request is satisfied.
71    #[doc(alias = "g_data_input_stream_read_line_async")]
72    fn read_line_async<
73        P: IsA<Cancellable>,
74        Q: FnOnce(Result<glib::collections::Slice<u8>, glib::Error>) + 'static,
75    >(
76        &self,
77        io_priority: glib::Priority,
78        cancellable: Option<&P>,
79        callback: Q,
80    ) {
81        let main_context = glib::MainContext::ref_thread_default();
82        let is_main_context_owner = main_context.is_owner();
83        let has_acquired_main_context = (!is_main_context_owner)
84            .then(|| main_context.acquire().ok())
85            .flatten();
86        assert!(
87            is_main_context_owner || has_acquired_main_context.is_some(),
88            "Async operations only allowed if the thread is owning the MainContext"
89        );
90
91        let user_data: Box_<glib::thread_guard::ThreadGuard<Q>> =
92            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
93        unsafe extern "C" fn read_line_async_trampoline<
94            Q: FnOnce(Result<glib::collections::Slice<u8>, glib::Error>) + 'static,
95        >(
96            _source_object: *mut glib::gobject_ffi::GObject,
97            res: *mut ffi::GAsyncResult,
98            user_data: glib::ffi::gpointer,
99        ) {
100            let mut error = ptr::null_mut();
101            let mut length = mem::MaybeUninit::uninit();
102            let ret = ffi::g_data_input_stream_read_line_finish(
103                _source_object as *mut _,
104                res,
105                length.as_mut_ptr(),
106                &mut error,
107            );
108            let length = length.assume_init();
109            let result = if error.is_null() {
110                Ok(FromGlibContainer::from_glib_full_num(ret, length))
111            } else {
112                Err(from_glib_full(error))
113            };
114            let callback: Box_<glib::thread_guard::ThreadGuard<Q>> =
115                Box_::from_raw(user_data as *mut _);
116            let callback = callback.into_inner();
117            callback(result);
118        }
119        let callback = read_line_async_trampoline::<Q>;
120        unsafe {
121            ffi::g_data_input_stream_read_line_async(
122                self.as_ref().to_glib_none().0,
123                io_priority.into_glib(),
124                cancellable.map(|p| p.as_ref()).to_glib_none().0,
125                Some(callback),
126                Box_::into_raw(user_data) as *mut _,
127            );
128        }
129    }
130
131    fn read_line_future(
132        &self,
133        io_priority: glib::Priority,
134    ) -> Pin<
135        Box_<
136            dyn std::future::Future<Output = Result<glib::collections::Slice<u8>, glib::Error>>
137                + 'static,
138        >,
139    > {
140        Box_::pin(crate::GioFuture::new(
141            self,
142            move |obj, cancellable, send| {
143                obj.read_line_async(io_priority, Some(cancellable), move |res| {
144                    send.resolve(res);
145                });
146            },
147        ))
148    }
149
150    /// Reads a UTF-8 encoded line from the data input stream.
151    ///
152    /// If @cancellable is not [`None`], then the operation can be cancelled by
153    /// triggering the cancellable object from another thread. If the operation
154    /// was cancelled, the error [`IOErrorEnum::Cancelled`][crate::IOErrorEnum::Cancelled] will be returned.
155    /// ## `cancellable`
156    /// optional #GCancellable object, [`None`] to ignore.
157    ///
158    /// # Returns
159    ///
160    /// a NUL terminated UTF-8 string
161    ///  with the line that was read in (without the newlines).  Set
162    ///  @length to a #gsize to get the length of the read line.  On an
163    ///  error, it will return [`None`] and @error will be set.  For UTF-8
164    ///  conversion errors, the set error domain is `G_CONVERT_ERROR`.  If
165    ///  there's no content to read, it will still return [`None`], but @error
166    ///  won't be set.
167    ///
168    /// ## `length`
169    /// a #gsize to get the length of the data read in.
170    #[doc(alias = "g_data_input_stream_read_line_utf8")]
171    fn read_line_utf8<P: IsA<Cancellable>>(
172        &self,
173        cancellable: Option<&P>,
174    ) -> Result<Option<GString>, glib::Error> {
175        unsafe {
176            let mut error = ptr::null_mut();
177            let ret = ffi::g_data_input_stream_read_line_utf8(
178                self.as_ref().to_glib_none().0,
179                ptr::null_mut(),
180                cancellable.map(|p| p.as_ref()).to_glib_none().0,
181                &mut error,
182            );
183            if error.is_null() {
184                Ok(from_glib_full(ret))
185            } else {
186                Err(from_glib_full(error))
187            }
188        }
189    }
190
191    fn read_line_utf8_async<
192        P: IsA<Cancellable>,
193        Q: FnOnce(Result<Option<GString>, glib::Error>) + 'static,
194    >(
195        &self,
196        io_priority: glib::Priority,
197        cancellable: Option<&P>,
198        callback: Q,
199    ) {
200        let main_context = glib::MainContext::ref_thread_default();
201        let is_main_context_owner = main_context.is_owner();
202        let has_acquired_main_context = (!is_main_context_owner)
203            .then(|| main_context.acquire().ok())
204            .flatten();
205        assert!(
206            is_main_context_owner || has_acquired_main_context.is_some(),
207            "Async operations only allowed if the thread is owning the MainContext"
208        );
209
210        let user_data: Box_<glib::thread_guard::ThreadGuard<Q>> =
211            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
212        unsafe extern "C" fn read_line_async_trampoline<
213            Q: FnOnce(Result<Option<GString>, glib::Error>) + 'static,
214        >(
215            _source_object: *mut glib::gobject_ffi::GObject,
216            res: *mut ffi::GAsyncResult,
217            user_data: glib::ffi::gpointer,
218        ) {
219            let mut error = ptr::null_mut();
220            let ret = ffi::g_data_input_stream_read_line_finish(
221                _source_object as *mut _,
222                res,
223                ptr::null_mut(),
224                &mut error,
225            );
226            let result = if error.is_null() {
227                Ok(from_glib_full(ret))
228            } else {
229                Err(from_glib_full(error))
230            };
231            let callback: Box_<glib::thread_guard::ThreadGuard<Q>> =
232                Box_::from_raw(user_data as *mut _);
233            let callback = callback.into_inner();
234            callback(result);
235        }
236        let callback = read_line_async_trampoline::<Q>;
237        unsafe {
238            ffi::g_data_input_stream_read_line_async(
239                self.as_ref().to_glib_none().0,
240                io_priority.into_glib(),
241                cancellable.map(|p| p.as_ref()).to_glib_none().0,
242                Some(callback),
243                Box_::into_raw(user_data) as *mut _,
244            );
245        }
246    }
247
248    fn read_line_utf8_future(
249        &self,
250        io_priority: glib::Priority,
251    ) -> Pin<Box_<dyn std::future::Future<Output = Result<Option<GString>, glib::Error>> + 'static>>
252    {
253        Box_::pin(crate::GioFuture::new(
254            self,
255            move |obj, cancellable, send| {
256                obj.read_line_utf8_async(io_priority, Some(cancellable), move |res| {
257                    send.resolve(res);
258                });
259            },
260        ))
261    }
262
263    /// Reads a string from the data input stream, up to the first
264    /// occurrence of any of the stop characters.
265    ///
266    /// In contrast to g_data_input_stream_read_until(), this function
267    /// does not consume the stop character. You have to use
268    /// g_data_input_stream_read_byte() to get it before calling
269    /// g_data_input_stream_read_upto() again.
270    ///
271    /// Note that @stop_chars may contain '\0' if @stop_chars_len is
272    /// specified.
273    ///
274    /// The returned string will always be nul-terminated on success.
275    /// ## `stop_chars`
276    /// characters to terminate the read
277    /// ## `stop_chars_len`
278    /// length of @stop_chars. May be -1 if @stop_chars is
279    ///     nul-terminated
280    /// ## `cancellable`
281    /// optional #GCancellable object, [`None`] to ignore
282    ///
283    /// # Returns
284    ///
285    /// a string with the data that was read
286    ///     before encountering any of the stop characters. Set @length to
287    ///     a #gsize to get the length of the string. This function will
288    ///     return [`None`] on an error
289    ///
290    /// ## `length`
291    /// a #gsize to get the length of the data read in
292    #[doc(alias = "g_data_input_stream_read_upto")]
293    fn read_upto<P: IsA<Cancellable>>(
294        &self,
295        stop_chars: &[u8],
296        cancellable: Option<&P>,
297    ) -> Result<glib::collections::Slice<u8>, glib::Error> {
298        let stop_chars_len = stop_chars.len() as isize;
299        unsafe {
300            let mut error = ptr::null_mut();
301            let mut length = mem::MaybeUninit::uninit();
302            let ret = ffi::g_data_input_stream_read_upto(
303                self.as_ref().to_glib_none().0,
304                stop_chars.to_glib_none().0 as *const _,
305                stop_chars_len,
306                length.as_mut_ptr(),
307                cancellable.map(|p| p.as_ref()).to_glib_none().0,
308                &mut error,
309            );
310            if error.is_null() {
311                let length = length.assume_init();
312                Ok(FromGlibContainer::from_glib_full_num(
313                    ret as *mut u8,
314                    length,
315                ))
316            } else {
317                Err(from_glib_full(error))
318            }
319        }
320    }
321
322    /// The asynchronous version of g_data_input_stream_read_upto().
323    /// It is an error to have two outstanding calls to this function.
324    ///
325    /// In contrast to g_data_input_stream_read_until(), this function
326    /// does not consume the stop character. You have to use
327    /// g_data_input_stream_read_byte() to get it before calling
328    /// g_data_input_stream_read_upto() again.
329    ///
330    /// Note that @stop_chars may contain '\0' if @stop_chars_len is
331    /// specified.
332    ///
333    /// When the operation is finished, @callback will be called. You
334    /// can then call g_data_input_stream_read_upto_finish() to get
335    /// the result of the operation.
336    /// ## `stop_chars`
337    /// characters to terminate the read
338    /// ## `stop_chars_len`
339    /// length of @stop_chars. May be -1 if @stop_chars is
340    ///     nul-terminated
341    /// ## `io_priority`
342    /// the [I/O priority](iface.AsyncResult.html#io-priority) of the request
343    /// ## `cancellable`
344    /// optional #GCancellable object, [`None`] to ignore
345    /// ## `callback`
346    /// callback to call when the request is satisfied
347    #[doc(alias = "g_data_input_stream_read_upto_async")]
348    fn read_upto_async<
349        P: IsA<Cancellable>,
350        Q: FnOnce(Result<glib::collections::Slice<u8>, glib::Error>) + 'static,
351    >(
352        &self,
353        stop_chars: &[u8],
354        io_priority: glib::Priority,
355        cancellable: Option<&P>,
356        callback: Q,
357    ) {
358        let main_context = glib::MainContext::ref_thread_default();
359        let is_main_context_owner = main_context.is_owner();
360        let has_acquired_main_context = (!is_main_context_owner)
361            .then(|| main_context.acquire().ok())
362            .flatten();
363        assert!(
364            is_main_context_owner || has_acquired_main_context.is_some(),
365            "Async operations only allowed if the thread is owning the MainContext"
366        );
367
368        let stop_chars_len = stop_chars.len() as isize;
369        let user_data: Box_<glib::thread_guard::ThreadGuard<Q>> =
370            Box_::new(glib::thread_guard::ThreadGuard::new(callback));
371        unsafe extern "C" fn read_upto_async_trampoline<
372            Q: FnOnce(Result<glib::collections::Slice<u8>, glib::Error>) + 'static,
373        >(
374            _source_object: *mut glib::gobject_ffi::GObject,
375            res: *mut ffi::GAsyncResult,
376            user_data: glib::ffi::gpointer,
377        ) {
378            let mut error = ptr::null_mut();
379            let mut length = mem::MaybeUninit::uninit();
380            let ret = ffi::g_data_input_stream_read_upto_finish(
381                _source_object as *mut _,
382                res,
383                length.as_mut_ptr(),
384                &mut error,
385            );
386            let result = if error.is_null() {
387                let length = length.assume_init();
388                Ok(FromGlibContainer::from_glib_full_num(
389                    ret as *mut u8,
390                    length,
391                ))
392            } else {
393                Err(from_glib_full(error))
394            };
395            let callback: Box_<glib::thread_guard::ThreadGuard<Q>> =
396                Box_::from_raw(user_data as *mut _);
397            let callback = callback.into_inner();
398            callback(result);
399        }
400        let callback = read_upto_async_trampoline::<Q>;
401        unsafe {
402            ffi::g_data_input_stream_read_upto_async(
403                self.as_ref().to_glib_none().0,
404                stop_chars.to_glib_none().0 as *const _,
405                stop_chars_len,
406                io_priority.into_glib(),
407                cancellable.map(|p| p.as_ref()).to_glib_none().0,
408                Some(callback),
409                Box_::into_raw(user_data) as *mut _,
410            );
411        }
412    }
413
414    fn read_upto_future(
415        &self,
416        stop_chars: &[u8],
417        io_priority: glib::Priority,
418    ) -> Pin<
419        Box_<
420            dyn std::future::Future<Output = Result<glib::collections::Slice<u8>, glib::Error>>
421                + 'static,
422        >,
423    > {
424        let stop_chars = Vec::from(stop_chars);
425        Box_::pin(crate::GioFuture::new(
426            self,
427            move |obj, cancellable, send| {
428                obj.read_upto_async(&stop_chars, io_priority, Some(cancellable), move |res| {
429                    send.resolve(res);
430                });
431            },
432        ))
433    }
434}
435
436impl<O: IsA<DataInputStream>> DataInputStreamExtManual for O {}