simd-lite / simd-json-derive

high performance Serialize and Deserialize derives
Apache License 2.0
33 stars 7 forks source link

Tape storage re-use #79

Open JosiahWhite opened 5 months ago

JosiahWhite commented 5 months ago

Is it possible to reuse the storage that was allocated for the Tape Vec? Based on my digging it doesn't look to be possible in the current state.

If I am right about this not being possible at the moment, It feels like it isn't supported due to the tape type in this package being Peekable<IntoIter<>> but this looks like it could be solved by using a Peekable<Drain<>>?

Let me know if I am on the right track with this...

Licenser commented 5 months ago

That sounds reasonable, I like the idea:) definitely worth a try

Licenser commented 4 months ago

I think the reason this didn't happen is lifetimes. since the tape has a lifetime bound to it's elements the re-use would make the borrowchedker think the life times are related:

let a: &'a[u8] = b"42";
let mut reusable_tape = make_new_tape();;
parse(a, &mut reusable_tape);
// reusable_tape: Tape<'a>
do_stuff_with(reusable_tape);
reusable_tape.clear()
let a: &'b[u8] = b"43";
parse(b, &mut reusable_tape);
// reusable_tape: Tape<'b> <= lifetime conflict! 'a now needs to be 'b or wider
JosiahWhite commented 4 months ago

I was able to modify the library to support this by adding an additional lifetime on the tape, I'll open a PR with the changes shortly but it was pretty straightforward to implement. The tape type now looks like this:

pub type Tape<'tape, 'input> = Peekable<Drain<'tape, Node<'input>>>;
pub trait Deserialize<'input> {
    fn from_tape<'tape>(tape: &mut Tape<'tape, 'input>) -> simd_json::Result<Self>
    where
        Self: Sized + 'input;
/// etc...
}

This also required modifying every deserializer implementation to match the trait lifetime changes. After the changes I can reuse a tape like so (roughly):

simd_json::fill_tape(json_msg, buffers, tape)?;
let mut itr = tape.0.drain(..).peekable();
let item = MyStruct::from_tape(&mut itr);
println!("item: {:?}", item);
let tape = tape.reset();
simd_json::fill_tape(second_json_msg, buffers, tape)?;
let mut itr = tape.0.drain(..).peekable();
let item = MyStruct::from_tape(&mut itr);
println!("other item: {:?}", item);

The only downside of this is that any existing deserializer implementations need to be updated with the new type signatures