#[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},
};
#[derive(Default, Debug)]
pub struct Encoder {
state: StateTracker<Vec<u8>, Error>,
output: Vec<u8>,
}
impl Encoder {
pub fn new() -> Self {
<Self as Default>::default()
}
#[must_use]
pub fn with_max_depth(mut self, max_depth: usize) -> Self {
self.state.set_max_depth(max_depth);
self
}
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) => {
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) => {
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(())
}
pub fn emit<E: ToBencode>(&mut self, value: E) -> Result<(), Error> {
self.emit_with(|e| value.encode(e))
}
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(())
}
pub fn emit_int<T: PrintableInteger>(&mut self, value: T) -> Result<(), Error> {
self.state.check_error()?;
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(())
}
pub fn emit_str(&mut self, value: &str) -> Result<(), Error> {
self.emit_token(Token::String(value.as_bytes()))
}
pub fn emit_bytes(&mut self, value: &[u8]) -> Result<(), Error> {
self.emit_token(Token::String(value))
}
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)
}
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)
}
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)
}
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> {
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)?;
self.state.observe_token(&Token::Num(""))?;
self.output.extend_from_slice(&v);
}
self.emit_token(Token::End)?;
Ok(())
}
}
pub struct SingleItemEncoder<'a> {
encoder: &'a mut Encoder,
value_written: &'a mut bool,
}
impl<'a> SingleItemEncoder<'a> {
pub fn emit<E: ToBencode + ?Sized>(self, value: &E) -> Result<(), Error> {
value.encode(self)
}
pub fn emit_with<F>(self, value_cb: F) -> Result<(), Error>
where
F: FnOnce(SingleItemEncoder) -> Result<(), Error>,
{
value_cb(self)
}
pub fn emit_int<T: PrintableInteger>(self, value: T) -> Result<(), Error> {
*self.value_written = true;
self.encoder.emit_int(value)
}
pub fn emit_str(self, value: &str) -> Result<(), Error> {
*self.value_written = true;
self.encoder.emit_str(value)
}
pub fn emit_bytes(self, value: &[u8]) -> Result<(), Error> {
*self.value_written = true;
self.encoder.emit_bytes(value)
}
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)
}
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)
}
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)
}
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(())
})
}
}
pub struct SortedDictEncoder<'a> {
encoder: &'a mut Encoder,
}
impl<'a> SortedDictEncoder<'a> {
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)
}
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)
}
}
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,
}
}
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))
}
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 {
state: "No value was emitted".to_owned(),
}));
} else {
self.error = encoder.state.observe_eof();
}
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 {
state: 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());
}
}