rustybit-serde-bencode 1.0.0

A bencode serializing/deserializing library powered by Serde
Documentation
use std::borrow::Cow;
use std::collections::HashMap;
use std::marker::PhantomData;

use serde::{Deserialize, Deserializer, Serialize};

#[derive(Debug, Deserialize, PartialEq, Eq, Hash)]
pub struct Bytes<'a>(Cow<'a, [u8]>);

impl<'a> Serialize for Bytes<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_bytes(&self.0)
    }
}

#[derive(Debug, Serialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum BencodeValue<'a> {
    Int(i64),
    Bytes(Bytes<'a>),
    List(Vec<BencodeValue<'a>>),
    Dict(HashMap<Bytes<'a>, BencodeValue<'a>>),
}

impl<'a, 'de: 'a> serde::de::Deserialize<'de> for BencodeValue<'a> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct Visitor<'a> {
            lifetime: PhantomData<BencodeValue<'a>>,
        }

        impl<'a, 'de: 'a> serde::de::Visitor<'de> for Visitor<'a> {
            type Value = BencodeValue<'a>;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(formatter, "a valid bencode value")
            }

            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(v.into())
            }

            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: serde::de::SeqAccess<'de>,
            {
                let mut v: Vec<BencodeValue<'a>> = Vec::new();
                while let Some(value) = seq.next_element()? {
                    v.push(value);
                }
                Ok(v.into())
            }

            fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(v.into())
            }

            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: serde::de::MapAccess<'de>,
            {
                let mut hashmap = HashMap::new();
                while let Some(key) = map.next_key::<&'de [u8]>()? {
                    let value = map.next_value()?;
                    hashmap.insert(Bytes(Cow::Borrowed(key)), value);
                }
                Ok(hashmap.into())
            }
        }

        deserializer.deserialize_any(Visitor { lifetime: PhantomData })
    }
}

impl From<i64> for BencodeValue<'_> {
    fn from(value: i64) -> Self {
        BencodeValue::Int(value)
    }
}

impl<'a> From<&'a [u8]> for BencodeValue<'a> {
    fn from(value: &'a [u8]) -> Self {
        BencodeValue::Bytes(Bytes(Cow::Borrowed(value)))
    }
}

impl From<String> for BencodeValue<'_> {
    fn from(s: String) -> Self {
        BencodeValue::Bytes(Bytes(Cow::Owned(s.into_bytes())))
    }
}

impl<'a> From<&'a str> for BencodeValue<'a> {
    fn from(v: &'a str) -> Self {
        BencodeValue::Bytes(Bytes(Cow::Borrowed(v.as_bytes())))
    }
}

impl From<Vec<u8>> for BencodeValue<'_> {
    fn from(value: Vec<u8>) -> Self {
        BencodeValue::Bytes(Bytes(Cow::Owned(value)))
    }
}

impl<'a> From<Vec<BencodeValue<'a>>> for BencodeValue<'a> {
    fn from(value: Vec<BencodeValue<'a>>) -> Self {
        BencodeValue::List(value)
    }
}

impl<'a> From<HashMap<Bytes<'a>, BencodeValue<'a>>> for BencodeValue<'a> {
    fn from(value: HashMap<Bytes<'a>, BencodeValue<'a>>) -> Self {
        BencodeValue::Dict(value)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{from_str, to_string};

    mod basic_types {
        use super::*;

        #[test]
        fn can_roundtrip_int() {
            let value: BencodeValue = 888i64.into();
            let serialized = to_string(&value).expect("failed to serialize an integer");
            assert_eq!(serialized, "i888e");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize an integer");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_negative_int() {
            let value: BencodeValue = (-888i64).into();
            let serialized = to_string(&value).expect("failed to serialize a neg integer");
            assert_eq!(serialized, "i-888e");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a neg integer");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_bytes() {
            let value: BencodeValue = "a nice value".into();
            let serialized = to_string(&value).expect("failed to serialize a string");
            assert_eq!(serialized, "12:a nice value");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a string");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_list_of_bytes() {
            let list: Vec<BencodeValue> = vec!["a nice value".into(), "another".into()];
            let value: BencodeValue = list.into();
            let serialized = to_string(&value).expect("failed to serialize a list of bytes");
            assert_eq!(serialized, "l12:a nice value7:anothere");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a list of bytes");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_list_of_ints() {
            let list: Vec<BencodeValue> = vec![10i64.into(), 11i64.into()];
            let value: BencodeValue = list.into();
            let serialized = to_string(&value).expect("failed to serialize a list of ints");
            assert_eq!(serialized, "li10ei11ee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a list of ints");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_list_of_lists() {
            let list: Vec<BencodeValue> = vec![
                BencodeValue::List(vec!["bytes".into()]),
                BencodeValue::List(vec![20i64.into()]),
            ];
            let value: BencodeValue = list.into();
            let serialized = to_string(&value).expect("failed to serialize a list of lists");
            assert_eq!(serialized, "ll5:byteseli20eee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a list of lists");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_list_of_dicts() {
            let dict_1 = HashMap::from([(Bytes(b"test".into()), BencodeValue::List(vec![21i64.into()]))]);
            let dict_2 = HashMap::from([(Bytes(b"another".into()), BencodeValue::Dict(HashMap::new()))]);

            let list: Vec<BencodeValue> = vec![dict_1.into(), dict_2.into()];
            let value: BencodeValue = list.into();
            let serialized = to_string(&value).expect("failed to serialize a list of dicts");
            assert_eq!(serialized, "ld4:testli21eeed7:anotherdeee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a list of dicts");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_dict_of_ints() {
            let dict: HashMap<Bytes, BencodeValue> = HashMap::from([(Bytes(b"key1".into()), 4i64.into())]);
            let value: BencodeValue = dict.into();
            let serialized = to_string(&value).expect("failed to serialize a dict of ints");
            assert_eq!(serialized, "d4:key1i4ee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a dict of ints");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_dict_of_bytes() {
            let dict: HashMap<Bytes, BencodeValue> = HashMap::from([(Bytes(b"key1".into()), "my value".into())]);
            let value: BencodeValue = dict.into();
            let serialized = to_string(&value).expect("failed to serialize a dict of bytes");
            assert_eq!(serialized, "d4:key18:my valuee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a dict of bytes");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_dict_of_lists() {
            let dict: HashMap<Bytes, BencodeValue> =
                HashMap::from([(Bytes(b"key1".into()), vec![BencodeValue::Dict(HashMap::new())].into())]);
            let value: BencodeValue = dict.into();
            let serialized = to_string(&value).expect("failed to serialize a dict of lists");
            assert_eq!(serialized, "d4:key1ldeee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a dict of lists");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_dict_of_dicts() {
            let dict: HashMap<Bytes, BencodeValue> = HashMap::from([(
                Bytes(b"key1".into()),
                HashMap::from([(Bytes(b"inner".into()), BencodeValue::Dict(HashMap::new()))]).into(),
            )]);
            let value: BencodeValue = dict.into();
            let serialized = to_string(&value).expect("failed to serialize a dict of dicts");
            assert_eq!(serialized, "d4:key1d5:innerdeee");
            let deserialized = from_str::<BencodeValue>(&serialized).expect("failed to deserialize a dict of dicts");
            assert_eq!(deserialized, value)
        }
    }

    mod option {
        use super::*;

        #[test]
        fn can_roundtrip_some() {
            let value: Option<i64> = Some(10);
            let serialized = to_string(&value).expect("failed to serialize an Option::Some");
            assert_eq!(serialized, "i10e");
            let deserialized = from_str::<Option<i64>>(&serialized).expect("failed to deserialize an Option::Some");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_none() {
            let value: Option<i64> = None;
            let serialized = to_string(&value).expect("failed to serialize an Option::None");
            assert_eq!(serialized, "0:");
            let deserialized = from_str::<Option<i64>>(&serialized).expect("failed to deserialize an Option::None");
            assert_eq!(deserialized, value)
        }
    }

    mod unit {
        use super::*;

        #[test]
        fn can_roundtrip_unit() {
            let value = ();
            let serialized = to_string(&value).expect("failed to serialize the unit type");
            assert_eq!(serialized, "0:");
            let deserialized = from_str::<()>(&serialized).expect("failed to deserialize the unit type");
            assert_eq!(deserialized, value)
        }
    }

    mod _struct {
        use super::*;

        #[test]
        fn can_roundtrip_unit_struct() {
            #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
            struct Test;

            let value = Test;
            let serialized = to_string(&value).expect("failed to serialize a unit struct");
            assert_eq!(serialized, "0:");
            let deserialized = from_str::<Test>(&serialized).expect("failed to deserialize a unit struct");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_newtype_struct() {
            #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
            struct Test(i64);

            let value = Test(11);
            let serialized = to_string(&value).expect("failed to serialize a newtype struct");
            assert_eq!(serialized, "i11e");
            let deserialized = from_str::<Test>(&serialized).expect("failed to deserialize a newtype struct");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_tuple_struct() {
            #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
            struct Test<'a>(i64, i64, &'a str);

            let value = Test(10, 11, "hey!");
            let serialized = to_string(&value).expect("failed to serialize a tuple struct");
            assert_eq!(serialized, "li10ei11e4:hey!e");
            let deserialized = from_str::<Test>(&serialized).expect("failed to deserialize a tuple struct");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_struct() {
            #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
            struct Test<'a> {
                field_1: &'a str,
                field_2: i64,
            }

            let value = Test {
                field_1: "test",
                field_2: 555,
            };
            let serialized = to_string(&value).expect("failed to serialize a struct");
            assert_eq!(serialized, "d7:field_14:test7:field_2i555ee");
            let deserialized = from_str::<Test>(&serialized).expect("failed to deserialize a struct");
            assert_eq!(deserialized, value)
        }
    }

    mod _enum {
        use super::*;

        #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
        enum Enumeration<'a> {
            Unit,
            NewType(i64),
            Tuple(i64, i64, &'a str),
            Struct { field: &'a str, integer: i64 },
        }

        #[test]
        fn can_roundtrip_unit_variant() {
            let value = Enumeration::Unit;
            let serialized = to_string(&value).expect("failed to serialize a unit variant");
            assert_eq!(serialized, "d4:Unit0:e");
            let deserialized = from_str::<Enumeration>(&serialized).expect("failed to deserialize a unit variant");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_newtype_variant() {
            let value = Enumeration::NewType(15);
            let serialized = to_string(&value).expect("failed to serialize a newtype variant");
            assert_eq!(serialized, "d7:NewTypei15ee");
            let deserialized = from_str::<Enumeration>(&serialized).expect("failed to deserialize a newtype variant");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_tuple_variant() {
            let value = Enumeration::Tuple(10, 12, "hi from enum");
            let serialized = to_string(&value).expect("failed to serialize a tuple variant");
            assert_eq!(serialized, "d5:Tupleli10ei12e12:hi from enumee");
            let deserialized = from_str::<Enumeration>(&serialized).expect("failed to deserialize a tuple variant");
            assert_eq!(deserialized, value)
        }

        #[test]
        fn can_roundtrip_struct_variant() {
            let value = Enumeration::Struct {
                field: "hi from enum",
                integer: 22,
            };
            let serialized = to_string(&value).expect("failed to serialize a struct variant");
            assert_eq!(serialized, "d6:Structd5:field12:hi from enum7:integeri22eee");
            let deserialized = from_str::<Enumeration>(&serialized).expect("failed to deserialize a struct variant");
            assert_eq!(deserialized, value)
        }
    }
}