gio/
converter.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, ptr};
4
5use glib::{prelude::*, translate::*};
6
7use crate::{ffi, Converter, ConverterFlags, ConverterResult};
8
9mod sealed {
10    pub trait Sealed {}
11    impl<T: super::IsA<super::Converter>> Sealed for T {}
12}
13
14pub trait ConverterExtManual: sealed::Sealed + IsA<Converter> + 'static {
15    /// This is the main operation used when converting data. It is to be called
16    /// multiple times in a loop, and each time it will do some work, i.e.
17    /// producing some output (in @outbuf) or consuming some input (from @inbuf) or
18    /// both. If its not possible to do any work an error is returned.
19    ///
20    /// Note that a single call may not consume all input (or any input at all).
21    /// Also a call may produce output even if given no input, due to state stored
22    /// in the converter producing output.
23    ///
24    /// If any data was either produced or consumed, and then an error happens, then
25    /// only the successful conversion is reported and the error is returned on the
26    /// next call.
27    ///
28    /// A full conversion loop involves calling this method repeatedly, each time
29    /// giving it new input and space output space. When there is no more input
30    /// data after the data in @inbuf, the flag [`ConverterFlags::INPUT_AT_END`][crate::ConverterFlags::INPUT_AT_END] must be set.
31    /// The loop will be (unless some error happens) returning [`ConverterResult::Converted`][crate::ConverterResult::Converted]
32    /// each time until all data is consumed and all output is produced, then
33    /// [`ConverterResult::Finished`][crate::ConverterResult::Finished] is returned instead. Note, that [`ConverterResult::Finished`][crate::ConverterResult::Finished]
34    /// may be returned even if [`ConverterFlags::INPUT_AT_END`][crate::ConverterFlags::INPUT_AT_END] is not set, for instance
35    /// in a decompression converter where the end of data is detectable from the
36    /// data (and there might even be other data after the end of the compressed data).
37    ///
38    /// When some data has successfully been converted @bytes_read and is set to
39    /// the number of bytes read from @inbuf, and @bytes_written is set to indicate
40    /// how many bytes was written to @outbuf. If there are more data to output
41    /// or consume (i.e. unless the [`ConverterFlags::INPUT_AT_END`][crate::ConverterFlags::INPUT_AT_END] is specified) then
42    /// [`ConverterResult::Converted`][crate::ConverterResult::Converted] is returned, and if no more data is to be output
43    /// then [`ConverterResult::Finished`][crate::ConverterResult::Finished] is returned.
44    ///
45    /// On error [`ConverterResult::Error`][crate::ConverterResult::Error] is returned and @error is set accordingly.
46    /// Some errors need special handling:
47    ///
48    /// [`IOErrorEnum::NoSpace`][crate::IOErrorEnum::NoSpace] is returned if there is not enough space
49    /// to write the resulting converted data, the application should
50    /// call the function again with a larger @outbuf to continue.
51    ///
52    /// [`IOErrorEnum::PartialInput`][crate::IOErrorEnum::PartialInput] is returned if there is not enough
53    /// input to fully determine what the conversion should produce,
54    /// and the [`ConverterFlags::INPUT_AT_END`][crate::ConverterFlags::INPUT_AT_END] flag is not set. This happens for
55    /// example with an incomplete multibyte sequence when converting text,
56    /// or when a regexp matches up to the end of the input (and may match
57    /// further input). It may also happen when @inbuf_size is zero and
58    /// there is no more data to produce.
59    ///
60    /// When this happens the application should read more input and then
61    /// call the function again. If further input shows that there is no
62    /// more data call the function again with the same data but with
63    /// the [`ConverterFlags::INPUT_AT_END`][crate::ConverterFlags::INPUT_AT_END] flag set. This may cause the conversion
64    /// to finish as e.g. in the regexp match case (or, to fail again with
65    /// [`IOErrorEnum::PartialInput`][crate::IOErrorEnum::PartialInput] in e.g. a charset conversion where the
66    /// input is actually partial).
67    ///
68    /// After g_converter_convert() has returned [`ConverterResult::Finished`][crate::ConverterResult::Finished] the
69    /// converter object is in an invalid state where its not allowed
70    /// to call g_converter_convert() anymore. At this time you can only
71    /// free the object or call g_converter_reset() to reset it to the
72    /// initial state.
73    ///
74    /// If the flag [`ConverterFlags::FLUSH`][crate::ConverterFlags::FLUSH] is set then conversion is modified
75    /// to try to write out all internal state to the output. The application
76    /// has to call the function multiple times with the flag set, and when
77    /// the available input has been consumed and all internal state has
78    /// been produced then [`ConverterResult::Flushed`][crate::ConverterResult::Flushed] (or [`ConverterResult::Finished`][crate::ConverterResult::Finished] if
79    /// really at the end) is returned instead of [`ConverterResult::Converted`][crate::ConverterResult::Converted].
80    /// This is somewhat similar to what happens at the end of the input stream,
81    /// but done in the middle of the data.
82    ///
83    /// This has different meanings for different conversions. For instance
84    /// in a compression converter it would mean that we flush all the
85    /// compression state into output such that if you uncompress the
86    /// compressed data you get back all the input data. Doing this may
87    /// make the final file larger due to padding though. Another example
88    /// is a regexp conversion, where if you at the end of the flushed data
89    /// have a match, but there is also a potential longer match. In the
90    /// non-flushed case we would ask for more input, but when flushing we
91    /// treat this as the end of input and do the match.
92    ///
93    /// Flushing is not always possible (like if a charset converter flushes
94    /// at a partial multibyte sequence). Converters are supposed to try
95    /// to produce as much output as possible and then return an error
96    /// (typically [`IOErrorEnum::PartialInput`][crate::IOErrorEnum::PartialInput]).
97    /// ## `inbuf`
98    /// the buffer
99    ///         containing the data to convert.
100    /// ## `outbuf`
101    /// a
102    ///    buffer to write converted data in.
103    /// ## `flags`
104    /// a #GConverterFlags controlling the conversion details
105    ///
106    /// # Returns
107    ///
108    /// a #GConverterResult, [`ConverterResult::Error`][crate::ConverterResult::Error] on error.
109    ///
110    /// ## `bytes_read`
111    /// will be set to the number of bytes read
112    ///    from @inbuf on success
113    ///
114    /// ## `bytes_written`
115    /// will be set to the number of bytes
116    ///    written to @outbuf on success
117    #[doc(alias = "g_converter_convert")]
118    fn convert<IN: AsRef<[u8]>, OUT: AsMut<[u8]>>(
119        &self,
120        inbuf: IN,
121        outbuf: OUT,
122        flags: ConverterFlags,
123    ) -> Result<(ConverterResult, usize, usize), glib::Error> {
124        let inbuf: Box<IN> = Box::new(inbuf);
125        let (inbuf_size, inbuf) = {
126            let slice = (*inbuf).as_ref();
127            (slice.len(), slice.as_ptr())
128        };
129        let mut outbuf: Box<OUT> = Box::new(outbuf);
130        let (outbuf_size, outbuf) = {
131            let slice = (*outbuf).as_mut();
132            (slice.len(), slice.as_mut_ptr())
133        };
134        unsafe {
135            let mut bytes_read = mem::MaybeUninit::uninit();
136            let mut bytes_written = mem::MaybeUninit::uninit();
137            let mut error = ptr::null_mut();
138            let ret = ffi::g_converter_convert(
139                self.as_ref().to_glib_none().0,
140                mut_override(inbuf),
141                inbuf_size,
142                outbuf,
143                outbuf_size,
144                flags.into_glib(),
145                bytes_read.as_mut_ptr(),
146                bytes_written.as_mut_ptr(),
147                &mut error,
148            );
149            if error.is_null() {
150                Ok((
151                    from_glib(ret),
152                    bytes_read.assume_init(),
153                    bytes_written.assume_init(),
154                ))
155            } else {
156                Err(from_glib_full(error))
157            }
158        }
159    }
160}
161
162impl<O: IsA<Converter>> ConverterExtManual for O {}