summaryrefslogtreecommitdiffstats
path: root/rust/vendor/bendy/src/encoding
diff options
context:
space:
mode:
Diffstat (limited to 'rust/vendor/bendy/src/encoding')
-rw-r--r--rust/vendor/bendy/src/encoding/encoder.rs482
-rw-r--r--rust/vendor/bendy/src/encoding/error.rs56
-rw-r--r--rust/vendor/bendy/src/encoding/printable_integer.rs15
-rw-r--r--rust/vendor/bendy/src/encoding/to_bencode.rs265
4 files changed, 818 insertions, 0 deletions
diff --git a/rust/vendor/bendy/src/encoding/encoder.rs b/rust/vendor/bendy/src/encoding/encoder.rs
new file mode 100644
index 0000000..ba4a164
--- /dev/null
+++ b/rust/vendor/bendy/src/encoding/encoder.rs
@@ -0,0 +1,482 @@
+#[cfg(not(feature = "std"))]
+use alloc::{
+ borrow::ToOwned,
+ collections::BTreeMap,
+ format,
+ string::{String, ToString},
+ vec::Vec,
+};
+#[cfg(feature = "std")]
+use std::{collections::BTreeMap, vec::Vec};
+
+use crate::{
+ encoding::{Error, PrintableInteger, ToBencode},
+ state_tracker::{StateTracker, StructureError, Token},
+};
+
+/// The actual encoder. Unlike the decoder, this is not zero-copy, as that would
+/// result in a horrible interface
+#[derive(Default, Debug)]
+pub struct Encoder {
+ state: StateTracker<Vec<u8>, Error>,
+ output: Vec<u8>,
+}
+
+impl Encoder {
+ /// Create a new encoder
+ pub fn new() -> Self {
+ <Self as Default>::default()
+ }
+
+ /// Set the max depth of the encoded object
+ #[must_use]
+ pub fn with_max_depth(mut self, max_depth: usize) -> Self {
+ self.state.set_max_depth(max_depth);
+ self
+ }
+
+ /// Emit a single token to the encoder
+ pub(crate) fn emit_token(&mut self, token: Token) -> Result<(), Error> {
+ self.state.check_error()?;
+ self.state.observe_token(&token)?;
+ match token {
+ Token::List => self.output.push(b'l'),
+ Token::Dict => self.output.push(b'd'),
+ Token::String(s) => {
+ // Writing to a vec can't fail
+ let length = s.len().to_string();
+ self.output.extend_from_slice(length.as_bytes());
+ self.output.push(b':');
+ self.output.extend_from_slice(s);
+ },
+ Token::Num(num) => {
+ // Alas, this doesn't verify that the given number is valid
+ self.output.push(b'i');
+ self.output.extend_from_slice(num.as_bytes());
+ self.output.push(b'e');
+ },
+ Token::End => self.output.push(b'e'),
+ }
+
+ Ok(())
+ }
+
+ /// Emit an arbitrary encodable object
+ pub fn emit<E: ToBencode>(&mut self, value: E) -> Result<(), Error> {
+ self.emit_with(|e| value.encode(e))
+ }
+
+ /// Emit a single object using an encoder
+ pub fn emit_with<F>(&mut self, value_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(SingleItemEncoder) -> Result<(), Error>,
+ {
+ let mut value_written = false;
+ let ret = value_cb(SingleItemEncoder {
+ encoder: self,
+ value_written: &mut value_written,
+ });
+
+ self.state.latch_err(ret)?;
+
+ if !value_written {
+ return self
+ .state
+ .latch_err(Err(Error::from(StructureError::invalid_state(
+ "No value was emitted",
+ ))));
+ }
+
+ Ok(())
+ }
+
+ /// Emit an integer
+ pub fn emit_int<T: PrintableInteger>(&mut self, value: T) -> Result<(), Error> {
+ // This doesn't use emit_token, as that would require that I write the integer to a
+ // temporary buffer and then copy it to the output; writing it directly saves at
+ // least one memory allocation
+ self.state.check_error()?;
+ // We observe an int here, as we need something that isn't a string (and therefore
+ // possibly valid as a key) but we also want to require as few state transitions as
+ // possible (for performance)
+ self.state.observe_token(&Token::Num(""))?;
+ self.output.push(b'i');
+ self.output.extend_from_slice(value.to_string().as_bytes());
+ self.output.push(b'e');
+ Ok(())
+ }
+
+ /// Emit a string
+ pub fn emit_str(&mut self, value: &str) -> Result<(), Error> {
+ self.emit_token(Token::String(value.as_bytes()))
+ }
+
+ /// Emit a byte array
+ pub fn emit_bytes(&mut self, value: &[u8]) -> Result<(), Error> {
+ self.emit_token(Token::String(value))
+ }
+
+ /// Emit a dictionary where you know that the keys are already
+ /// sorted. The callback must emit key/value pairs to the given
+ /// encoder in sorted order. If the key/value pairs may not be
+ /// sorted, [`emit_unsorted_dict`] should be used instead.
+ ///
+ /// [`emit_unsorted_dict`]: SingleItemEncoder::emit_unsorted_dict
+ ///
+ /// Example:
+ ///
+ /// ```
+ /// # use bendy::encoding::{Encoder, Error};
+ /// #
+ /// # fn main() -> Result<(), Error>{
+ /// let mut encoder = Encoder::new();
+ /// encoder.emit_dict(|mut e| {
+ /// e.emit_pair(b"a", "foo")?;
+ /// e.emit_pair(b"b", 2)
+ /// })
+ /// # }
+ /// ```
+ pub fn emit_dict<F>(&mut self, content_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(SortedDictEncoder) -> Result<(), Error>,
+ {
+ self.emit_token(Token::Dict)?;
+ content_cb(SortedDictEncoder { encoder: self })?;
+ self.emit_token(Token::End)
+ }
+
+ /// Emit an arbitrary list. The callback should emit the contents
+ /// of the list to the given encoder.
+ ///
+ /// E.g., to emit the list `[1,2,3]`, you would write
+ ///
+ /// ```
+ /// # use bendy::encoding::{Encoder, Error};
+ /// # fn main() -> Result<(), Error> {
+ /// let mut encoder = Encoder::new();
+ /// encoder.emit_list(|e| {
+ /// e.emit_int(1)?;
+ /// e.emit_int(2)?;
+ /// e.emit_int(3)
+ /// })
+ /// # }
+ /// ```
+ pub fn emit_list<F>(&mut self, list_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(&mut Encoder) -> Result<(), Error>,
+ {
+ self.emit_token(Token::List)?;
+ list_cb(self)?;
+ self.emit_token(Token::End)
+ }
+
+ /// Emit a dictionary that may have keys out of order. This will write the dict
+ /// values to temporary memory, then sort them before adding them to the serialized
+ /// stream
+ ///
+ /// Example.
+ ///
+ /// ```
+ /// # use bendy::encoding::{Encoder, Error};
+ /// #
+ /// # fn main() -> Result<(), Error> {
+ /// let mut encoder = Encoder::new();
+ /// encoder.emit_and_sort_dict(|e| {
+ /// // Unlike in the example for Encoder::emit_dict(), these keys aren't sorted
+ /// e.emit_pair(b"b", 2)?;
+ /// e.emit_pair(b"a", "foo")
+ /// })
+ /// # }
+ /// ```
+ pub fn emit_and_sort_dict<F>(&mut self, content_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(&mut UnsortedDictEncoder) -> Result<(), Error>,
+ {
+ let mut encoder = self.begin_unsorted_dict()?;
+
+ content_cb(&mut encoder)?;
+
+ self.end_unsorted_dict(encoder)
+ }
+
+ /// Return the encoded string, if all objects written are complete
+ pub fn get_output(mut self) -> Result<Vec<u8>, Error> {
+ self.state.observe_eof()?;
+ Ok(self.output)
+ }
+
+ pub(crate) fn begin_unsorted_dict(&mut self) -> Result<UnsortedDictEncoder, Error> {
+ // emit the dict token so that a pre-existing state error is reported early
+ self.emit_token(Token::Dict)?;
+
+ Ok(UnsortedDictEncoder::new(self.state.remaining_depth()))
+ }
+
+ pub(crate) fn end_unsorted_dict(&mut self, encoder: UnsortedDictEncoder) -> Result<(), Error> {
+ let content = encoder.done()?;
+
+ for (k, v) in content {
+ self.emit_bytes(&k)?;
+ // We know that the output is a single object by construction
+ self.state.observe_token(&Token::Num(""))?;
+ self.output.extend_from_slice(&v);
+ }
+
+ self.emit_token(Token::End)?;
+
+ Ok(())
+ }
+}
+
+/// An encoder that can only encode a single item. See [`Encoder`]
+/// for usage examples; the only difference between these classes is
+/// that `SingleItemEncoder` can only be used once.
+pub struct SingleItemEncoder<'a> {
+ encoder: &'a mut Encoder,
+ /// Whether we attempted to write a value to the encoder. The value
+ /// of the referent of this field is meaningless if the encode method
+ /// failed.
+ value_written: &'a mut bool,
+}
+
+impl<'a> SingleItemEncoder<'a> {
+ /// Emit an arbitrary encodable object
+ pub fn emit<E: ToBencode + ?Sized>(self, value: &E) -> Result<(), Error> {
+ value.encode(self)
+ }
+
+ /// Emit a single object using an encoder
+ pub fn emit_with<F>(self, value_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(SingleItemEncoder) -> Result<(), Error>,
+ {
+ value_cb(self)
+ }
+
+ /// Emit an integer
+ pub fn emit_int<T: PrintableInteger>(self, value: T) -> Result<(), Error> {
+ *self.value_written = true;
+ self.encoder.emit_int(value)
+ }
+
+ /// Emit a string
+ pub fn emit_str(self, value: &str) -> Result<(), Error> {
+ *self.value_written = true;
+ self.encoder.emit_str(value)
+ }
+
+ /// Emit a byte array
+ pub fn emit_bytes(self, value: &[u8]) -> Result<(), Error> {
+ *self.value_written = true;
+ self.encoder.emit_bytes(value)
+ }
+
+ /// Emit an arbitrary list
+ pub fn emit_list<F>(self, list_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(&mut Encoder) -> Result<(), Error>,
+ {
+ *self.value_written = true;
+ self.encoder.emit_list(list_cb)
+ }
+
+ /// Emit a sorted dictionary. If the input dictionary is unsorted, this will return an error.
+ pub fn emit_dict<F>(self, content_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(SortedDictEncoder) -> Result<(), Error>,
+ {
+ *self.value_written = true;
+ self.encoder.emit_dict(content_cb)
+ }
+
+ /// Emit a dictionary that may have keys out of order. This will write the dict
+ /// values to temporary memory, then sort them before adding them to the serialized
+ /// stream
+ pub fn emit_unsorted_dict<F>(self, content_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(&mut UnsortedDictEncoder) -> Result<(), Error>,
+ {
+ *self.value_written = true;
+ self.encoder.emit_and_sort_dict(content_cb)
+ }
+
+ /// Emit an arbitrary list.
+ ///
+ /// Attention: If this method is used while canonical output is required
+ /// the caller needs to ensure that the iterator has a defined order.
+ pub fn emit_unchecked_list(
+ self,
+ iterable: impl Iterator<Item = impl ToBencode>,
+ ) -> Result<(), Error> {
+ self.emit_list(|e| {
+ for item in iterable {
+ e.emit(item)?;
+ }
+ Ok(())
+ })
+ }
+}
+
+/// Encodes a map with pre-sorted keys
+pub struct SortedDictEncoder<'a> {
+ encoder: &'a mut Encoder,
+}
+
+impl<'a> SortedDictEncoder<'a> {
+ /// Emit a key/value pair
+ pub fn emit_pair<E>(&mut self, key: &[u8], value: E) -> Result<(), Error>
+ where
+ E: ToBencode,
+ {
+ self.encoder.emit_token(Token::String(key))?;
+ self.encoder.emit(value)
+ }
+
+ /// Equivalent to [`SortedDictEncoder::emit_pair()`], but forces the type of the value
+ /// to be a callback
+ pub fn emit_pair_with<F>(&mut self, key: &[u8], value_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(SingleItemEncoder) -> Result<(), Error>,
+ {
+ self.encoder.emit_token(Token::String(key))?;
+ self.encoder.emit_with(value_cb)
+ }
+}
+
+/// Helper to write a dictionary that may have keys out of order. This will buffer the
+/// dict values in temporary memory, then sort them before adding them to the serialized
+/// stream
+pub struct UnsortedDictEncoder {
+ content: BTreeMap<Vec<u8>, Vec<u8>>,
+ error: Result<(), Error>,
+ remaining_depth: usize,
+}
+
+impl UnsortedDictEncoder {
+ pub(crate) fn new(remaining_depth: usize) -> Self {
+ Self {
+ content: BTreeMap::new(),
+ error: Ok(()),
+ remaining_depth,
+ }
+ }
+
+ /// Emit a key/value pair
+ pub fn emit_pair<E>(&mut self, key: &[u8], value: E) -> Result<(), Error>
+ where
+ E: ToBencode,
+ {
+ self.emit_pair_with(key, |e| value.encode(e))
+ }
+
+ /// Emit a key/value pair where the value is produced by a callback
+ pub fn emit_pair_with<F>(&mut self, key: &[u8], value_cb: F) -> Result<(), Error>
+ where
+ F: FnOnce(SingleItemEncoder) -> Result<(), Error>,
+ {
+ let mut value_written = false;
+
+ let mut encoder = Encoder::new().with_max_depth(self.remaining_depth);
+
+ let ret = value_cb(SingleItemEncoder {
+ encoder: &mut encoder,
+ value_written: &mut value_written,
+ });
+
+ if ret.is_err() {
+ self.error = ret.clone();
+ return ret;
+ }
+
+ if !value_written {
+ self.error = Err(Error::from(StructureError::InvalidState(
+ "No value was emitted".to_owned(),
+ )));
+ } else {
+ self.error = encoder.state.observe_eof().map_err(Error::from);
+ }
+
+ if self.error.is_err() {
+ return self.error.clone();
+ }
+
+ let encoded_object = encoder
+ .get_output()
+ .expect("Any errors should have been caught by observe_eof");
+
+ self.save_pair(key, encoded_object)
+ }
+
+ #[cfg(feature = "serde")]
+ pub(crate) fn remaining_depth(&self) -> usize {
+ self.remaining_depth
+ }
+
+ pub(crate) fn save_pair(
+ &mut self,
+ unencoded_key: &[u8],
+ encoded_value: Vec<u8>,
+ ) -> Result<(), Error> {
+ #[cfg(not(feature = "std"))]
+ use alloc::collections::btree_map::Entry;
+ #[cfg(feature = "std")]
+ use std::collections::btree_map::Entry;
+
+ if self.error.is_err() {
+ return self.error.clone();
+ }
+
+ let vacancy = match self.content.entry(unencoded_key.to_owned()) {
+ Entry::Vacant(vacancy) => vacancy,
+ Entry::Occupied(occupation) => {
+ self.error = Err(Error::from(StructureError::InvalidState(format!(
+ "Duplicate key {}",
+ String::from_utf8_lossy(occupation.key())
+ ))));
+ return self.error.clone();
+ },
+ };
+
+ vacancy.insert(encoded_value);
+
+ Ok(())
+ }
+
+ pub(crate) fn done(self) -> Result<BTreeMap<Vec<u8>, Vec<u8>>, Error> {
+ self.error?;
+ Ok(self.content)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ pub fn simple_encoding_works() {
+ let mut encoder = Encoder::new();
+ encoder
+ .emit_dict(|mut e| {
+ e.emit_pair(b"bar", 25)?;
+ e.emit_pair_with(b"foo", |e| {
+ e.emit_list(|e| {
+ e.emit_str("baz")?;
+ e.emit_str("qux")
+ })
+ })
+ })
+ .expect("Encoding shouldn't fail");
+ assert_eq!(
+ &encoder
+ .get_output()
+ .expect("Complete object should have been written"),
+ &b"d3:bari25e3:fool3:baz3:quxee"
+ );
+ }
+
+ #[test]
+ fn emit_cb_must_emit() {
+ let mut encoder = Encoder::new();
+ assert!(encoder.emit_with(|_| Ok(())).is_err());
+ }
+}
diff --git a/rust/vendor/bendy/src/encoding/error.rs b/rust/vendor/bendy/src/encoding/error.rs
new file mode 100644
index 0000000..cc651d8
--- /dev/null
+++ b/rust/vendor/bendy/src/encoding/error.rs
@@ -0,0 +1,56 @@
+#[cfg(feature = "std")]
+use std::sync::Arc;
+
+use failure::Fail;
+
+use crate::state_tracker::StructureError;
+
+#[derive(Debug, Clone, Fail)]
+#[fail(display = "encoding failed: {}", _0)]
+pub struct Error(#[fail(cause)] pub ErrorKind);
+
+/// An enumeration of potential errors that appear during bencode encoding.
+#[derive(Debug, Clone, Fail)]
+pub enum ErrorKind {
+ /// Error that occurs if the serialized structure contains invalid semantics.
+ #[cfg(feature = "std")]
+ #[fail(display = "malformed content discovered: {}", _0)]
+ MalformedContent(Arc<failure::Error>),
+ /// Error that occurs if the serialized structure contains invalid semantics.
+ #[cfg(not(feature = "std"))]
+ #[fail(display = "malformed content discovered")]
+ MalformedContent,
+ /// Error in the bencode structure (e.g. a missing field end separator).
+ #[fail(display = "bencode encoding corrupted")]
+ StructureError(#[fail(cause)] StructureError),
+}
+
+impl Error {
+ /// Raised when there is a general error while deserializing a type.
+ /// The message should not be capitalized and should not end with a period.
+ ///
+ /// Note that, when building with no_std, this method accepts any type as
+ /// its argument.
+ #[cfg(feature = "std")]
+ pub fn malformed_content(cause: impl Into<failure::Error>) -> Error {
+ let error = Arc::new(cause.into());
+ Self(ErrorKind::MalformedContent(error))
+ }
+
+ #[cfg(not(feature = "std"))]
+ pub fn malformed_content<T>(_cause: T) -> Error {
+ Self(ErrorKind::MalformedContent)
+ }
+}
+
+impl From<StructureError> for Error {
+ fn from(error: StructureError) -> Self {
+ Self(ErrorKind::StructureError(error))
+ }
+}
+
+impl From<ErrorKind> for Error {
+ fn from(kind: ErrorKind) -> Self {
+ Self(kind)
+ }
+}
diff --git a/rust/vendor/bendy/src/encoding/printable_integer.rs b/rust/vendor/bendy/src/encoding/printable_integer.rs
new file mode 100644
index 0000000..8140dca
--- /dev/null
+++ b/rust/vendor/bendy/src/encoding/printable_integer.rs
@@ -0,0 +1,15 @@
+#[cfg(not(feature = "std"))]
+use core::fmt::Display;
+#[cfg(feature = "std")]
+use std::fmt::Display;
+
+/// A value that can be formatted as a decimal integer
+pub trait PrintableInteger: Display {}
+
+macro_rules! impl_integer {
+ ($($type:ty)*) => {$(
+ impl PrintableInteger for $type {}
+ )*}
+}
+
+impl_integer!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
diff --git a/rust/vendor/bendy/src/encoding/to_bencode.rs b/rust/vendor/bendy/src/encoding/to_bencode.rs
new file mode 100644
index 0000000..a19dcb3
--- /dev/null
+++ b/rust/vendor/bendy/src/encoding/to_bencode.rs
@@ -0,0 +1,265 @@
+#[cfg(not(feature = "std"))]
+use alloc::{
+ collections::{BTreeMap, LinkedList, VecDeque},
+ rc::Rc,
+ string::String,
+ sync::Arc,
+ vec::Vec,
+};
+
+#[cfg(feature = "std")]
+use std::{
+ collections::{BTreeMap, HashMap, LinkedList, VecDeque},
+ hash::{BuildHasher, Hash},
+ rc::Rc,
+ sync::Arc,
+};
+
+use crate::encoding::{Encoder, Error, SingleItemEncoder};
+
+/// An object that can be encoded into a single bencode object
+pub trait ToBencode {
+ /// The maximum depth that this object could encode to. Leaves do not consume a level, so an
+ /// `i1e` has depth 0 and `li1ee` has depth 1.
+ const MAX_DEPTH: usize;
+
+ /// Encode this object into the bencode stream
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error>;
+
+ /// Encode this object to a byte string
+ fn to_bencode(&self) -> Result<Vec<u8>, Error> {
+ let mut encoder = Encoder::new().with_max_depth(Self::MAX_DEPTH);
+ encoder.emit_with(|e| self.encode(e).map_err(Error::into))?;
+
+ let bytes = encoder.get_output()?;
+ Ok(bytes)
+ }
+}
+
+/// Wrapper to allow `Vec<u8>` encoding as bencode string element.
+#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)]
+pub struct AsString<I>(pub I);
+
+// Forwarding impls
+impl<'a, E: 'a + ToBencode + Sized> ToBencode for &'a E {
+ const MAX_DEPTH: usize = E::MAX_DEPTH;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ E::encode(self, encoder)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<E: ToBencode> ToBencode for Box<E> {
+ const MAX_DEPTH: usize = E::MAX_DEPTH;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ E::encode(&*self, encoder)
+ }
+}
+
+impl<E: ToBencode> ToBencode for Rc<E> {
+ const MAX_DEPTH: usize = E::MAX_DEPTH;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ E::encode(&*self, encoder)
+ }
+}
+
+impl<E: ToBencode> ToBencode for Arc<E> {
+ const MAX_DEPTH: usize = E::MAX_DEPTH;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ E::encode(&*self, encoder)
+ }
+}
+
+// Base type impls
+impl<'a> ToBencode for &'a str {
+ const MAX_DEPTH: usize = 0;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_str(self).map_err(Error::from)
+ }
+}
+
+impl ToBencode for String {
+ const MAX_DEPTH: usize = 0;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_str(self).map_err(Error::from)
+ }
+}
+
+macro_rules! impl_encodable_integer {
+ ($($type:ty)*) => {$(
+ impl ToBencode for $type {
+ const MAX_DEPTH: usize = 1;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_int(*self).map_err(Error::from)
+ }
+ }
+ )*}
+}
+
+impl_encodable_integer!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
+
+macro_rules! impl_encodable_iterable {
+ ($($type:ident)*) => {$(
+ impl <ContentT> ToBencode for $type<ContentT>
+ where
+ ContentT: ToBencode
+ {
+ const MAX_DEPTH: usize = ContentT::MAX_DEPTH + 1;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_list(|e| {
+ for item in self {
+ e.emit(item)?;
+ }
+ Ok(())
+ })?;
+
+ Ok(())
+ }
+ }
+ )*}
+}
+
+impl_encodable_iterable!(Vec VecDeque LinkedList);
+
+impl<'a, ContentT> ToBencode for &'a [ContentT]
+where
+ ContentT: ToBencode,
+{
+ const MAX_DEPTH: usize = ContentT::MAX_DEPTH + 1;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_list(|e| {
+ for item in *self {
+ e.emit(item)?;
+ }
+ Ok(())
+ })?;
+
+ Ok(())
+ }
+}
+
+impl<K: AsRef<[u8]>, V: ToBencode> ToBencode for BTreeMap<K, V> {
+ const MAX_DEPTH: usize = V::MAX_DEPTH + 1;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_dict(|mut e| {
+ for (k, v) in self {
+ e.emit_pair(k.as_ref(), v)?;
+ }
+ Ok(())
+ })?;
+
+ Ok(())
+ }
+}
+
+#[cfg(feature = "std")]
+impl<K, V, S> ToBencode for HashMap<K, V, S>
+where
+ K: AsRef<[u8]> + Eq + Hash,
+ V: ToBencode,
+ S: BuildHasher,
+{
+ const MAX_DEPTH: usize = V::MAX_DEPTH + 1;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_dict(|mut e| {
+ let mut pairs = self
+ .iter()
+ .map(|(k, v)| (k.as_ref(), v))
+ .collect::<Vec<_>>();
+ pairs.sort_by_key(|&(k, _)| k);
+ for (k, v) in pairs {
+ e.emit_pair(k, v)?;
+ }
+ Ok(())
+ })?;
+
+ Ok(())
+ }
+}
+
+impl<I> ToBencode for AsString<I>
+where
+ I: AsRef<[u8]>,
+{
+ const MAX_DEPTH: usize = 1;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_bytes(self.0.as_ref())?;
+ Ok(())
+ }
+}
+
+impl<I> AsRef<[u8]> for AsString<I>
+where
+ I: AsRef<[u8]>,
+{
+ fn as_ref(&self) -> &'_ [u8] {
+ self.0.as_ref()
+ }
+}
+
+impl<'a, I> From<&'a [u8]> for AsString<I>
+where
+ I: From<&'a [u8]>,
+{
+ fn from(content: &'a [u8]) -> Self {
+ AsString(I::from(content))
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ #[cfg(not(feature = "std"))]
+ use alloc::{borrow::ToOwned, vec};
+
+ use super::*;
+
+ struct Foo {
+ bar: u32,
+ baz: Vec<String>,
+ qux: Vec<u8>,
+ }
+
+ impl ToBencode for Foo {
+ const MAX_DEPTH: usize = 2;
+
+ fn encode(&self, encoder: SingleItemEncoder) -> Result<(), Error> {
+ encoder.emit_dict(|mut e| {
+ e.emit_pair(b"bar", &self.bar)?;
+ e.emit_pair(b"baz", &self.baz)?;
+ e.emit_pair(b"qux", AsString(&self.qux))?;
+ Ok(())
+ })?;
+
+ Ok(())
+ }
+ }
+
+ #[test]
+ fn simple_encodable_works() {
+ let mut encoder = Encoder::new();
+ encoder
+ .emit(Foo {
+ bar: 5,
+ baz: vec!["foo".to_owned(), "bar".to_owned()],
+ qux: b"qux".to_vec(),
+ })
+ .unwrap();
+ assert_eq!(
+ &encoder.get_output().unwrap()[..],
+ &b"d3:bari5e3:bazl3:foo3:bare3:qux3:quxe"[..]
+ );
+ }
+}