在宏中捕获单态化泛型:嵌入式Rust无Box迭代器实现
无堆分配实现heapless::Vec的ToLeBytes trait
我编写了一个ToLeBytes trait,用于将对象序列化为小端字节迭代器:
pub trait ToLeBytes: Sized where Self::Iter: Iterator<Item = u8>, { type Iter; fn to_le_bytes(&self) -> Self::Iter; }
我已经为所需的基本数据类型及heapless::Vec实现了该trait:
#[allow(clippy::cast_possible_truncation)] #[cfg(feature = "heapless")] impl<I, const SIZE: usize> ToLeBytes for heapless::Vec<I, SIZE> where I: ToLeBytes, for<'a> <I as ToLeBytes>::Iter: Iterator<Item = u8> + 'a, { type Iter = Box<dyn Iterator<Item = u8>>; fn to_le_bytes(&self) -> Self::Iter { let mut iterator: Box<dyn Iterator<Item = u8>> = Box::new(empty()); if u8::try_from(SIZE).is_ok() { iterator = Box::new(<u8 as ToLeBytes>::to_le_bytes(&(self.len() as u8))); } else if u16::try_from(SIZE).is_ok() { iterator = Box::new(<u16 as ToLeBytes>::to_le_bytes(&(self.len() as u16))); } else if u32::try_from(SIZE).is_ok() { iterator = Box::new(<u32 as ToLeBytes>::to_le_bytes(&(self.len() as u32))); } else if u64::try_from(SIZE).is_ok() { iterator = Box::new(<u64 as ToLeBytes>::to_le_bytes(&(self.len() as u64))); } for item in self { iterator = Box::new(iterator.chain(<I as ToLeBytes>::to_le_bytes(item))); } iterator } }
由于代码需要运行在低性能嵌入式硬件上,我希望避免堆分配,因此必须移除Box。但Rust中每次调用.chain()都会返回新类型的迭代器,无法直接链式调用。我曾为该trait实现过派生宏,因此考虑用宏来解决问题,但只想为程序中实际使用的I和SIZE实现逻辑,这需要在单态化代码上运行宏,目前没找到相关实现方法,求方向指引。
更新
在Chayim的建议下,我已经接近目标:
use crate::ToLeBytes; use std::array::IntoIter; use std::iter::FlatMap; use std::slice::Iter; pub struct ContainerIterator<'a, T, const HEADER_SIZE: usize> where T: ToLeBytes, { size_iterator: IntoIter<u8, HEADER_SIZE>, items_iterator: FlatMap<Iter<'a, T>, <T as ToLeBytes>::Iter, fn(&T) -> <T as ToLeBytes>::Iter>, } impl<'a, T, const HEADER_SIZE: usize> ContainerIterator<'a, T, HEADER_SIZE> where T: ToLeBytes, { fn from_size_iterator_and_slice(size_iterator: IntoIter<u8, HEADER_SIZE>, items: &[T]) -> Self where T: ToLeBytes, { Self { size_iterator, items_iterator: items .iter() .flat_map(|item| <T as ToLeBytes>::to_le_bytes(item)), } } } impl<'a, T, const HEADER_SIZE: usize> Iterator for ContainerIterator<'a, T, HEADER_SIZE> where T: ToLeBytes, { type Item = u8; fn next(&mut self) -> Option<Self::Item> { if let Some(next_header) = self.size_iterator.next() { Some(next_header) } else { self.items_iterator.next() } } } pub enum SizedContainerIterator<'a, T> where T: ToLeBytes, { U8(ContainerIterator<'a, T, 1>), U16(ContainerIterator<'a, T, 2>), U32(ContainerIterator<'a, T, 4>), U64(ContainerIterator<'a, T, 8>), } impl<'a, T> SizedContainerIterator<'a, T> where T: ToLeBytes, { pub fn new(items: &[T], capacity: usize) -> SizedContainerIterator<'a, T> where T: ToLeBytes, { if u8::try_from(capacity).is_ok() { SizedContainerIterator::U8(ContainerIterator::from_size_iterator_and_slice( <u8 as ToLeBytes>::to_le_bytes(&(items.len() as u8)), items, )) } else if u16::try_from(capacity).is_ok() { SizedContainerIterator::U16(ContainerIterator::from_size_iterator_and_slice( <u16 as ToLeBytes>::to_le_bytes(&(items.len() as u16)), items, )) } else if u32::try_from(capacity).is_ok() { SizedContainerIterator::U32(ContainerIterator::from_size_iterator_and_slice( <u32 as ToLeBytes>::to_le_bytes(&(items.len() as u32)), items, )) } else if u64::try_from(capacity).is_ok() { SizedContainerIterator::U64(ContainerIterator::from_size_iterator_and_slice( <u64 as ToLeBytes>::to_le_bytes(&(items.len() as u64)), items, )) } else { unreachable!("vec size exceeds u64"); } } } impl<'a, T> Iterator for SizedContainerIterator<'a, T> where T: ToLeBytes, { type Item = u8; fn next(&mut self) -> Option<Self::Item> { match self { Self::U8(iterator) => iterator.next(), Self::U16(iterator) => iterator.next(), Self::U32(iterator) => iterator.next(), Self::U64(iterator) => iterator.next(), } } }
但现在我遇到了为Iter类型指定生命周期的问题:
#[allow(clippy::cast_possible_truncation)] #[cfg(feature = "heapless")] impl<I, const SIZE: usize> ToLeBytes for heapless::Vec<I, SIZE> where I: ToLeBytes, for<'a> <I as ToLeBytes>::Iter: Iterator<Item = u8> + 'a, { type Iter = SizedContainerIterator<'_, I>; fn to_le_bytes(&self) -> Self::Iter { SizedContainerIterator::new(self, SIZE) } }
内容的提问来源于stack exchange,提问作者user22747722
相关产品推荐
相关产品推荐

