You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在宏中捕获单态化泛型:嵌入式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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 19:32:02