From 92021a260842059ee12d4c588d2cf0b57ffc95eb Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Tue, 31 Mar 2026 00:34:31 -0600 Subject: [PATCH] feat: add legacy-msrv feature for Rust 1.83+ compat Adds a `legacy-msrv` feature flag that replaces the const copy_from_slice (Rust 1.93+) with a manual byte loop, allowing the crate to compile on older toolchains like Xtensa. All other optimizations (sub-slice scan, zero fast path, decode batch fill) work on 1.83 without the feature. Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.toml | 1 + src/lib.rs | 26 +++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e147895..0141895 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ categories = ["encoding", "no-std::no-alloc", "embedded"] [features] default = [] +legacy-msrv = [] [lints.rust] unsafe_code = "forbid" diff --git a/src/lib.rs b/src/lib.rs index 8d3cf0a..d850907 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,6 +148,28 @@ #![forbid(unsafe_code)] #![warn(missing_docs)] +/// Copy `src` into `dest[offset..]` in a const-compatible way. +/// Default path uses `copy_from_slice` (Rust 1.93+, compiles to memcpy). +/// With `legacy-msrv` feature, falls back to a manual loop for Rust 1.83+. +#[inline(always)] +#[cfg(not(feature = "legacy-msrv"))] +const fn const_copy(dest: &mut [u8], offset: usize, src: &[u8]) { + let (_, tail) = dest.split_at_mut(offset); + let (chunk, _) = tail.split_at_mut(src.len()); + chunk.copy_from_slice(src); +} + +/// Fallback const copy for toolchains older than Rust 1.93. +#[inline(always)] +#[cfg(feature = "legacy-msrv")] +const fn const_copy(dest: &mut [u8], offset: usize, src: &[u8]) { + let mut i = 0; + while i < src.len() { + dest[offset + i] = src[i]; + i += 1; + } +} + /// COBS-encode `src` into `dest`. /// /// Returns the number of bytes written, or `None` if `dest` is too small. @@ -223,10 +245,8 @@ pub const fn encode(src: &[u8], dest: &mut [u8]) -> Option { if di + run > dest.len() { return None; } - let (_, dest_tail) = dest.split_at_mut(di); - let (dest_chunk, _) = dest_tail.split_at_mut(run); let (src_chunk, _) = src_window.split_at(run); - dest_chunk.copy_from_slice(src_chunk); + const_copy(dest, di, src_chunk); di += run; } si += run;