sveppa_bencode/
bencode.rs

1use std::collections::HashMap;
2
3use Bencode::*;
4
5use crate::error::{
6    BencodeParserError,
7    BencodeParserError::*,
8    invalid_variant_method,
9};
10use crate::parser::parse_child;
11
12/// A nested enum containing the parsed Bencode file structure.
13pub enum Bencode {
14    /// A value. (or a 'leaf' in tree terminology) which can be converted into a value with any
15    /// of: `as_string()`, `as_bytes()`, or `as_usize()`.
16    ///
17    /// Possible options:
18    /// - An Integer. eg: `i123e`. indicated by `i` and terminated by `e`.
19    /// - A ByteString. eg: `3:cat`. stars with an integer length, followed by `:` as a separator,
20    ///   then the bytes.
21    Value(Vec<u8>),
22    /// A list of Bencode structs which can be destructured into a Vec with `as_vec()`.
23    List(Vec<Bencode>),
24    /// A map of bencoded values. All keys are Vec<u8>, and values are nested Bencode structs.
25    /// This can be destructured with `as_map()`.
26    Dict(HashMap<Vec<u8>, Bencode>),
27}
28
29/// Attempts to parse the given bytes into a Bencode object.
30pub fn from_bytes(bytes: &[u8]) -> Result<Bencode, BencodeParserError> {
31    match parse_child(bytes) {
32        Ok((bencode, _)) => Ok(bencode),
33        Err(e) => Err(e)
34    }
35}
36
37impl Bencode {
38    /// Attempt to parse a `Bencode::Value` variant into a `usize`.
39    ///
40    /// Can return:
41    /// - `InvalidVariantMethod`, if called on any of `Bencode::{List, Dict}`.
42    /// - `InvalidUTF8String`, if the bytes cannot be parsed as a UTF8, ASCII string.
43    /// - `InvalidASCIIInteger`, if the ASCII bytes aren't a valid base 10 number.
44    pub fn as_usize(&self) -> Result<usize, BencodeParserError> {
45        match self {
46            Value(_) => match self.as_string() {
47                Ok(str) => match usize::from_str_radix(str.as_str(), 10) {
48                    Ok(val) => Ok(val),
49                    Err(err) => Err(InvalidASCIIInteger(err))
50                },
51                Err(e) => Err(e),
52            }
53            _ => Err(invalid_variant_method("as_usize()", self))
54        }
55    }
56    /// Attempt to parse a `Bencode::Value` variant into a `String`.
57    ///
58    /// Can return:
59    /// - `InvalidVariantMethod`, if called on any of `Bencode::{List, Dict}`.
60    /// - `InvalidUTF8String`, if the bytes cannot be parsed as a UTF8, ASCII string.
61    pub fn as_string(&self) -> Result<String, BencodeParserError> {
62        match self {
63            Value(val) => {
64                match String::from_utf8(val.to_owned()) {
65                    Ok(val) => Ok(val),
66                    Err(err) => Err(InvalidUTF8String(err)),
67                }
68            }
69            _ => Err(invalid_variant_method("as_string()", self))
70        }
71    }
72    /// Destructures a `Bencode::Value` into a `Vec<u8>`. This method will always succeed if applied
73    /// to a `Bencode::Value`.
74    ///
75    /// Can return:
76    /// - `InvalidVariantMethod`, if called on any of `Bencode::{List, Dict}`.
77    pub fn as_bytes(&self) -> Result<&Vec<u8>, BencodeParserError> {
78        match self {
79            Value(val) => Ok(val),
80            _ => Err(invalid_variant_method("as_bytes()", self))
81        }
82    }
83    /// Attempt to parse a `Bencode::List` into a `Vec<Bencode>`. This method will always succeed
84    /// if applied to a `Bencode::List`.
85    ///
86    /// Can return:
87    /// - `InvalidVariantMethod`, if called on any of `Bencode::{Value, Dict}`.
88    pub fn as_vec(&self) -> Result<&Vec<Bencode>, BencodeParserError> {
89        match self {
90            List(list) => Ok(list),
91            _ => Err(invalid_variant_method("as_list()", self))
92        }
93    }
94    /// Attempt to parse a `Bencode::Dict` into a `HashMap<Vec<u8>, Bencode>`. This method will
95    /// always succeed if applied to a `Bencode::Dict`.
96    ///
97    /// Can return:
98    /// - `InvalidVariantMethod`, if called on any of `Bencode::{Value, List}`.
99    pub fn as_map(&self) -> Result<&HashMap<Vec<u8>, Bencode>, BencodeParserError> {
100        match self {
101            Dict(dict) => Ok(dict),
102            _ => Err(invalid_variant_method("as_dict()", self))
103        }
104    }
105}