Coverage Report

Created: 2026-09-28 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}