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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
use std::collections::HashMap; use Bencode::*; use crate::error::{ BencodeParserError, BencodeParserError::*, invalid_variant_method, }; use crate::parser::parse_child; /// A nested enum containing the parsed Bencode file structure. pub enum Bencode { /// A value. (or a 'leaf' in tree terminology) which can be converted into a value with any /// of: `as_string()`, `as_bytes()`, or `as_usize()`. /// /// Possible options: /// - An Integer. eg: `i123e`. indicated by `i` and terminated by `e`. /// - A ByteString. eg: `3:cat`. stars with an integer length, followed by `:` as a separator, /// then the bytes. Value(Vec<u8>), /// A list of Bencode structs which can be destructured into a Vec with `as_vec()`. List(Vec<Bencode>), /// A map of bencoded values. All keys are Vec<u8>, and values are nested Bencode structs. /// This can be destructured with `as_map()`. Dict(HashMap<Vec<u8>, Bencode>), } /// Attempts to parse the given bytes into a Bencode object. pub fn from_bytes(bytes: &[u8]) -> Result<Bencode, BencodeParserError> { match parse_child(bytes) { Ok((bencode, _)) => Ok(bencode), Err(e) => Err(e) } } impl Bencode { /// Attempt to parse a `Bencode::Value` variant into a `usize`. /// /// Can return: /// - `InvalidVariantMethod`, if called on any of `Bencode::{List, Dict}`. /// - `InvalidUTF8String`, if the bytes cannot be parsed as a UTF8, ASCII string. /// - `InvalidASCIIInteger`, if the ASCII bytes aren't a valid base 10 number. pub fn as_usize(&self) -> Result<usize, BencodeParserError> { match self { Value(_) => match self.as_string() { Ok(str) => match usize::from_str_radix(str.as_str(), 10) { Ok(val) => Ok(val), Err(err) => Err(InvalidASCIIInteger(err)) }, Err(e) => Err(e), } _ => Err(invalid_variant_method("as_usize()", self)) } } /// Attempt to parse a `Bencode::Value` variant into a `String`. /// /// Can return: /// - `InvalidVariantMethod`, if called on any of `Bencode::{List, Dict}`. /// - `InvalidUTF8String`, if the bytes cannot be parsed as a UTF8, ASCII string. pub fn as_string(&self) -> Result<String, BencodeParserError> { match self { Value(val) => { match String::from_utf8(val.to_owned()) { Ok(val) => Ok(val), Err(err) => Err(InvalidUTF8String(err)), } } _ => Err(invalid_variant_method("as_string()", self)) } } /// Destructures a `Bencode::Value` into a `Vec<u8>`. This method will always succeed if applied /// to a `Bencode::Value`. /// /// Can return: /// - `InvalidVariantMethod`, if called on any of `Bencode::{List, Dict}`. pub fn as_bytes(&self) -> Result<&Vec<u8>, BencodeParserError> { match self { Value(val) => Ok(val), _ => Err(invalid_variant_method("as_bytes()", self)) } } /// Attempt to parse a `Bencode::List` into a `Vec<Bencode>`. This method will always succeed /// if applied to a `Bencode::List`. /// /// Can return: /// - `InvalidVariantMethod`, if called on any of `Bencode::{Value, Dict}`. pub fn as_vec(&self) -> Result<&Vec<Bencode>, BencodeParserError> { match self { List(list) => Ok(list), _ => Err(invalid_variant_method("as_list()", self)) } } /// Attempt to parse a `Bencode::Dict` into a `HashMap<Vec<u8>, Bencode>`. This method will /// always succeed if applied to a `Bencode::Dict`. /// /// Can return: /// - `InvalidVariantMethod`, if called on any of `Bencode::{Value, List}`. pub fn as_map(&self) -> Result<&HashMap<Vec<u8>, Bencode>, BencodeParserError> { match self { Dict(dict) => Ok(dict), _ => Err(invalid_variant_method("as_dict()", self)) } } }