Skip to main content

irontide_bencode/
value.rs

1#![allow(
2    clippy::cast_possible_wrap,
3    reason = "M175: BencodeValue `u64 → i64` — bencode integers are i64 by spec"
4)]
5
6use std::collections::BTreeMap;
7use std::fmt;
8
9/// A dynamically-typed bencode value.
10///
11/// Useful for inspecting bencode data without a schema, and for
12/// `find_dict_key_span` operations.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum BencodeValue {
15    /// Integer: `i42e`
16    Integer(i64),
17    /// Byte string: `4:spam`
18    Bytes(Vec<u8>),
19    /// List: `l...e`
20    List(Vec<Self>),
21    /// Dictionary: `d...e` (keys sorted lexicographically)
22    Dict(BTreeMap<Vec<u8>, Self>),
23}
24
25impl BencodeValue {
26    /// Returns the integer value if this is a `BencodeValue::Integer`.
27    #[must_use]
28    pub fn as_int(&self) -> Option<i64> {
29        match self {
30            Self::Integer(n) => Some(*n),
31            _ => None,
32        }
33    }
34
35    /// Returns the raw byte slice if this is a `BencodeValue::Bytes`.
36    #[must_use]
37    pub fn as_bytes_raw(&self) -> Option<&[u8]> {
38        match self {
39            Self::Bytes(b) => Some(b),
40            _ => None,
41        }
42    }
43
44    /// Returns the list if this is a `BencodeValue::List`.
45    #[must_use]
46    pub fn as_list(&self) -> Option<&[Self]> {
47        match self {
48            Self::List(items) => Some(items),
49            _ => None,
50        }
51    }
52
53    /// Returns the dictionary if this is a `BencodeValue::Dict`.
54    #[must_use]
55    pub fn as_dict(&self) -> Option<&BTreeMap<Vec<u8>, Self>> {
56        match self {
57            Self::Dict(map) => Some(map),
58            _ => None,
59        }
60    }
61}
62
63impl fmt::Display for BencodeValue {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        match self {
66            Self::Integer(n) => write!(f, "{n}"),
67            Self::Bytes(b) => match std::str::from_utf8(b) {
68                Ok(s) => write!(f, "\"{s}\""),
69                Err(_) => write!(f, "<{} bytes>", b.len()),
70            },
71            Self::List(items) => {
72                write!(f, "[")?;
73                for (i, item) in items.iter().enumerate() {
74                    if i > 0 {
75                        write!(f, ", ")?;
76                    }
77                    write!(f, "{item}")?;
78                }
79                write!(f, "]")
80            }
81            Self::Dict(map) => {
82                write!(f, "{{")?;
83                for (i, (key, val)) in map.iter().enumerate() {
84                    if i > 0 {
85                        write!(f, ", ")?;
86                    }
87                    match std::str::from_utf8(key) {
88                        Ok(s) => write!(f, "\"{s}\": {val}")?,
89                        Err(_) => write!(f, "<{} bytes>: {val}", key.len())?,
90                    }
91                }
92                write!(f, "}}")
93            }
94        }
95    }
96}
97
98impl serde::Serialize for BencodeValue {
99    fn serialize<S: serde::Serializer>(
100        &self,
101        serializer: S,
102    ) -> std::result::Result<S::Ok, S::Error> {
103        match self {
104            Self::Integer(n) => serializer.serialize_i64(*n),
105            Self::Bytes(b) => serializer.serialize_bytes(b),
106            Self::List(items) => {
107                use serde::ser::SerializeSeq;
108                let mut seq = serializer.serialize_seq(Some(items.len()))?;
109                for item in items {
110                    seq.serialize_element(item)?;
111                }
112                seq.end()
113            }
114            Self::Dict(map) => {
115                use serde::ser::SerializeMap;
116                let mut m = serializer.serialize_map(Some(map.len()))?;
117                for (key, val) in map {
118                    m.serialize_entry(&serde_bytes::Bytes::new(key), val)?;
119                }
120                m.end()
121            }
122        }
123    }
124}
125
126impl<'de> serde::Deserialize<'de> for BencodeValue {
127    fn deserialize<D: serde::Deserializer<'de>>(
128        deserializer: D,
129    ) -> std::result::Result<Self, D::Error> {
130        deserializer.deserialize_any(BencodeValueVisitor)
131    }
132}
133
134struct BencodeValueVisitor;
135
136impl<'de> serde::de::Visitor<'de> for BencodeValueVisitor {
137    type Value = BencodeValue;
138
139    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        write!(f, "a bencode value")
141    }
142
143    fn visit_i64<E: serde::de::Error>(self, v: i64) -> std::result::Result<Self::Value, E> {
144        Ok(BencodeValue::Integer(v))
145    }
146
147    fn visit_u64<E: serde::de::Error>(self, v: u64) -> std::result::Result<Self::Value, E> {
148        Ok(BencodeValue::Integer(v as i64))
149    }
150
151    fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> std::result::Result<Self::Value, E> {
152        Ok(BencodeValue::Bytes(v.to_vec()))
153    }
154
155    fn visit_borrowed_bytes<E: serde::de::Error>(
156        self,
157        v: &'de [u8],
158    ) -> std::result::Result<Self::Value, E> {
159        Ok(BencodeValue::Bytes(v.to_vec()))
160    }
161
162    fn visit_str<E: serde::de::Error>(self, v: &str) -> std::result::Result<Self::Value, E> {
163        Ok(BencodeValue::Bytes(v.as_bytes().to_vec()))
164    }
165
166    fn visit_seq<A: serde::de::SeqAccess<'de>>(
167        self,
168        mut seq: A,
169    ) -> std::result::Result<Self::Value, A::Error> {
170        let mut items = Vec::new();
171        while let Some(item) = seq.next_element()? {
172            items.push(item);
173        }
174        Ok(BencodeValue::List(items))
175    }
176
177    fn visit_map<A: serde::de::MapAccess<'de>>(
178        self,
179        mut map: A,
180    ) -> std::result::Result<Self::Value, A::Error> {
181        let mut dict = BTreeMap::new();
182        while let Some((key, val)) = map.next_entry::<serde_bytes::ByteBuf, BencodeValue>()? {
183            dict.insert(key.into_vec(), val);
184        }
185        Ok(BencodeValue::Dict(dict))
186    }
187}