use std::borrow::Cow;
use std::collections::BTreeMap;
use std::str;
use crate::access::bencode::{BMutAccess, BRefAccess, MutKind, RefKind};
use crate::access::dict::BDictAccess;
use crate::access::list::BListAccess;
use crate::mutable::encode;
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum Inner<'a> {
Int(i64),
Bytes(Cow<'a, [u8]>),
List(Vec<BencodeMut<'a>>),
Dict(BTreeMap<Cow<'a, [u8]>, BencodeMut<'a>>),
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct BencodeMut<'a> {
inner: Inner<'a>,
}
impl<'a> BencodeMut<'a> {
fn new(inner: Inner<'a>) -> BencodeMut<'a> {
BencodeMut { inner }
}
#[must_use]
pub fn new_int(value: i64) -> BencodeMut<'a> {
BencodeMut::new(Inner::Int(value))
}
#[must_use]
pub fn new_bytes(value: Cow<'a, [u8]>) -> BencodeMut<'a> {
BencodeMut::new(Inner::Bytes(value))
}
#[must_use]
pub fn new_list() -> BencodeMut<'a> {
BencodeMut::new(Inner::List(Vec::new()))
}
#[must_use]
pub fn new_dict() -> BencodeMut<'a> {
BencodeMut::new(Inner::Dict(BTreeMap::new()))
}
#[must_use]
pub fn encode(&self) -> Vec<u8> {
let mut buffer = Vec::new();
encode::encode(self, &mut buffer);
buffer
}
}
impl<'a> BRefAccess for BencodeMut<'a> {
type BKey = Cow<'a, [u8]>;
type BType = BencodeMut<'a>;
fn kind<'b>(&'b self) -> RefKind<'b, Cow<'a, [u8]>, BencodeMut<'a>> {
match self.inner {
Inner::Int(n) => RefKind::Int(n),
Inner::Bytes(ref n) => RefKind::Bytes(n),
Inner::List(ref n) => RefKind::List(n),
Inner::Dict(ref n) => RefKind::Dict(n),
}
}
fn str(&self) -> Option<&str> {
let bytes = self.bytes()?;
match str::from_utf8(bytes) {
Ok(n) => Some(n),
Err(_) => None,
}
}
fn int(&self) -> Option<i64> {
match self.inner {
Inner::Int(n) => Some(n),
_ => None,
}
}
fn bytes(&self) -> Option<&[u8]> {
match self.inner {
Inner::Bytes(ref n) => Some(n.as_ref()),
_ => None,
}
}
fn list(&self) -> Option<&dyn BListAccess<BencodeMut<'a>>> {
match self.inner {
Inner::List(ref n) => Some(n),
_ => None,
}
}
fn dict(&self) -> Option<&dyn BDictAccess<Cow<'a, [u8]>, BencodeMut<'a>>> {
match self.inner {
Inner::Dict(ref n) => Some(n),
_ => None,
}
}
}
impl<'a> BMutAccess for BencodeMut<'a> {
fn kind_mut<'b>(&'b mut self) -> MutKind<'b, Cow<'a, [u8]>, BencodeMut<'a>> {
match self.inner {
Inner::Int(n) => MutKind::Int(n),
Inner::Bytes(ref mut n) => MutKind::Bytes((*n).as_ref()),
Inner::List(ref mut n) => MutKind::List(n),
Inner::Dict(ref mut n) => MutKind::Dict(n),
}
}
fn list_mut(&mut self) -> Option<&mut dyn BListAccess<BencodeMut<'a>>> {
match self.inner {
Inner::List(ref mut n) => Some(n),
_ => None,
}
}
fn dict_mut(&mut self) -> Option<&mut dyn BDictAccess<Cow<'a, [u8]>, BencodeMut<'a>>> {
match self.inner {
Inner::Dict(ref mut n) => Some(n),
_ => None,
}
}
}
#[cfg(test)]
mod test {
use crate::access::bencode::BMutAccess;
use crate::mutable::bencode_mut::BencodeMut;
#[test]
fn positive_int_encode() {
let bencode_int = BencodeMut::new_int(-560);
let int_bytes = b"i-560e"; assert_eq!(&int_bytes[..], &bencode_int.encode()[..]);
}
#[test]
fn positive_bytes_encode() {
let bencode_bytes = BencodeMut::new_bytes((&b"asdasd"[..]).into());
let bytes_bytes = b"6:asdasd"; assert_eq!(&bytes_bytes[..], &bencode_bytes.encode()[..]);
}
#[test]
fn positive_empty_list_encode() {
let bencode_list = BencodeMut::new_list();
let list_bytes = b"le"; assert_eq!(&list_bytes[..], &bencode_list.encode()[..]);
}
#[test]
fn positive_nonempty_list_encode() {
let mut bencode_list = BencodeMut::new_list();
{
let list_mut = bencode_list.list_mut().unwrap();
list_mut.push(BencodeMut::new_int(56));
}
let list_bytes = b"li56ee"; assert_eq!(&list_bytes[..], &bencode_list.encode()[..]);
}
#[test]
fn positive_empty_dict_encode() {
let bencode_dict = BencodeMut::new_dict();
let dict_bytes = b"de"; assert_eq!(&dict_bytes[..], &bencode_dict.encode()[..]);
}
#[test]
fn positive_nonempty_dict_encode() {
let mut bencode_dict = BencodeMut::new_dict();
{
let dict_mut = bencode_dict.dict_mut().unwrap();
dict_mut.insert((&b"asd"[..]).into(), BencodeMut::new_bytes((&b"asdasd"[..]).into()));
}
let dict_bytes = b"d3:asd6:asdasde"; assert_eq!(&dict_bytes[..], &bencode_dict.encode()[..]);
}
}