bencode_rs/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
mod parsing;

use parsing::{next_list_item, next_value, Res, Value as ParseValue};
use std::{error::Error, fmt::Display};

pub enum Value {
    Integer(i64),
    ByteString(Vec<u8>),
    List(Vec<Value>),
    Dictionary(Vec<(Value, Value)>),
}

pub fn parse_all(bytes: &[u8]) -> Result<Vec<Value>, ParseError> {
    let (_, out) = parse_list(bytes, next_value)?;
    Ok(out)
}

fn parse_list(
    mut bytes: &[u8],
    f: fn(&[u8]) -> Res<Option<ParseValue>>,
) -> Result<(&[u8], Vec<Value>), ParseError> {
    let mut out = vec![];
    loop {
        match parse_one(bytes, f)? {
            (_, None) => break,
            (i, Some(value)) => {
                bytes = i;
                out.push(value);
            }
        }
    }
    Ok((bytes, out))
}

#[allow(clippy::type_complexity)]
fn parse_dictionary(mut bytes: &[u8]) -> Result<(&[u8], Vec<(Value, Value)>), ParseError> {
    let mut out = vec![];
    loop {
        let (i, k) = parse_one(bytes, next_list_item)?;
        let Some(k) = k else { break };
        let (i, v) = parse_one(i, next_list_item)?;
        bytes = i;
        let Some(v) = v else { return Err(ParseError) };
        out.push((k, v));
    }
    Ok((bytes, out))
}

fn parse_one(
    bytes: &[u8],
    f: fn(&[u8]) -> Res<Option<ParseValue>>,
) -> Result<(&[u8], Option<Value>), ParseError> {
    Ok(match f(bytes) {
        Ok((i, None)) => (i, None),
        Ok((i, Some(ParseValue::Integer(int)))) => (i, Some(Value::Integer(int))),
        Ok((i, Some(ParseValue::ByteString(s)))) => (i, Some(Value::ByteString(s.to_vec()))),
        Ok((i, Some(ParseValue::List))) => {
            let (i, list) = parse_list(i, next_list_item)?;
            (i, Some(Value::List(list)))
        }
        Ok((i, Some(ParseValue::Dictionary))) => {
            let (i, dictionary) = parse_dictionary(i)?;
            (i, Some(Value::Dictionary(dictionary)))
        }
        Err(_) => return Err(ParseError),
    })
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ParseError;

impl Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Invalid bencode")
    }
}

impl Error for ParseError {}