Rust中可变长度消息的单缓冲区容器:现有实现查询
复用大缓冲区存储可变长度消息的现有实现推荐
确实有现成的Rust crate能满足你复用单一缓冲区存储多条可变长度消息的需求,不用自己从零实现:
bytebuffer:针对字节场景优化的缓冲区,支持追加数据并自动记录分段边界,能直接取出各段消息的切片,适合处理u8类型的消息,还附带读写指针、字节序处理等实用功能。vec_arena:轻量级的向量竞技场,内部用单个Vec存储所有数据,通过索引数组记录每个分段的起始和长度(和你自己实现的PushVec思路几乎一致),支持迭代所有分段,还能安全地获取指定索引的分段切片。arena:通用内存竞技场,支持任意类型的数据存储,通过分配连续内存块的方式复用空间,你可以基于它封装适合自己消息类型的存储结构,灵活性更高。
另外,你自己实现的PushVec思路非常靠谱,核心逻辑没问题。如果不想引入外部依赖,这个实现完全可以投入使用,这里给几个小优化建议:
- 给
iter方法实现ExactSizeIterator,因为slices的长度就是消息总数,能让迭代器更高效; - 添加
get(&self, index: usize) -> Option<&[T]>方法,直接通过索引获取对应消息,不用遍历迭代器; - 针对
T: Copy的情况,可以单独实现一个版本,用copy_from_slice替代extend_from_slice,去掉Clone约束,提升性能。
你的原实现代码:
#[derive(Default)] pub struct PushVec<T: Clone> { buffer: Vec<T>, slices: Vec<usize>, } impl<T: Clone> PushVec<T> { pub fn push(&mut self, data: &[T]) { let len = data.len(); self.buffer.extend_from_slice(data); self.slices.push(len); } pub fn iter(&self) -> impl Iterator<Item = &[T]> { let mut bytes_counter: usize = 0; self.slices.iter().map(move |slice_len| { let slice = &self.buffer[bytes_counter .. bytes_counter + slice_len]; bytes_counter += slice_len; slice }) } pub fn clear(&mut self) { self.slices.clear(); self.buffer.clear(); } } #[cfg(test)] mod test { use super::PushVec; #[test] fn multi_vec_test() { let mut multi = PushVec::<i32>::default(); multi.push(&[1, 2, 3, 4, 5, 6, 7]); multi.push(&[8, 9]); multi.push(&[10, 11]); let get_result: Vec<&[i32]> = multi.iter().collect(); assert_eq!(get_result[0], &[1, 2, 3, 4, 5, 6, 7]); assert_eq!(get_result[1], &[8, 9]); assert_eq!(get_result[2], &[10, 11]); } }
内容的提问来源于stack exchange,提问作者Some Dinosaur
相关产品推荐
相关产品推荐

