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