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