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