/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bendy-0.3.3/src/encoding/encoder.rs
Line | Count | Source |
1 | | #[cfg(not(feature = "std"))] |
2 | | use alloc::{ |
3 | | borrow::ToOwned, |
4 | | collections::BTreeMap, |
5 | | format, |
6 | | string::{String, ToString}, |
7 | | vec::Vec, |
8 | | }; |
9 | | #[cfg(feature = "std")] |
10 | | use std::{collections::BTreeMap, vec::Vec}; |
11 | | |
12 | | use crate::{ |
13 | | encoding::{Error, PrintableInteger, ToBencode}, |
14 | | state_tracker::{StateTracker, StructureError, Token}, |
15 | | }; |
16 | | |
17 | | /// The actual encoder. Unlike the decoder, this is not zero-copy, as that would |
18 | | /// result in a horrible interface |
19 | | #[derive(Default, Debug)] |
20 | | pub struct Encoder { |
21 | | state: StateTracker<Vec<u8>, Error>, |
22 | | output: Vec<u8>, |
23 | | } |
24 | | |
25 | | impl Encoder { |
26 | | /// Create a new encoder |
27 | 0 | pub fn new() -> Self { |
28 | 0 | <Self as Default>::default() |
29 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::new Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::new |
30 | | |
31 | | /// Set the max depth of the encoded object |
32 | | #[must_use] |
33 | 0 | pub fn with_max_depth(mut self, max_depth: usize) -> Self { |
34 | 0 | self.state.set_max_depth(max_depth); |
35 | 0 | self |
36 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::with_max_depth Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::with_max_depth |
37 | | |
38 | | /// Emit a single token to the encoder |
39 | 0 | pub(crate) fn emit_token(&mut self, token: Token) -> Result<(), Error> { |
40 | 0 | self.state.check_error()?; |
41 | 0 | self.state.observe_token(&token)?; |
42 | 0 | match token { |
43 | 0 | Token::List => self.output.push(b'l'), |
44 | 0 | Token::Dict => self.output.push(b'd'), |
45 | 0 | Token::String(s) => { |
46 | 0 | // Writing to a vec can't fail |
47 | 0 | let length = s.len().to_string(); |
48 | 0 | self.output.extend_from_slice(length.as_bytes()); |
49 | 0 | self.output.push(b':'); |
50 | 0 | self.output.extend_from_slice(s); |
51 | 0 | }, |
52 | 0 | Token::Num(num) => { |
53 | 0 | // Alas, this doesn't verify that the given number is valid |
54 | 0 | self.output.push(b'i'); |
55 | 0 | self.output.extend_from_slice(num.as_bytes()); |
56 | 0 | self.output.push(b'e'); |
57 | 0 | }, |
58 | 0 | Token::End => self.output.push(b'e'), |
59 | | } |
60 | | |
61 | 0 | Ok(()) |
62 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_token Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_token |
63 | | |
64 | | /// Emit an arbitrary encodable object |
65 | 0 | pub fn emit<E: ToBencode>(&mut self, value: E) -> Result<(), Error> { |
66 | 0 | self.emit_with(|e| value.encode(e)) Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit::<&bendy::value::Value>::{closure#0}Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit::<&bendy::value::Value>::{closure#0} |
67 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit::<&bendy::value::Value> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit::<&bendy::value::Value> |
68 | | |
69 | | /// Emit a single object using an encoder |
70 | 0 | pub fn emit_with<F>(&mut self, value_cb: F) -> Result<(), Error> |
71 | 0 | where |
72 | 0 | F: FnOnce(SingleItemEncoder) -> Result<(), Error>, |
73 | | { |
74 | 0 | let mut value_written = false; |
75 | 0 | let ret = value_cb(SingleItemEncoder { |
76 | 0 | encoder: self, |
77 | 0 | value_written: &mut value_written, |
78 | 0 | }); |
79 | | |
80 | 0 | self.state.latch_err(ret)?; |
81 | | |
82 | 0 | if !value_written { |
83 | 0 | return self |
84 | 0 | .state |
85 | 0 | .latch_err(Err(Error::from(StructureError::invalid_state( |
86 | 0 | "No value was emitted", |
87 | 0 | )))); |
88 | 0 | } |
89 | | |
90 | 0 | Ok(()) |
91 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_with::<<bendy::encoding::encoder::Encoder>::emit<&bendy::value::Value>::{closure#0}>Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_with::<<bendy::encoding::encoder::Encoder>::emit<&bendy::value::Value>::{closure#0}> |
92 | | |
93 | | /// Emit an integer |
94 | 0 | pub fn emit_int<T: PrintableInteger>(&mut self, value: T) -> Result<(), Error> { |
95 | | // This doesn't use emit_token, as that would require that I write the integer to a |
96 | | // temporary buffer and then copy it to the output; writing it directly saves at |
97 | | // least one memory allocation |
98 | 0 | self.state.check_error()?; |
99 | | // We observe an int here, as we need something that isn't a string (and therefore |
100 | | // possibly valid as a key) but we also want to require as few state transitions as |
101 | | // possible (for performance) |
102 | 0 | self.state.observe_token(&Token::Num(""))?; |
103 | 0 | self.output.push(b'i'); |
104 | 0 | self.output.extend_from_slice(value.to_string().as_bytes()); |
105 | 0 | self.output.push(b'e'); |
106 | 0 | Ok(()) |
107 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i8> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u8> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<isize> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<usize> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i32> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u32> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i128> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u128> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i16> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u16> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i64> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u64> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i8> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u8> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<isize> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<usize> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i32> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u32> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i128> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u128> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i16> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u16> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<i64> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_int::<u64> |
108 | | |
109 | | /// Emit a string |
110 | 0 | pub fn emit_str(&mut self, value: &str) -> Result<(), Error> { |
111 | 0 | self.emit_token(Token::String(value.as_bytes())) |
112 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_str Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_str |
113 | | |
114 | | /// Emit a byte array |
115 | 0 | pub fn emit_bytes(&mut self, value: &[u8]) -> Result<(), Error> { |
116 | 0 | self.emit_token(Token::String(value)) |
117 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_bytes Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_bytes |
118 | | |
119 | | /// Emit a dictionary where you know that the keys are already |
120 | | /// sorted. The callback must emit key/value pairs to the given |
121 | | /// encoder in sorted order. If the key/value pairs may not be |
122 | | /// sorted, [`emit_unsorted_dict`] should be used instead. |
123 | | /// |
124 | | /// [`emit_unsorted_dict`]: SingleItemEncoder::emit_unsorted_dict |
125 | | /// |
126 | | /// Example: |
127 | | /// |
128 | | /// ``` |
129 | | /// # use bendy::encoding::{Encoder, Error}; |
130 | | /// # |
131 | | /// # fn main() -> Result<(), Error>{ |
132 | | /// let mut encoder = Encoder::new(); |
133 | | /// encoder.emit_dict(|mut e| { |
134 | | /// e.emit_pair(b"a", "foo")?; |
135 | | /// e.emit_pair(b"b", 2) |
136 | | /// }) |
137 | | /// # } |
138 | | /// ``` |
139 | 0 | pub fn emit_dict<F>(&mut self, content_cb: F) -> Result<(), Error> |
140 | 0 | where |
141 | 0 | F: FnOnce(SortedDictEncoder) -> Result<(), Error>, |
142 | | { |
143 | 0 | self.emit_token(Token::Dict)?; |
144 | 0 | content_cb(SortedDictEncoder { encoder: self })?; |
145 | 0 | self.emit_token(Token::End) |
146 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_dict::<<alloc::collections::btree::map::BTreeMap<alloc::borrow::Cow<[u8]>, bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}>Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_dict::<<alloc::collections::btree::map::BTreeMap<alloc::borrow::Cow<[u8]>, bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}> |
147 | | |
148 | | /// Emit an arbitrary list. The callback should emit the contents |
149 | | /// of the list to the given encoder. |
150 | | /// |
151 | | /// E.g., to emit the list `[1,2,3]`, you would write |
152 | | /// |
153 | | /// ``` |
154 | | /// # use bendy::encoding::{Encoder, Error}; |
155 | | /// # fn main() -> Result<(), Error> { |
156 | | /// let mut encoder = Encoder::new(); |
157 | | /// encoder.emit_list(|e| { |
158 | | /// e.emit_int(1)?; |
159 | | /// e.emit_int(2)?; |
160 | | /// e.emit_int(3) |
161 | | /// }) |
162 | | /// # } |
163 | | /// ``` |
164 | 0 | pub fn emit_list<F>(&mut self, list_cb: F) -> Result<(), Error> |
165 | 0 | where |
166 | 0 | F: FnOnce(&mut Encoder) -> Result<(), Error>, |
167 | | { |
168 | 0 | self.emit_token(Token::List)?; |
169 | 0 | list_cb(self)?; |
170 | 0 | self.emit_token(Token::End) |
171 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_list::<<alloc::vec::Vec<bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}>Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_list::<<alloc::vec::Vec<bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}> |
172 | | |
173 | | /// Emit a dictionary that may have keys out of order. This will write the dict |
174 | | /// values to temporary memory, then sort them before adding them to the serialized |
175 | | /// stream |
176 | | /// |
177 | | /// Example. |
178 | | /// |
179 | | /// ``` |
180 | | /// # use bendy::encoding::{Encoder, Error}; |
181 | | /// # |
182 | | /// # fn main() -> Result<(), Error> { |
183 | | /// let mut encoder = Encoder::new(); |
184 | | /// encoder.emit_and_sort_dict(|e| { |
185 | | /// // Unlike in the example for Encoder::emit_dict(), these keys aren't sorted |
186 | | /// e.emit_pair(b"b", 2)?; |
187 | | /// e.emit_pair(b"a", "foo") |
188 | | /// }) |
189 | | /// # } |
190 | | /// ``` |
191 | 0 | pub fn emit_and_sort_dict<F>(&mut self, content_cb: F) -> Result<(), Error> |
192 | 0 | where |
193 | 0 | F: FnOnce(&mut UnsortedDictEncoder) -> Result<(), Error>, |
194 | | { |
195 | 0 | let mut encoder = self.begin_unsorted_dict()?; |
196 | | |
197 | 0 | content_cb(&mut encoder)?; |
198 | | |
199 | 0 | self.end_unsorted_dict(encoder) |
200 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_and_sort_dict::<_> Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::emit_and_sort_dict::<_> |
201 | | |
202 | | /// Return the encoded string, if all objects written are complete |
203 | 0 | pub fn get_output(mut self) -> Result<Vec<u8>, Error> { |
204 | 0 | self.state.observe_eof()?; |
205 | 0 | Ok(self.output) |
206 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::get_output Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::get_output |
207 | | |
208 | 0 | pub(crate) fn begin_unsorted_dict(&mut self) -> Result<UnsortedDictEncoder, Error> { |
209 | | // emit the dict token so that a pre-existing state error is reported early |
210 | 0 | self.emit_token(Token::Dict)?; |
211 | | |
212 | 0 | Ok(UnsortedDictEncoder::new(self.state.remaining_depth())) |
213 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::begin_unsorted_dict Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::begin_unsorted_dict |
214 | | |
215 | 0 | pub(crate) fn end_unsorted_dict(&mut self, encoder: UnsortedDictEncoder) -> Result<(), Error> { |
216 | 0 | let content = encoder.done()?; |
217 | | |
218 | 0 | for (k, v) in content { |
219 | 0 | self.emit_bytes(&k)?; |
220 | | // We know that the output is a single object by construction |
221 | 0 | self.state.observe_token(&Token::Num(""))?; |
222 | 0 | self.output.extend_from_slice(&v); |
223 | | } |
224 | | |
225 | 0 | self.emit_token(Token::End)?; |
226 | | |
227 | 0 | Ok(()) |
228 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::end_unsorted_dict Unexecuted instantiation: <bendy::encoding::encoder::Encoder>::end_unsorted_dict |
229 | | } |
230 | | |
231 | | /// An encoder that can only encode a single item. See [`Encoder`] |
232 | | /// for usage examples; the only difference between these classes is |
233 | | /// that `SingleItemEncoder` can only be used once. |
234 | | pub struct SingleItemEncoder<'a> { |
235 | | encoder: &'a mut Encoder, |
236 | | /// Whether we attempted to write a value to the encoder. The value |
237 | | /// of the referent of this field is meaningless if the encode method |
238 | | /// failed. |
239 | | value_written: &'a mut bool, |
240 | | } |
241 | | |
242 | | impl<'a> SingleItemEncoder<'a> { |
243 | | /// Emit an arbitrary encodable object |
244 | 0 | pub fn emit<E: ToBencode + ?Sized>(self, value: &E) -> Result<(), Error> { |
245 | 0 | value.encode(self) |
246 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit::<_> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit::<_> |
247 | | |
248 | | /// Emit a single object using an encoder |
249 | 0 | pub fn emit_with<F>(self, value_cb: F) -> Result<(), Error> |
250 | 0 | where |
251 | 0 | F: FnOnce(SingleItemEncoder) -> Result<(), Error>, |
252 | | { |
253 | 0 | value_cb(self) |
254 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_with::<_> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_with::<_> |
255 | | |
256 | | /// Emit an integer |
257 | 0 | pub fn emit_int<T: PrintableInteger>(self, value: T) -> Result<(), Error> { |
258 | 0 | *self.value_written = true; |
259 | 0 | self.encoder.emit_int(value) |
260 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i8> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u8> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<isize> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<usize> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i32> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u32> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i128> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u128> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i16> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u16> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i64> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u64> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i8> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u8> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<isize> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<usize> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i32> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u32> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i128> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u128> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i16> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u16> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<i64> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_int::<u64> |
261 | | |
262 | | /// Emit a string |
263 | 0 | pub fn emit_str(self, value: &str) -> Result<(), Error> { |
264 | 0 | *self.value_written = true; |
265 | 0 | self.encoder.emit_str(value) |
266 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_str Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_str |
267 | | |
268 | | /// Emit a byte array |
269 | 0 | pub fn emit_bytes(self, value: &[u8]) -> Result<(), Error> { |
270 | 0 | *self.value_written = true; |
271 | 0 | self.encoder.emit_bytes(value) |
272 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_bytes Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_bytes |
273 | | |
274 | | /// Emit an arbitrary list |
275 | 0 | pub fn emit_list<F>(self, list_cb: F) -> Result<(), Error> |
276 | 0 | where |
277 | 0 | F: FnOnce(&mut Encoder) -> Result<(), Error>, |
278 | | { |
279 | 0 | *self.value_written = true; |
280 | 0 | self.encoder.emit_list(list_cb) |
281 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_list::<<alloc::vec::Vec<bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}>Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_list::<<alloc::vec::Vec<bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}> |
282 | | |
283 | | /// Emit a sorted dictionary. If the input dictionary is unsorted, this will return an error. |
284 | 0 | pub fn emit_dict<F>(self, content_cb: F) -> Result<(), Error> |
285 | 0 | where |
286 | 0 | F: FnOnce(SortedDictEncoder) -> Result<(), Error>, |
287 | | { |
288 | 0 | *self.value_written = true; |
289 | 0 | self.encoder.emit_dict(content_cb) |
290 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_dict::<<alloc::collections::btree::map::BTreeMap<alloc::borrow::Cow<[u8]>, bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}>Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_dict::<<alloc::collections::btree::map::BTreeMap<alloc::borrow::Cow<[u8]>, bendy::value::Value> as bendy::encoding::to_bencode::ToBencode>::encode::{closure#0}> |
291 | | |
292 | | /// Emit a dictionary that may have keys out of order. This will write the dict |
293 | | /// values to temporary memory, then sort them before adding them to the serialized |
294 | | /// stream |
295 | 0 | pub fn emit_unsorted_dict<F>(self, content_cb: F) -> Result<(), Error> |
296 | 0 | where |
297 | 0 | F: FnOnce(&mut UnsortedDictEncoder) -> Result<(), Error>, |
298 | | { |
299 | 0 | *self.value_written = true; |
300 | 0 | self.encoder.emit_and_sort_dict(content_cb) |
301 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_unsorted_dict::<_> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_unsorted_dict::<_> |
302 | | |
303 | | /// Emit an arbitrary list. |
304 | | /// |
305 | | /// Attention: If this method is used while canonical output is required |
306 | | /// the caller needs to ensure that the iterator has a defined order. |
307 | 0 | pub fn emit_unchecked_list( |
308 | 0 | self, |
309 | 0 | iterable: impl Iterator<Item = impl ToBencode>, |
310 | 0 | ) -> Result<(), Error> { |
311 | 0 | self.emit_list(|e| { |
312 | 0 | for item in iterable { |
313 | 0 | e.emit(item)?; |
314 | | } |
315 | 0 | Ok(()) |
316 | 0 | }) Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_unchecked_list::<_, _>::{closure#0}Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_unchecked_list::<_, _>::{closure#0} |
317 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_unchecked_list::<_, _> Unexecuted instantiation: <bendy::encoding::encoder::SingleItemEncoder>::emit_unchecked_list::<_, _> |
318 | | } |
319 | | |
320 | | /// Encodes a map with pre-sorted keys |
321 | | pub struct SortedDictEncoder<'a> { |
322 | | encoder: &'a mut Encoder, |
323 | | } |
324 | | |
325 | | impl<'a> SortedDictEncoder<'a> { |
326 | | /// Emit a key/value pair |
327 | 0 | pub fn emit_pair<E>(&mut self, key: &[u8], value: E) -> Result<(), Error> |
328 | 0 | where |
329 | 0 | E: ToBencode, |
330 | | { |
331 | 0 | self.encoder.emit_token(Token::String(key))?; |
332 | 0 | self.encoder.emit(value) |
333 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SortedDictEncoder>::emit_pair::<&bendy::value::Value> Unexecuted instantiation: <bendy::encoding::encoder::SortedDictEncoder>::emit_pair::<&bendy::value::Value> |
334 | | |
335 | | /// Equivalent to [`SortedDictEncoder::emit_pair()`], but forces the type of the value |
336 | | /// to be a callback |
337 | 0 | pub fn emit_pair_with<F>(&mut self, key: &[u8], value_cb: F) -> Result<(), Error> |
338 | 0 | where |
339 | 0 | F: FnOnce(SingleItemEncoder) -> Result<(), Error>, |
340 | | { |
341 | 0 | self.encoder.emit_token(Token::String(key))?; |
342 | 0 | self.encoder.emit_with(value_cb) |
343 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::SortedDictEncoder>::emit_pair_with::<_> Unexecuted instantiation: <bendy::encoding::encoder::SortedDictEncoder>::emit_pair_with::<_> |
344 | | } |
345 | | |
346 | | /// Helper to write a dictionary that may have keys out of order. This will buffer the |
347 | | /// dict values in temporary memory, then sort them before adding them to the serialized |
348 | | /// stream |
349 | | pub struct UnsortedDictEncoder { |
350 | | content: BTreeMap<Vec<u8>, Vec<u8>>, |
351 | | error: Result<(), Error>, |
352 | | remaining_depth: usize, |
353 | | } |
354 | | |
355 | | impl UnsortedDictEncoder { |
356 | 0 | pub(crate) fn new(remaining_depth: usize) -> Self { |
357 | 0 | Self { |
358 | 0 | content: BTreeMap::new(), |
359 | 0 | error: Ok(()), |
360 | 0 | remaining_depth, |
361 | 0 | } |
362 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::new Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::new |
363 | | |
364 | | /// Emit a key/value pair |
365 | 0 | pub fn emit_pair<E>(&mut self, key: &[u8], value: E) -> Result<(), Error> |
366 | 0 | where |
367 | 0 | E: ToBencode, |
368 | | { |
369 | 0 | self.emit_pair_with(key, |e| value.encode(e)) Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::emit_pair::<_>::{closure#0}Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::emit_pair::<_>::{closure#0} |
370 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::emit_pair::<_> Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::emit_pair::<_> |
371 | | |
372 | | /// Emit a key/value pair where the value is produced by a callback |
373 | 0 | pub fn emit_pair_with<F>(&mut self, key: &[u8], value_cb: F) -> Result<(), Error> |
374 | 0 | where |
375 | 0 | F: FnOnce(SingleItemEncoder) -> Result<(), Error>, |
376 | | { |
377 | 0 | let mut value_written = false; |
378 | | |
379 | 0 | let mut encoder = Encoder::new().with_max_depth(self.remaining_depth); |
380 | | |
381 | 0 | let ret = value_cb(SingleItemEncoder { |
382 | 0 | encoder: &mut encoder, |
383 | 0 | value_written: &mut value_written, |
384 | 0 | }); |
385 | | |
386 | 0 | if ret.is_err() { |
387 | 0 | self.error = ret.clone(); |
388 | 0 | return ret; |
389 | 0 | } |
390 | | |
391 | 0 | if !value_written { |
392 | 0 | self.error = Err(Error::from(StructureError::InvalidState( |
393 | 0 | "No value was emitted".to_owned(), |
394 | 0 | ))); |
395 | 0 | } else { |
396 | 0 | self.error = encoder.state.observe_eof().map_err(Error::from); |
397 | 0 | } |
398 | | |
399 | 0 | if self.error.is_err() { |
400 | 0 | return self.error.clone(); |
401 | 0 | } |
402 | | |
403 | 0 | let encoded_object = encoder |
404 | 0 | .get_output() |
405 | 0 | .expect("Any errors should have been caught by observe_eof"); |
406 | | |
407 | 0 | self.save_pair(key, encoded_object) |
408 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::emit_pair_with::<_> Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::emit_pair_with::<_> |
409 | | |
410 | | #[cfg(feature = "serde")] |
411 | | pub(crate) fn remaining_depth(&self) -> usize { |
412 | | self.remaining_depth |
413 | | } |
414 | | |
415 | 0 | pub(crate) fn save_pair( |
416 | 0 | &mut self, |
417 | 0 | unencoded_key: &[u8], |
418 | 0 | encoded_value: Vec<u8>, |
419 | 0 | ) -> Result<(), Error> { |
420 | | #[cfg(not(feature = "std"))] |
421 | | use alloc::collections::btree_map::Entry; |
422 | | #[cfg(feature = "std")] |
423 | | use std::collections::btree_map::Entry; |
424 | | |
425 | 0 | if self.error.is_err() { |
426 | 0 | return self.error.clone(); |
427 | 0 | } |
428 | | |
429 | 0 | let vacancy = match self.content.entry(unencoded_key.to_owned()) { |
430 | 0 | Entry::Vacant(vacancy) => vacancy, |
431 | 0 | Entry::Occupied(occupation) => { |
432 | 0 | self.error = Err(Error::from(StructureError::InvalidState(format!( |
433 | 0 | "Duplicate key {}", |
434 | 0 | String::from_utf8_lossy(occupation.key()) |
435 | 0 | )))); |
436 | 0 | return self.error.clone(); |
437 | | }, |
438 | | }; |
439 | | |
440 | 0 | vacancy.insert(encoded_value); |
441 | | |
442 | 0 | Ok(()) |
443 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::save_pair Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::save_pair |
444 | | |
445 | 0 | pub(crate) fn done(self) -> Result<BTreeMap<Vec<u8>, Vec<u8>>, Error> { |
446 | 0 | self.error?; |
447 | 0 | Ok(self.content) |
448 | 0 | } Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::done Unexecuted instantiation: <bendy::encoding::encoder::UnsortedDictEncoder>::done |
449 | | } |
450 | | |
451 | | #[cfg(test)] |
452 | | mod test { |
453 | | use super::*; |
454 | | |
455 | | #[test] |
456 | | pub fn simple_encoding_works() { |
457 | | let mut encoder = Encoder::new(); |
458 | | encoder |
459 | | .emit_dict(|mut e| { |
460 | | e.emit_pair(b"bar", 25)?; |
461 | | e.emit_pair_with(b"foo", |e| { |
462 | | e.emit_list(|e| { |
463 | | e.emit_str("baz")?; |
464 | | e.emit_str("qux") |
465 | | }) |
466 | | }) |
467 | | }) |
468 | | .expect("Encoding shouldn't fail"); |
469 | | assert_eq!( |
470 | | &encoder |
471 | | .get_output() |
472 | | .expect("Complete object should have been written"), |
473 | | &b"d3:bari25e3:fool3:baz3:quxee" |
474 | | ); |
475 | | } |
476 | | |
477 | | #[test] |
478 | | fn emit_cb_must_emit() { |
479 | | let mut encoder = Encoder::new(); |
480 | | assert!(encoder.emit_with(|_| Ok(())).is_err()); |
481 | | } |
482 | | } |