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