From 05d78c2421a46b56485e6b60265a31e72e0a5eb6 Mon Sep 17 00:00:00 2001 From: Joel Alvarez Date: Wed, 29 Jul 2026 09:20:57 -0700 Subject: [PATCH] feat: add zero copy parser models --- .../2026-07-29-rust-performance-course.md | 2 +- src/lib.rs | 1 + src/zero_copy.rs | 27 +++++++++++++++++++ tests/zero_copy_parser.rs | 24 +++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/zero_copy.rs create mode 100644 tests/zero_copy_parser.rs diff --git a/docs/superpowers/plans/2026-07-29-rust-performance-course.md b/docs/superpowers/plans/2026-07-29-rust-performance-course.md index 989a48b..80f6e99 100644 --- a/docs/superpowers/plans/2026-07-29-rust-performance-course.md +++ b/docs/superpowers/plans/2026-07-29-rust-performance-course.md @@ -136,7 +136,7 @@ su dependencia. ### Capítulo 08: zero-copy, buffers y serialización - [x] #24 Especificar préstamos, buffers, parsing y costo de copias. -- [ ] #25 Implementar y probar parsing basado en slices y buffers. +- [x] #25 Implementar y probar parsing basado en slices y buffers. - [ ] #26 Escribir capítulo, diagrama, ejemplos, ejercicios y benchmarks. ### Capítulo 09: SIMD y límites de vectorización diff --git a/src/lib.rs b/src/lib.rs index 4927bbb..129174a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ pub mod layout; pub mod locality; pub mod measurement; pub mod profile; +pub mod zero_copy; /// Devuelve la identidad del curso para comprobar la fundación del crate. #[must_use] diff --git a/src/zero_copy.rs b/src/zero_copy.rs new file mode 100644 index 0000000..a3e7135 --- /dev/null +++ b/src/zero_copy.rs @@ -0,0 +1,27 @@ +//! Parsing equivalente con datos prestados o propietarios. + +/// Error al interpretar un segmento de pares clave-valor. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ParseError { + /// El segmento no contiene el separador `=`. + MissingSeparator, +} + +/// Interpreta pares `clave=valor` sin copiar sus fragmentos. +pub fn parse_borrowed(input: &str) -> Result, ParseError> { + input + .split(';') + .filter(|segment| !segment.is_empty()) + .map(|segment| segment.split_once('=').ok_or(ParseError::MissingSeparator)) + .collect() +} + +/// Interpreta el mismo formato y crea una representación propietaria. +pub fn parse_owned(input: &str) -> Result, ParseError> { + parse_borrowed(input).map(|pairs| { + pairs + .into_iter() + .map(|(key, value)| (key.to_owned(), value.to_owned())) + .collect() + }) +} diff --git a/tests/zero_copy_parser.rs b/tests/zero_copy_parser.rs new file mode 100644 index 0000000..2baf6b0 --- /dev/null +++ b/tests/zero_copy_parser.rs @@ -0,0 +1,24 @@ +use rust_performance::zero_copy::{parse_borrowed, parse_owned, ParseError}; + +#[test] +fn borrowed_and_owned_parsers_preserve_the_same_pairs() { + let borrowed = parse_borrowed("lang=rust;mode=release").expect("valid input"); + let owned = parse_owned("lang=rust;mode=release").expect("valid input"); + + assert_eq!(borrowed, [("lang", "rust"), ("mode", "release")]); + assert_eq!( + owned, + [ + (String::from("lang"), String::from("rust")), + (String::from("mode"), String::from("release")) + ] + ); +} + +#[test] +fn parser_rejects_segments_without_an_equals_sign() { + assert_eq!( + parse_borrowed("lang=rust;invalid"), + Err(ParseError::MissingSeparator) + ); +}