bde/value/
mod.rs

1use serde::{de::DeserializeOwned, Serialize};
2use std::{collections::BTreeMap, fmt::Debug};
3
4use crate::{byte_string::ByteString, Error};
5
6mod de;
7mod integer;
8mod ser;
9
10pub use integer::Integer;
11pub use ser::ValueSerializer;
12
13pub type Dictionary<V = Value> = BTreeMap<ByteString, V>;
14
15/// Represents any valid Bencode value.
16#[derive(PartialEq, Eq, PartialOrd, Ord)]
17pub enum Value {
18    /// Represents a bencode byte string.
19    ByteString(ByteString),
20    /// Represents a bencode integer.
21    Integer(Integer),
22    /// Represents a bencode list.
23    List(Vec<Value>),
24    /// Represents a bencode dictionary.
25    Dictionary(Dictionary),
26}
27
28impl Debug for Value {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        match self {
31            Self::ByteString(value) => f
32                .debug_tuple("ByteString")
33                .field(&String::from_utf8_lossy(value))
34                .finish(),
35            Self::Integer(value) => Debug::fmt(value, f),
36            Self::List(value) => {
37                f.write_str("List(")?;
38                Debug::fmt(value, f)?;
39                f.write_str(")")
40            }
41            Self::Dictionary(value) => {
42                f.write_str("Dictionary(")?;
43                Debug::fmt(value, f)?;
44                f.write_str(")")
45            }
46        }
47    }
48}
49
50impl Value {
51    pub const fn is_byte_string(&self) -> bool {
52        matches!(self, Self::ByteString(_))
53    }
54
55    pub const fn is_integer(&self) -> bool {
56        matches!(self, Self::Integer(_))
57    }
58
59    pub const fn is_list(&self) -> bool {
60        matches!(self, Self::Integer(_))
61    }
62
63    pub const fn is_dictionary(&self) -> bool {
64        matches!(self, Self::Dictionary(_))
65    }
66
67    pub const fn as_byte_string(&self) -> Option<&ByteString> {
68        match self {
69            Self::ByteString(byte_string) => Some(byte_string),
70            _ => None,
71        }
72    }
73
74    pub const fn as_integer(&self) -> Option<&Integer> {
75        match self {
76            Self::Integer(integer) => Some(integer),
77            _ => None,
78        }
79    }
80
81    pub const fn as_list(&self) -> Option<&Vec<Value>> {
82        match self {
83            Self::List(list) => Some(list),
84            _ => None,
85        }
86    }
87
88    pub const fn as_dictionary(&self) -> Option<&Dictionary> {
89        match self {
90            Self::Dictionary(dictionary) => Some(dictionary),
91            _ => None,
92        }
93    }
94}
95
96pub fn to_value<T>(value: T) -> Result<Value, Error>
97where
98    T: Serialize,
99{
100    value.serialize(ValueSerializer)
101}
102
103pub fn from_value<T>(value: Value) -> Result<T, Error>
104where
105    T: DeserializeOwned,
106{
107    T::deserialize(value)
108}
109
110#[cfg(test)]
111mod tests {
112    use super::{ByteString, Integer, Value};
113    use serde_test::{assert_tokens, Token};
114    use std::collections::BTreeMap;
115
116    #[test]
117    fn deserialize_and_serialize_dictionary() {
118        let mut map = BTreeMap::new();
119        map.insert(ByteString::from("a"), Value::Integer(Integer::from(10u64)));
120        map.insert(ByteString::from("c"), Value::Integer(Integer::from(10u64)));
121        map.insert(ByteString::from("d"), Value::Integer(Integer::from(10u64)));
122        map.insert(ByteString::from("b"), Value::Integer(Integer::from(10u64)));
123        map.insert(ByteString::from("e"), Value::Integer(Integer::from(10u64)));
124
125        let len = map.len();
126
127        assert_tokens(
128            &Value::Dictionary(map),
129            &[
130                Token::Map { len: Some(len) },
131                Token::Bytes(b"a"),
132                Token::U64(10),
133                Token::Bytes(b"b"),
134                Token::U64(10),
135                Token::Bytes(b"c"),
136                Token::U64(10),
137                Token::Bytes(b"d"),
138                Token::U64(10),
139                Token::Bytes(b"e"),
140                Token::U64(10),
141                Token::MapEnd,
142            ],
143        )
144    }
145}