Closed avdb13 closed 1 year ago
Alas, making the decoder clonable will be a significant amount of work; all of the various types of decoder have a shared reference to the main decoding state, and just cloning the DictDecoder/ListDecoder leaves us with no place to store the main state.
However, all is not lost. Once you've decoded the dictionary and found the mode field, you can call into_raw
on the DictDecoder object, which will return a reference to the raw representation of the entire dict. You can use that to create a new decoder, the first object returned from which will be the original dict.
It would also be possible to "reset" a dictionary or list decoder, so that the next item that it returns would be the first one. There's no code for that yet, but we've just added it to the TODO list.
Would either of these two solutions work for you?
Can you suggest an example? This is what I have currently, spent hours trying to work around borrowing problems:
let dict = object.try_into_dictionary()?;
let mut info = Info::default();
// determine the mode while taking ownership of all the elements
let f = |dict: DictDecoder| -> (Vec<_>, Mode) {
let mut tmp = Vec::new();
let mut mode = Mode::default();
while let Some(pair) = dict.next_pair().unwrap() {
match pair {
(b"files", _) => mode = Mode::Multi(MultiInfo::default()),
p => tmp.push(p),
}
}
(tmp, mode)
};
let result = f(dict);
// match the vector of Objects on the right field
let rem: Vec<Result<Option<&(&[u8], bendy::decoding::Object)>, bendy::encoding::Error>> = result.0.iter().map(|pair| {
match pair {
(b"piece length", _) => {
match u64::decode_bencode_object(pair.1) {
Ok(x) => {
info.piece_length = x;
Ok(None)
},
Err(e) => Err(e),
}
}
(b"pieces", _) => {
match pair.1.try_into_bytes() {
Ok(x) => {
info.pieces = x.to_vec();
Ok(None)
},
Err(e) => Err(e.into()),
}
}
(b"private", _) => {
match u8::decode_bencode_object(pair.1) {
Ok(0) => {
info.private = Some(());
Ok(None)
},
Ok(x) => {
Ok(None)
},
Err(e) => Err(e.into()),
}
}
p => Ok(Some(p)),
}
}).collect();
Sorry for the ugly Result
handling boilerplate. I'm not sure whether it's a good idea to define the match in another closure and run that over the Iterator
(which can't be constructed and I have no clue why).
Note that this is inside an impl FromBencode
.
Currently I have the following code in which I have two possible enumerations for an object, first I have to parse the bytes to figure out what object to initialize for the data and after that I have to parse the fields. I need the ability to clone either
Object
orDictDecoder
for this: