pub enum Value<'a> {
Int(Int),
Str(Str<'a>),
List(List<'a>),
Dict(Dict<'a>),
}Expand description
A Bencode value is either an Int, a Str, a List or a Dict
Note that Value carries a lifetime parameter for borrowed data. This is useful for two reasons:
- When encoding data, you can avoid unnecessary allocations by just referencing existing data. Usually, the object is serialized right away and the object is dropped afterwards.
- When decoding data, all byte strings and dictionary keys are borrowed from the input buffer. This avoids unnecessary allocations and is key to performance. Especially since keys are often quite short, a separate Vec allocation per key would be very wasteful. The idea here is also that after decoding, the object is used and dispatched right away and then dropped. Actually required and useful data can be cloned out of the object if needed.
Values are meant to be constructed using a combination of the provided macros int!, str!, list! and dict!:
use bencode_minimal::*;
let alice = "Alice".to_string();
let v = dict! {
"age" => int!(42),
"name" => str!("John"), // <-- static
"friends" => list![
str!(alice.as_str()), // <-- borrowed
dict! {
"name" => str!("Bob".to_string()), // <-- owned
"data" => str!(vec![48u8, 49, 50]), // <-- owned
}
]
};
let bin = v.encode();
assert_eq!(&bin, b"d3:agei42e7:friendsl5:Aliced4:data3:0124:name3:Bobee4:name4:Johne");Variants§
Implementations§
Source§impl<'a> Value<'a>
impl<'a> Value<'a>
Sourcepub fn get<'b, T: TryFromValue<'b>>(&'b self, key: &'static str) -> Option<T>
pub fn get<'b, T: TryFromValue<'b>>(&'b self, key: &'static str) -> Option<T>
Assume the value is a dictionary and get the value for the given key, converted into the desired type using TryFromValue
Fails if the value is not a dictionary, the key does not exist or the value cannot be converted into the desired type.
use bencode_minimal::*;
let v = dict! {
"t" => str!(b"1234"),
"y" => str!(b"q"),
"q" => str!(b"ping"),
"a" => dict! {
"id" => str!(vec![5u8; 20]),
},
};
let ping_query = || {
let _ = v.get::<&str>("y").filter(|x| *x == "q")?;
let _ = v.get::<&str>("q").filter(|x| *x == "ping")?;
let a = v.get::<&Value>("a")?;
let t = v.get::<&[u8]>("t")?;
let id = a.get::<[u8;20]>("id")?;
Some((t, id))
};
let (t, id) = ping_query().unwrap();
assert_eq!(t, b"1234");
assert_eq!(id, [5u8; 20]);Sourcepub fn try_into<'b, T: TryFromValue<'b>>(&'b self) -> Option<T>
pub fn try_into<'b, T: TryFromValue<'b>>(&'b self) -> Option<T>
Try to convert the Value into the desired type using TryFromValue
Fails if the value cannot be converted into the desired type.
Sourcepub fn encode_into(&self, buf: &mut Vec<u8>)
pub fn encode_into(&self, buf: &mut Vec<u8>)
Encode into the provided buffer
The provided buffer is cleared before encoding and has the length of the encoded data afterwards. Its capacity is increased as needed but never decreased. Make sure to reuse the buffer when possible to avoid unnecessary allocations.Also, make sure to provide a buffer with sufficient initial capacity to avoid multiple reallocations. When passing the same buffer multiple times, its capacity will grow to the maximum size needed.
Sourcepub fn decode(buf: &'a [u8], max_allocs: usize) -> Option<Self>
pub fn decode(buf: &'a [u8], max_allocs: usize) -> Option<Self>
Try to decode a Value from the provided buffer
The max_allocs parameter limits the number of allocations that may be performed during decoding.
This is useful to avoid denial-of-service attacks by providing maliciously crafted input that would
cause excessive memory allocations. Each list item and dictionary entry counts as one allocation.
If the limit is exceeded, decoding fails and None is returned.
The returned Value borrows all byte strings from the input buffer. The value can therefor not outlive the input buffer. Either deconstruct the value right away (recommended) or use Self::into_owned.