ringbuffer icon indicating copy to clipboard operation
ringbuffer copied to clipboard

feat: implement Serialize and Deserialize

Open dzmitry-lahoda opened this issue 1 year ago • 9 comments

All the different ringbuffers should implement Serialize and Deserialize when the serde feature is enabled, and should do so safely and soundly.

dzmitry-lahoda avatar Apr 01 '24 19:04 dzmitry-lahoda

@jdonszelmann would PR with borsh serde considered for review and merge if made? behind borsh feature gate

dzmitry-lahoda avatar May 15 '24 17:05 dzmitry-lahoda

I like the idea, but why do we need borsh? I think if you implement the Serialize and Deserialize traits that should be enough. Then you can choose any format (like postcard or even json if you really wanted)

jdonszelmann avatar May 15 '24 17:05 jdonszelmann

I talked to @NULLx76 about this and we'd prefer serde to borsh

jdonszelmann avatar May 15 '24 17:05 jdonszelmann

Additionally I'm against this because Borsh seems related to blockchain/web3 which is not something we'd like to condone

NULLx76 avatar May 15 '24 17:05 NULLx76

Feel free to file a PR though

jdonszelmann avatar May 15 '24 18:05 jdonszelmann

please reopen when change reasoning.

here is wrapper for Const if somebody needs that

//! This module provides serialization and deserialization for the `ringbuffer` crate.
use borsh::{BorshDeserialize, BorshSerialize};
use ringbuffer::{ConstGenericRingBuffer, RingBuffer};

#[derive(Debug, Default, BorshSerialize, BorshDeserialize, Clone)]
pub struct ConstGenericRingBufferWrapper<T, const CAP: usize> {
    #[borsh(
        serialize_with = "serialize_const_generic_ring_buffer",
        deserialize_with = "deserialize_const_generic_ring_buffer"
    )]
    buffer: ConstGenericRingBuffer<T, CAP>,
}

/// Ring buffer is just fixed size array
#[cfg(test)]
impl<T: borsh::BorshSchema, const CAP: usize> borsh::BorshSchema
    for ConstGenericRingBufferWrapper<T, CAP>
{
    fn add_definitions_recursively(
        definitions: &mut std::collections::BTreeMap<
            borsh::schema::Declaration,
            borsh::schema::Definition,
        >,
    ) {
        <[T; CAP]>::add_definitions_recursively(definitions)
    }

    fn declaration() -> borsh::schema::Declaration {
        <[T; CAP]>::declaration()
    }
}

impl<T, const CAP: usize> ConstGenericRingBufferWrapper<T, CAP> {
    pub fn peek(&self) -> Option<&T> {
        self.buffer.peek()
    }

    pub fn push(&mut self, item: T) {
        self.buffer.push(item);
    }

    pub fn back(&self) -> Option<&T> {
        self.buffer.back()
    }

    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.buffer.iter()
    }

    pub fn get(&self, index: usize) -> Option<&T> {
        self.buffer.get(index)
    }

    pub fn len(&self) -> usize {
        self.buffer.len()
    }

    pub fn front(&self) -> Option<&T> {
        self.buffer.front()
    }
}

pub fn serialize_const_generic_ring_buffer<T: borsh::BorshSerialize, const CAP: usize>(
    obj: &ConstGenericRingBuffer<T, CAP>,
    writer: &mut impl std::io::prelude::Write,
) -> std::io::Result<()> {
    for item in obj.into_iter() {
        item.serialize(writer)?;
    }
    Ok(())
}

pub fn deserialize_const_generic_ring_buffer<T: borsh::BorshDeserialize, const CAP: usize>(
    reader: &mut impl std::io::prelude::Read,
) -> std::io::Result<ConstGenericRingBuffer<T, CAP>> {
    let mut buffer = ConstGenericRingBuffer::new();
    for _ in 0..CAP {
        buffer.push(T::try_from_reader(reader)?);
    }
    if T::try_from_reader(reader).is_ok() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "Buffer is longs than CAP",
        ));
    }
    Ok(buffer)
}

dzmitry-lahoda avatar May 19 '24 12:05 dzmitry-lahoda

sorry, some mix of things. closed for borsh. for serde open sure :) sorry for confusion.

dzmitry-lahoda avatar May 19 '24 13:05 dzmitry-lahoda