bencode_rs/
lib.rs

1mod parsing;
2
3use parsing::{next_nested, next_outer, Res, Value as ParseValue};
4use std::{error::Error, fmt::Display};
5
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub enum Value {
8    Integer(i64),
9    ByteString(Vec<u8>),
10    List(Vec<Value>),
11    Dictionary(Vec<(Value, Value)>),
12}
13
14pub fn parse_all(bytes: &[u8]) -> Result<Vec<Value>, ParseError> {
15    let (_, out) = parse_many(bytes, next_outer)?;
16    Ok(out)
17}
18
19fn parse_many(
20    mut bytes: &[u8],
21    f: fn(&[u8]) -> Res<Option<ParseValue>>,
22) -> Result<(&[u8], Vec<Value>), ParseError> {
23    let mut out = vec![];
24    loop {
25        let (i, maybe_value) = parse_one(bytes, f)?;
26        bytes = i;
27        match maybe_value {
28            Some(value) => out.push(value),
29            None => break,
30        }
31    }
32    Ok((bytes, out))
33}
34
35#[allow(clippy::type_complexity)]
36fn parse_dictionary(mut bytes: &[u8]) -> Result<(&[u8], Vec<(Value, Value)>), ParseError> {
37    let mut out = vec![];
38    loop {
39        let (i, k) = parse_one(bytes, next_nested)?;
40        bytes = i;
41        let Some(k) = k else { break };
42        let (i, v) = parse_one(bytes, next_nested)?;
43        bytes = i;
44        let Some(v) = v else { return Err(ParseError) };
45        out.push((k, v));
46    }
47    Ok((bytes, out))
48}
49
50fn parse_one(
51    bytes: &[u8],
52    f: fn(&[u8]) -> Res<Option<ParseValue>>,
53) -> Result<(&[u8], Option<Value>), ParseError> {
54    Ok(match f(bytes) {
55        Ok((i, None)) => (i, None),
56        Ok((i, Some(ParseValue::Integer(int)))) => (i, Some(Value::Integer(int))),
57        Ok((i, Some(ParseValue::ByteString(s)))) => (i, Some(Value::ByteString(s.to_vec()))),
58        Ok((i, Some(ParseValue::List))) => {
59            let (i, list) = parse_many(i, next_nested)?;
60            (i, Some(Value::List(list)))
61        }
62        Ok((i, Some(ParseValue::Dictionary))) => {
63            let (i, dictionary) = parse_dictionary(i)?;
64            (i, Some(Value::Dictionary(dictionary)))
65        }
66        Err(e) => {
67            println!("{e:?}");
68            return Err(ParseError);
69        }
70    })
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
74pub struct ParseError;
75
76impl Display for ParseError {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        write!(f, "Invalid bencode")
79    }
80}
81
82impl Error for ParseError {}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn valid_int() {
90        assert_eq!(
91            parse_all(b"i115ei-12e"),
92            Ok(vec![Value::Integer(115), Value::Integer(-12)])
93        );
94    }
95
96    #[test]
97    fn valid_list() {
98        assert_eq!(
99            parse_all(b"li115ei-12ee"),
100            Ok(vec![Value::List(vec![
101                Value::Integer(115),
102                Value::Integer(-12)
103            ])])
104        )
105    }
106
107    #[test]
108    fn valid_dictionary() {
109        assert_eq!(
110            parse_all(b"di1ei2ee"),
111            Ok(vec![Value::Dictionary(vec![(
112                Value::Integer(1),
113                Value::Integer(2),
114            )])])
115        )
116    }
117
118    #[test]
119    fn complex_value() {
120        assert_eq!(
121            parse_all(b"i1eli2el3:foo3:bared3:bazi3el7:listkeye5:valueee"),
122            Ok(vec![
123                Value::Integer(1),
124                Value::List(vec![
125                    Value::Integer(2),
126                    Value::List(vec![
127                        Value::ByteString(b"foo".to_vec()),
128                        Value::ByteString(b"bar".to_vec()),
129                    ]),
130                    Value::Dictionary(vec![
131                        (Value::ByteString(b"baz".to_vec()), Value::Integer(3)),
132                        (
133                            Value::List(vec![Value::ByteString(b"listkey".to_vec())]),
134                            Value::ByteString(b"value".to_vec())
135                        )
136                    ])
137                ])
138            ])
139        )
140    }
141}