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