尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

re_span 深度解析:Rerun 数据栈中保证非负长度的整数区间类型

re_span 深度解析:Rerun 数据栈中保证非负长度的整数区间类型 re_span 深度解析Rerun 数据栈中保证非负长度的整数区间类型【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun导读re_span是 Rerunreruncrates 家族中的一个轻量级基础工具 crate核心提供SpanIdx类型一个长度恒为非负值len 0的整数区间。它在 Rerun 中承担两类关键任务——re_chunk对 Chunk 数据行的高效切片row_sliced以及re_video对视频二进制字节区间的定位与传递。阅读本文你将掌握Span相对std::ops::Range解决了什么问题、其完整的构造/查询/集合运算/饱和运算 API 及使用姿势、溢出与边界处理约定以及它如何被上层模块实际调用。背景std::ops::Range的固有缺陷标准库的std::ops::RangeIdx只存储start与end两个端点因此可以构造出start end的反向区间。一旦函数以Range作为入参被调用方就必须防御性地检查这种非法状态并返回错误否则可能在切片、迭代时触发 panic 或未定义行为。re_span的设计目标见 crates/utils/re_span/README.md正是从类型层面消灭这类非法状态Span内部不存end而是存储start与len从而结构性保证了len 0恒成立。任何反向区间在构造入口就被拒绝调用方无需再逐层校验。Span核心数据结构源码定义位于 crates/utils/re_span/src/lib.rs/// An integer range whos length is always at least zero. #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SpanIdx: Unsigned Copy { /// The index of the first element. pub start: Idx, /// The number of elements in the range. pub len: Idx, }关键设计要点泛型约束Idx: Unsigned Copy只接受无符号整数类型从类型系统上杜绝负长度Copy Clone值语义传递零开销Default等价于start 0, len 0的空区间Ord/Hash/Eq支持排序、哈希可安全作为HashMap/BTreeMap键两个字段均为pub可直接解构例如re_chunk中let Span { start: index, len } span;见 crates/store/re_chunk/src/slice.rs。crate 的唯一外部依赖是num_traits见 crates/utils/re_span/Cargo.toml用于CheckedAdd、SaturatingAdd、SaturatingSub、Unsigned等 trait保证底层运算行为与标准整数语义一致。构造 API三种入口两种安全策略from_start_len恒定安全的组合方式pub const fn from_start_len(start: Idx, len: Idx) - Self直接由起点和长度构造const fn可在编译期求值。由于len本身非负此构造器永不失败。from_start_end可 panic 的便捷构造pub fn from_start_end(start: Idx, end: Idx) - Self // Panics if end start.由start含与end不含构造等价于半开区间[start, end)。当end start时直接assert!panic错误信息为Span start must be less than or equal to end。适合调用方已静态保证端点顺序的场景。try_from_start_end返回Option的容错构造pub fn try_from_start_end(start: Idx, end: Idx) - OptionSelf与上者逻辑相同但非法输入返回None而非 panic适合处理不可信输入。内置测试 crates/utils/re_span/src/lib.rs#L313-L324 验证了三态行为assert_eq!(Span::try_from_start_end(3_u64, 7), Some(Span::from_start_len(3, 4))); assert_eq!(Span::try_from_start_end(5_u64, 5), Some(Span::from_start_len(5, 0))); // 空区间合法 assert_eq!(Span::try_from_start_end(7_u64, 3), None); // 反向区间被拒注意start end是合法的——它表示一个空区间len 0这在半开区间语义下完全合理。查询与投影 APIend()返回区间外的下一个元素即start len半开区间右端点is_empty()len.is_zero()用于判断空区间contains(idx)判断索引是否落在[start, end)内含起点、不含终点需要Idx: PartialOrdrange()/FromSpanIdx for RangeIdx转换为标准std::ops::Range用于直接切片slice[span.range()]或slice[span]From自动转换try_castNarrow()将SpanIdx收窄转换为SpanNarrow任一字段转换失败则整体返回None需Narrow: TryFromIdx。集合运算交集、并集与裁剪intersects(other)半开区间的重叠判断pub fn intersects(self, other: Self) - bool按半开区间规则判断两个区间是否共享至少一个索引且空区间与任何区间都不相交。测试用例crates/utils/re_span/src/lib.rs#L326-L335覆盖了边界情形3..7与7..8不相交终点相接不算重叠、与0..3不相交、与内部空区间5..5不相交。union(other)覆盖两者及间隙的最小区间返回包含self与other及二者之间所有空隙的最小Span即min(start)到max(end)。测试证明其吸收性与间隙填充语义crates/utils/re_span/src/lib.rs#L337-L351。clamped_to(len)按容器长度夹取pub fn clamped_to(self, len: Idx) - Self将区间夹取到容器0..len内起点取start.min(len)长度取self.len.min(len - start)。若区间起点已超出len结果为起点在len处的空区间。测试crates/utils/re_span/src/lib.rs#L353-L371展示10..13夹到len10得10..10空20..23夹到10同样得10..10。该 API 是上层“先夹取再切片”防御模式的基石——见下文re_chunk应用。算术变换平移、缩放与饱和运算add(rhs)/sub(rhs)按无符号整数语义平移起点、保持长度不变。溢出/下溢遵循原生无符号运算行为add溢出回绕sub在rhs start时下溢 panic文档注释明确建议需要夹取语义时改用饱和版本。scale(scale)元素区间转字节区间pub fn scale(self, scale: Idx) - Self同时放大start与len。文档注释给出了典型用途用size_of::T()将元素索引区间翻译为字节区间。saturating_add(rhs)/saturating_sub(rhs)夹取式平移两端点均被限制在最大值/零处越界时长度会相应收缩。文档内嵌示例u8下(250..254).saturating_add(3) 253..255长度从 4 收缩为 2(2..5).saturating_sub(3) 0..2。测试 crates/utils/re_span/src/lib.rs#L373-L387 进一步验证了(250..254).saturating_add(200) 255..255完全被压成空区间的极端情形。类型特化与迭代支持针对高频索引类型提供了特化转换Spanu32::range_usize()拓宽转换为Rangeusize常用于索引Spanusize::cast_u64()拓宽为Spanu64Spanu64::range_usize()在原生平台上转换为Rangeusize以便索引。迭代方面由于底层Range迭代器依赖不稳定的Steptrait无法泛型实现IntoIterator因此通过macro_rules为u8/u16/u32/u64/usize逐个具体类型实现crates/utils/re_span/src/lib.rs#L261-L281impl_into_iterator!(u8, u16, u32, u64, usize);Debug输出格式与Range一致如3..7当start len溢出时输出200..200100 (overflow)而非 panic见测试 crates/utils/re_span/src/lib.rs#L389-L396。另实现了FromSpanIdx到std::ops::Range与core::range::Range的双向兼容转换。仓库内的真实应用场景re_chunkChunk 行切片的基础设施re_chunk是 Rerun 的核心存储格式 crate其行切片 API 直接以Spanusize为参数见 crates/store/re_chunk/src/slice.rspub fn row_sliced_shallow(self, span: Spanusize) - Self pub fn row_sliced_deep(self, span: Spanusize) - Self pub fn row_sliced(self, span: Spanusize) - Self实现中采用“先夹取、后判空”的防御模式crates/store/re_chunk/src/slice.rs#L128-L137let span span.clamped_to(self.num_rows()); if span.is_empty() { return self.emptied(); } let Span { start: index, len } span;clamped_to(self.num_rows())保证越界请求被安全夹取避免slice::slicepanic空区间直接返回空 Chunk无需后续运算Span保证len非负因此row_ids.slice(index, len)这类底层调用无需再校验长度合法性。单行切片则通过Span::from_start_len(index, 1)构造crates/store/re_chunk/src/slice.rs#L70测试中大量使用Span::from_start_len(0, 1)、(1, 1)、(2, 1)逐行切片crates/store/re_chunk/src/slice.rs#L1753-L1755。re_video视频字节区间的表达re_videocrate 使用Span表达视频数据在存储中的字节位置crates/utils/re_video/src/demux/mp4.rslet byte_span Span::from_start_len(sample.offset, sample.size); // ... crate::VideoSource::Span(byte_span),VideoSource::Span变体直接承载Span随后在播放解码时从该字节区间取出数据。这里Span的“长度恒非负”特性天然契合文件字节区间的语义——解复用器解析出的offset与size组合不会产生反向区间。同时Span的Copy语义使得这些区间可以在解析、缓存、播放链路中廉价传递相关使用见 crates/utils/re_video/src/player/mod.rs 与 crates/utils/re_video/src/stable_index_deque.rs。总结re_span用约 400 行代码含测试提供了一个小而精的区间抽象其价值可归纳为类型安全len 0由结构保证反向区间在构造入口被拒绝调用方零防御成本边界完备半开区间语义、空区间显式支持、clamped_to/饱和运算覆盖全部越界场景零依赖成本仅依赖num_traitsCopy值语义在数据热路径上开销可忽略生态验证re_chunk的行切片与re_video的字节区间都将其作为核心参数类型是 Rerun 存储与多媒体链路中不可或缺的基础设施。对于需要在 Rust 中安全表达“[start, startlen)整数区间”的场景re_span是一个可以直接借鉴甚至直接依赖的成熟实现其源码与完整测试位于 crates/utils/re_span/src/lib.rs可作为学习“用类型消除非法状态”这一 Rust 工程实践的绝佳范本。【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表