diff --git a/CHANGELOG.md b/CHANGELOG.md index a1e273a..4c4d77c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [0.11.3] - 2025-10-21 +### Changed + +* `SerIter` and `SerIterOwned` have been coalesced into a single structure + `SerIter` that is generic over iterators whose items implement `Borrow`. + ### Fixed * Fixed `mmap` dependency to 0.6. diff --git a/Cargo.lock b/Cargo.lock index 9115ef0..29052e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "byteorder" @@ -44,12 +44,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "combine" version = "4.6.7" @@ -86,7 +80,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -94,12 +88,12 @@ name = "epserde" version = "0.11.3" dependencies = [ "anyhow", - "bitflags 2.9.4", + "bitflags 2.10.0", "common_traits", "epserde-derive", "maligned", "mem_dbg", - "mmap-rs 0.6.1", + "mmap-rs", "sealed", "thiserror 2.0.17", "trybuild", @@ -113,7 +107,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -160,7 +154,7 @@ dependencies = [ "autocfg", "impl-tools-lib", "proc-macro-error2", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -172,14 +166,14 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", @@ -214,14 +208,14 @@ checksum = "7e88c3cbe8288f77f293e48a28b3232e3defd203a6d839fa7f68ea4329e83464" [[package]] name = "mem_dbg" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3909b65ec66660700b460313b017ea8308c7ee8a5c8795f8b97eafaf440fe9c" +checksum = "a3e3eb8a4c851185832fb250e5c041e74f4408e11fd56263cc1f61b48f9174f5" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "maligned", "mem_dbg-derive", - "mmap-rs 0.7.0", + "mmap-rs", ] [[package]] @@ -232,7 +226,7 @@ checksum = "f266c6ba1558dee16c56363c3dc6093a97a2451ddf29f928d5da042ee330537b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -260,30 +254,13 @@ dependencies = [ "combine", "libc", "mach2", - "nix 0.26.4", - "sysctl 0.5.5", + "nix", + "sysctl", "thiserror 1.0.69", "widestring", "windows", ] -[[package]] -name = "mmap-rs" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ecce9d566cb9234ae3db9e249c8b55665feaaf32b0859ff1e27e310d2beb3d8" -dependencies = [ - "bitflags 2.9.4", - "combine", - "libc", - "mach2", - "nix 0.30.1", - "sysctl 0.6.0", - "thiserror 2.0.17", - "widestring", - "windows", -] - [[package]] name = "nix" version = "0.26.4" @@ -297,18 +274,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "pin-utils" version = "0.1.0" @@ -401,7 +366,7 @@ checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -430,7 +395,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -467,9 +432,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -482,21 +447,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" dependencies = [ - "bitflags 2.9.4", - "byteorder", - "enum-as-inner", - "libc", - "thiserror 1.0.69", - "walkdir", -] - -[[package]] -name = "sysctl" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" -dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "enum-as-inner", "libc", @@ -545,7 +496,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -556,7 +507,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -615,9 +566,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "version_check" @@ -760,5 +711,5 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] diff --git a/README.md b/README.md index b42ed29..a4e12f1 100644 --- a/README.md +++ b/README.md @@ -564,10 +564,10 @@ let t: Data<&[i32]> = unsafe { >>::deserialize_eps(b.as_ref())? ## Example: (Structures containing) iterators -ε-serde can serialize exact-size iterators returning references to a type. The -resulting field can be deserialized as a vector/boxed slice. In this case we -need to wrap the iterator in a [`SerIter`], as ε-serde cannot implement the -serialization traits directly on [`Iterator`]. For example, +ε-serde can serialize exact-size iterators. The resulting field can be +deserialized as a vector/boxed slice. In this case we need to wrap the +iterator in a [`SerIter`], as ε-serde cannot implement the serialization traits +directly on [`Iterator`]. For example, ```rust # use epserde::prelude::*; @@ -578,7 +578,7 @@ let i: Iter<'_, i32> = v.iter(); // Serialize it by wrapping it in a SerIter let mut file = std::env::temp_dir(); file.push("serialized9"); -unsafe { SerIter::from(i).store(&file) }; +unsafe { SerIter::::from(i).store(&file) }; // Load the serialized form in a buffer let b = std::fs::read(&file)?; @@ -598,7 +598,7 @@ struct Data { s: A, } -let d = Data { s: SerIter::from(v.iter()) }; +let d = Data { s: SerIter::::from(v.iter()) }; // Serialize it unsafe { d.store(&file) }; // Load the serialized form in a buffer diff --git a/epserde/examples/iter.rs b/epserde/examples/iter.rs index 4de952d..fbfb5ca 100644 --- a/epserde/examples/iter.rs +++ b/epserde/examples/iter.rs @@ -11,8 +11,6 @@ //! //! Please compile with the "schema" feature to see the schema output. -use std::slice::Iter; - use epserde::{impls::iter::SerIter, prelude::*, ser::SerType}; use maligned::A16; @@ -21,7 +19,7 @@ struct Data { a: A, } -type Type<'a> = SerIter<'a, i32, Iter<'a, i32>>; +type Type = SerIter>; fn main() -> Result<(), Box> { println!("Serializable type: {}", core::any::type_name::()); @@ -32,12 +30,10 @@ fn main() -> Result<(), Box> { println!(); let a = vec![0, 1, 2, 3]; - // Turn it into an iterator - let i = a.iter(); + let i = a.clone().into_iter(); let mut cursor = >::new(); - // Serialize the iterator #[cfg(feature = "schema")] { let schema = unsafe { SerIter::from(i).serialize_with_schema(&mut cursor)? }; @@ -45,9 +41,11 @@ fn main() -> Result<(), Box> { println!(); } #[cfg(not(feature = "schema"))] - let _bytes_written = unsafe { SerIter::from(i).serialize(&mut cursor)? }; + { + let i = a.clone().into_iter(); + let _bytes_written = unsafe { SerIter::from(i).serialize(&mut cursor)? }; + } - // Do a full-copy deserialization as a vector cursor.set_position(0); let full = unsafe { >::deserialize_full(&mut cursor)? }; println!( @@ -58,7 +56,6 @@ fn main() -> Result<(), Box> { println!(); - // Do a full-copy deserialization as a boxed slice cursor.set_position(0); let full = unsafe { >::deserialize_full(&mut cursor)? }; println!( @@ -69,7 +66,6 @@ fn main() -> Result<(), Box> { println!(); - // Do an ε-copy deserialization as a slice let eps = unsafe { >::deserialize_eps(cursor.as_bytes())? }; println!( "ε-copy deserialization: returns the associated deserialization type {}", @@ -80,25 +76,23 @@ fn main() -> Result<(), Box> { println!(); println!(); - // Let's do it with a structure let i = a.iter(); - let d: Data = Data { + let d: Data>> = Data { a: SerIter::from(i), }; println!( "Serializable type: {}", - core::any::type_name::>() + core::any::type_name::>>>() ); println!( "Associated serialization type: {}", - core::any::type_name::>>() + core::any::type_name::>>>>() ); println!(); cursor.set_position(0); - // Serialize the structure #[cfg(feature = "schema")] { let schema = unsafe { d.serialize_with_schema(&mut cursor)? }; @@ -108,7 +102,6 @@ fn main() -> Result<(), Box> { #[cfg(not(feature = "schema"))] let _bytes_written = unsafe { d.serialize(&mut cursor)? }; - // Do a full-copy deserialization with a vector cursor.set_position(0); let full = unsafe { >>::deserialize_full(&mut cursor)? }; println!( @@ -119,7 +112,6 @@ fn main() -> Result<(), Box> { println!(); - // Do a full-copy deserialization with a boxed slice cursor.set_position(0); let full = unsafe { >>::deserialize_full(&mut cursor)? }; println!( @@ -130,7 +122,6 @@ fn main() -> Result<(), Box> { println!(); - // Do an ε-copy deserialization let eps = unsafe { >>::deserialize_eps(cursor.as_bytes())? }; println!( "ε-copy deserialization: returns the associated deserialization type {}", diff --git a/epserde/src/impls/iter.rs b/epserde/src/impls/iter.rs index 21519c0..5c4a9e6 100644 --- a/epserde/src/impls/iter.rs +++ b/epserde/src/impls/iter.rs @@ -4,21 +4,24 @@ * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later */ -//! Implementations for exact-size iterators. -//! -//! In theory all types serialized by ε-serde must be immutable. However, we -//! provide a convenience implementation that serializes [exact-size -//! iterators](core::iter::ExactSizeIterator) returning references to `T` as -//! vectors of `T`. -//! -//! More precisely, we provide a [`SerIter`] type that [wraps](SerIter::new) an -//! iterator into a serializable type. We provide a [`From`] implementation for -//! convenience. -//! -//! Note, however, that you must deserialize the iterator as a vector—see the -//! example in the [crate-level documentation](crate). - -use core::{cell::RefCell, ops::DerefMut}; +/*! + +Implementations for exact-size iterators. + +In theory all types serialized by ε-serde must be immutable. However, we +provide a convenience implementation that serializes [exact-size +iterators](core::iter::ExactSizeIterator) returning references to `T` as +vectors of `T`. + +More precisely, we provide a [`SerIter`] type that [wraps](SerIter::new) an +iterator into a serializable type. We provide a [`From`] implementation for +convenience. + +Note, however, that you must deserialize the iterator as a vector—see the +example in the [crate-level documentation](crate). + +!*/ +use core::{cell::RefCell, ops::DerefMut, borrow::Borrow}; use crate::prelude::*; use ser::*; @@ -27,36 +30,42 @@ use ser::*; use alloc::boxed::Box; #[derive(Clone, Debug, PartialEq, Eq, Default)] -pub struct SerIter<'a, T: 'a, I: ExactSizeIterator>(RefCell); +pub struct SerIter(RefCell, core::marker::PhantomData); -impl<'a, T, I: ExactSizeIterator> SerIter<'a, T, I> { +impl SerIter { pub fn new(iter: I) -> Self { - SerIter(RefCell::new(iter)) + SerIter(RefCell::new(iter), core::marker::PhantomData) } } -impl<'a, T, I: ExactSizeIterator> From for SerIter<'a, T, I> { +impl From for SerIter { fn from(iter: I) -> Self { SerIter::new(iter) } } -impl<'a, T: CopyType + SerInner, I: ExactSizeIterator> SerInner for SerIter<'a, T, I> +impl SerInner for SerIter where - SerIter<'a, T, I>: SerHelper<::Copy>, + I: ExactSizeIterator, + I::Item: Borrow, + T: CopyType + SerInner, + Self: SerHelper<::Copy>, { type SerType = Box<[T::SerType]>; const IS_ZERO_COPY: bool = false; unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> { - unsafe { SerHelper::_ser_inner(self, backend) } + unsafe { ::Copy>>::_ser_inner(self, backend) } } } -impl<'a, T: ZeroCopy, I: ExactSizeIterator> SerHelper for SerIter<'a, T, I> { +impl SerHelper for SerIter +where + I: ExactSizeIterator, + I::Item: Borrow, + T: ZeroCopy, +{ unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> { check_zero_copy::(); - // This code must be kept aligned with that of Box<[T]> for zero-copy - // types let mut iter = self.0.borrow_mut(); let len = iter.len(); backend.write("len", &len)?; @@ -64,7 +73,7 @@ impl<'a, T: ZeroCopy, I: ExactSizeIterator> SerHelper for Se let mut c = 0; for item in iter.deref_mut() { - ser_zero_unchecked(backend, item)?; + ser_zero_unchecked(backend, item.borrow())?; c += 1; } @@ -79,17 +88,20 @@ impl<'a, T: ZeroCopy, I: ExactSizeIterator> SerHelper for Se } } -impl<'a, T: DeepCopy, I: ExactSizeIterator> SerHelper for SerIter<'a, T, I> { +impl SerHelper for SerIter +where + I: ExactSizeIterator, + I::Item: Borrow, + T: DeepCopy, +{ unsafe fn _ser_inner(&self, backend: &mut impl WriteWithNames) -> ser::Result<()> { - // This code must be kept aligned with that of Vec for deep-copy - // types let mut iter = self.0.borrow_mut(); let len = iter.len(); backend.write("len", &len)?; let mut c = 0; for item in iter.deref_mut() { - unsafe { item._ser_inner(backend) }?; + unsafe { item.borrow()._ser_inner(backend)? }; c += 1; }