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 {}