From d8748d851c96c42d21a8ea12376bae5b0de21eb6 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Wed, 4 Dec 2024 00:32:21 +0300 Subject: [PATCH 1/2] Added slices --- src/enc.rs | 3 - src/lib.rs | 226 +++++++++++++++++++++++++++++++++++++++++------------ src/raw.rs | 153 ++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+), 51 deletions(-) diff --git a/src/enc.rs b/src/enc.rs index ee4b838..b57a5e6 100644 --- a/src/enc.rs +++ b/src/enc.rs @@ -292,9 +292,6 @@ impl> Encoding for UserDefinedEncoding { fn stage_by_prefix(&self, prefix: u8) -> Option<&Stage> { let index = self.stages_lookup[prefix as usize] as usize; let stage = self.stages.as_ref().get(index); - dbg!(prefix); - dbg!(index); - dbg!(self.stages.as_ref()); stage } diff --git a/src/lib.rs b/src/lib.rs index 59840f6..327705b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,10 +25,11 @@ mod raw; mod reader; mod writer; -use raw::RawOrdPath; +use raw::{RawOrdPath, RawOrdPathSlice}; pub use enc::*; pub use error::*; +pub use raw::Bytes; pub use reader::*; pub use writer::*; @@ -92,7 +93,20 @@ impl OrdPath { Self::try_from_bytes(s, enc).unwrap() } - /// Tries to encode a slice of ordinals `s` and ceate a new `OrdPath`. + /// Tries to allocate a new `OrdPath` storing the slice. + pub fn try_from_slice(s: OrdPathSlice<'_, E>) -> Result + where + E: Clone, + { + let mut bytes = s.bytes(); + let mut path = Self::new(bytes.len(), s.encoding().clone())?; + + bytes.read_exact(path.raw.as_mut_slice())?; + + Ok(path) + } + + /// Tries to encode a slice of ordinals `s` and create a new `OrdPath`. pub fn try_from_ordinals(s: &[i64], enc: E) -> Result { let mut len = Len(0); let mut writer = Writer::new(&mut len, &enc); @@ -223,56 +237,22 @@ impl OrdPath { /// # use ordpath::{DefaultEncoding, OrdPath}; /// let path = ::from_ordinals(&[1, 2], DefaultEncoding); /// let parent = path.parent(); - /// assert_eq!(parent, Some(::from_ordinals(&[1], DefaultEncoding))); + /// assert_eq!(parent, Some(::from_ordinals(&[1], DefaultEncoding).as_slice())); /// let grand_parent = parent.and_then(|p| p.parent()); - /// assert_eq!(grand_parent, Some(::from_ordinals(&[], DefaultEncoding))); + /// assert_eq!(grand_parent, Some(::from_ordinals(&[], DefaultEncoding).as_slice())); /// let grand_grand_parent = grand_parent.and_then(|p| p.parent()); /// assert_eq!(grand_grand_parent, None); /// ``` - pub fn parent(&self) -> Option - where - E: Clone, - { - let src = self.bytes(); - if src.is_empty() { - return None; - } - - let mut bits = 0u8; - let mut bytes = 0; - let mut reader = Reader::new(src, self.encoding()); - unsafe { - // SAFETY: Validation of the data happens on creation even for a byte slice. - if let Some((_, stage)) = reader.read().unwrap_unchecked() { - let mut bits_prev = stage.bits(); - while let Some((_, stage)) = reader.read().unwrap_unchecked() { - let bits_tmp = bits + bits_prev; - - bits_prev = stage.bits(); - bits = bits_tmp & 7; - bytes += bits_tmp as usize >> 3; - } - - if bits > 0 || bytes > 0 { - bytes += bits.div_ceil(8) as usize; - bits &= 7; - } - } - } - - let mut path = Self::new(bytes, self.encoding().clone()).unwrap(); - let dst = path.raw.as_mut_slice(); - if !dst.is_empty() { - dst.copy_from_slice(&src[..dst.len()]); - - let bits = (8 - bits) & 7; - let last = &mut dst[dst.len() - 1]; + pub fn parent(&self) -> Option> { + self.as_slice().parent() + } - *last &= u8::MAX << bits; - path.raw.set_trailing_bits(bits); + /// Returns a slice containing the entire `OrdPath`. + pub fn as_slice(&self) -> OrdPathSlice { + OrdPathSlice { + raw: RawOrdPathSlice::new(self.bytes(), 0, self.raw.trailing_bits()), + enc: self.encoding(), } - - Some(path) } } @@ -419,6 +399,152 @@ impl<'de, Enc: Encoding + Default, const N: usize> Visitor<'de> for OrdPathVisit } } +/// A slice of an [`OrdPath`]. +pub struct OrdPathSlice<'a, E: Encoding> { + raw: RawOrdPathSlice<'a>, + enc: &'a E, +} + +impl<'a, E: Encoding> OrdPathSlice<'a, E> { + /// Returns a reference to the used encoding. + #[inline] + pub fn encoding(&self) -> &'a E { + self.enc + } + + /// An iterator over the bytes of an `OrdPathSlice`. + #[inline] + pub fn bytes(&self) -> Bytes { + self.raw.bytes() + } + + /// An iterator over the ordinals of an `OrdPathSlice`. + #[inline] + pub fn ordinals(&self) -> Ordinals { + Ordinals { + reader: Reader::new(self.bytes(), self.encoding()), + } + } + + /// Returns the `OrdPathSlice` without its final element, if there is one. + /// + /// See [`OrdPath::parent()`] for an example. + pub fn parent(&self) -> Option> { + let src = self.bytes(); + if src.is_empty() { + return None; + } + + let mut bits = 0u8; + let mut bytes = 0; + let mut reader = Reader::new(src, self.encoding()); + unsafe { + // SAFETY: Validation of the data happens on creation even for a byte slice. + if let Some((_, stage)) = reader.read().unwrap_unchecked() { + let mut bits_prev = stage.bits(); + while let Some((_, stage)) = reader.read().unwrap_unchecked() { + let bits_tmp = bits + bits_prev; + + bits_prev = stage.bits(); + bits = bits_tmp & 7; + bytes += bits_tmp as usize >> 3; + } + + if bits > 0 || bytes > 0 { + bytes += bits.div_ceil(8) as usize; + bits &= 7; + } + } + } + + Some(Self { + raw: self.raw.take(bytes, (8 - bits) & 7), + enc: self.encoding(), + }) + } + + /// Creates an owned [`OrdPath`] by cloning the data. + pub fn to_path(&self) -> OrdPath + where + E: Clone, + { + let mut bytes = self.bytes(); + let mut path = OrdPath::new(bytes.len(), self.encoding().clone()).unwrap(); + + unsafe { + // SAFETY: The path has the same size as the slice. + bytes.read_exact(path.raw.as_mut_slice()).unwrap_unchecked(); + } + + path + } +} + +impl<'a, E: Encoding + PartialEq> PartialEq for OrdPathSlice<'a, E> { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.encoding().eq(other.encoding()) && self.raw.eq(&other.raw) + } +} + +impl<'a, E: Encoding + PartialEq> PartialOrd for OrdPathSlice<'a, E> { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.encoding() + .eq(other.encoding()) + .then(|| self.bytes().cmp(other.bytes())) + } +} + +impl<'a, E: Encoding> Hash for OrdPathSlice<'a, E> { + #[inline] + fn hash(&self, state: &mut H) { + for b in self.bytes() { + state.write_u8(b); + } + } +} + +impl<'a, E: Encoding> Debug for OrdPathSlice<'a, E> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(self, f) + } +} + +impl<'a, E: Encoding> Display for OrdPathSlice<'a, E> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut ordinals = self.ordinals(); + if let Some(value) = ordinals.next() { + write!(f, "{}", value)?; + for value in ordinals { + write!(f, ".{}", value)?; + } + } + Ok(()) + } +} + +impl<'a, E: Encoding> Binary for OrdPathSlice<'a, E> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Binary::fmt(&self.raw, f) + } +} + +impl<'a, E: Encoding> LowerHex for OrdPathSlice<'a, E> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + LowerHex::fmt(&self.raw, f) + } +} + +impl<'a, E: Encoding> UpperHex for OrdPathSlice<'a, E> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + UpperHex::fmt(&self.raw, f) + } +} + /// An iterator over the ordinals of an [`OrdPath`]. /// /// This struct is created by the [`ordinals`] method on [`OrdPath`]. @@ -611,13 +737,17 @@ mod tests { #[test] fn path_parent() { + fn parent(p: Option) -> Option { + p.and_then(|p| p.parent().and_then(|p| OrdPath::try_from_slice(p).ok())) + } + fn assert(s: &[i64]) { let mut p = Some(::from_ordinals(s, DefaultEncoding)); for i in (0..s.len()).rev() { - p = p.and_then(|p| p.parent()); + p = parent(p); assert_eq!(p, Some(OrdPath::from_ordinals(&s[..i], DefaultEncoding))); } - assert_eq!(p.and_then(|p| p.parent()), None); + assert_eq!(parent(p), None); } assert(&[1, 2]); diff --git a/src/raw.rs b/src/raw.rs index a48daa5..baaa8b0 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -1,6 +1,7 @@ use std::alloc::{self, Layout}; use std::cmp::Ordering; use std::fmt::{Binary, LowerHex, UpperHex}; +use std::io::{Read, Write}; use std::mem::{align_of, size_of, MaybeUninit}; use std::ptr::{addr_of, addr_of_mut, NonNull}; use std::slice; @@ -274,3 +275,155 @@ impl Drop for RawOrdPath { } } } + +pub(crate) struct RawOrdPathSlice<'a> { + data: &'a [u8], + head: u8, + tail: u8, +} + +impl<'a> RawOrdPathSlice<'a> { + pub fn new(data: &'a [u8], head: u8, tail: u8) -> Self { + Self { data, head, tail } + } + + pub fn take(&self, bytes: usize, tail: u8) -> Self { + Self { + data: &self.data[..bytes], + head: self.head, + tail, + } + } + + pub fn bytes(&self) -> Bytes<'a> { + Bytes { + data: self.data, + head: self.head, + tail: self.tail, + } + } +} + +impl<'a> PartialEq for RawOrdPathSlice<'a> { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.cmp(other).is_eq() + } +} + +impl<'a> Eq for RawOrdPathSlice<'a> {} + +impl<'a> PartialOrd for RawOrdPathSlice<'a> { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl<'a> Ord for RawOrdPathSlice<'a> { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.bytes().cmp(other.bytes()) + } +} + +impl<'a> Binary for RawOrdPathSlice<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for b in self.bytes() { + write!(f, "{b:0>8b}")?; + } + Ok(()) + } +} + +impl<'a> LowerHex for RawOrdPathSlice<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for b in self.bytes() { + write!(f, "{b:0>2x}")?; + } + Ok(()) + } +} + +impl<'a> UpperHex for RawOrdPathSlice<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for b in self.bytes() { + write!(f, "{b:0>2X}")?; + } + Ok(()) + } +} + +/// An iterator over the bytes of an `OrdPath` slice. +pub struct Bytes<'a> { + data: &'a [u8], + head: u8, + tail: u8, +} + +impl Bytes<'_> { + /// Returns the length of this `Bytes`. + pub fn len(&self) -> usize { + self.data.len() - (self.head as usize + self.tail as usize).div_euclid(8) + } + + /// Returns `true` if this `Bytes` has a length of zero, and `false` otherwise. + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } +} + +impl Read for Bytes<'_> { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let mut dst = buf; + let mut res = 0; + + loop { + let mut tmp = [0; size_of::()]; + + let len = dst.len().min(tmp.len()); + let len = self.data.read(&mut tmp[..len])?; + + if len == 0 { + break; + } + + let acc = { + let acc = usize::from_be_bytes(tmp) << self.head; + let acc = match self.head { + 0 => acc, + h => { + self.data.read_exact(&mut tmp[..1])?; + acc | (tmp[0] as usize >> (8 - h)) + } + }; + + if self.data.is_empty() { + let used = len as u8 * 8 - self.tail; + let mask = usize::MAX << (64 - used); + acc & mask + } else { + acc + } + }; + + dst.write_all(&acc.to_be_bytes()[..len])?; + res += len; + } + + Ok(res) + } +} + +impl Iterator for Bytes<'_> { + type Item = u8; + + fn next(&mut self) -> Option { + let mut buf = [0; 1]; + if self.read_exact(&mut buf).is_ok() { + Some(buf[0]) + } else { + None + } + } +} From eddb0af32d084868e0fcd25ca17ced5b6a3278cd Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Fri, 10 Jan 2025 22:09:17 +0300 Subject: [PATCH 2/2] Elided lifetimes --- src/enc.rs | 2 +- src/lib.rs | 18 +++++++++--------- src/raw.rs | 14 +++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/enc.rs b/src/enc.rs index b57a5e6..7943f92 100644 --- a/src/enc.rs +++ b/src/enc.rs @@ -69,7 +69,7 @@ impl fmt::Debug for Stage { // TODO: Use field_with when it's stabilized (https://github.com/rust-lang/rust/issues/117729). struct Prefix<'s>(&'s Stage); - impl<'s> fmt::Debug for Prefix<'s> { + impl fmt::Debug for Prefix<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let prefix = self.0.prefix(); let prefix_len = self.0.prefix_bits() as usize; diff --git a/src/lib.rs b/src/lib.rs index 327705b..eb456e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -387,7 +387,7 @@ struct OrdPathVisitor { } #[cfg(feature = "serde")] -impl<'de, Enc: Encoding + Default, const N: usize> Visitor<'de> for OrdPathVisitor { +impl Visitor<'_> for OrdPathVisitor { type Value = OrdPath; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -480,14 +480,14 @@ impl<'a, E: Encoding> OrdPathSlice<'a, E> { } } -impl<'a, E: Encoding + PartialEq> PartialEq for OrdPathSlice<'a, E> { +impl PartialEq for OrdPathSlice<'_, E> { #[inline] fn eq(&self, other: &Self) -> bool { self.encoding().eq(other.encoding()) && self.raw.eq(&other.raw) } } -impl<'a, E: Encoding + PartialEq> PartialOrd for OrdPathSlice<'a, E> { +impl PartialOrd for OrdPathSlice<'_, E> { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.encoding() @@ -496,7 +496,7 @@ impl<'a, E: Encoding + PartialEq> PartialOrd for OrdPathSlice<'a, E> { } } -impl<'a, E: Encoding> Hash for OrdPathSlice<'a, E> { +impl Hash for OrdPathSlice<'_, E> { #[inline] fn hash(&self, state: &mut H) { for b in self.bytes() { @@ -505,13 +505,13 @@ impl<'a, E: Encoding> Hash for OrdPathSlice<'a, E> { } } -impl<'a, E: Encoding> Debug for OrdPathSlice<'a, E> { +impl Debug for OrdPathSlice<'_, E> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::fmt(self, f) } } -impl<'a, E: Encoding> Display for OrdPathSlice<'a, E> { +impl Display for OrdPathSlice<'_, E> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut ordinals = self.ordinals(); if let Some(value) = ordinals.next() { @@ -524,21 +524,21 @@ impl<'a, E: Encoding> Display for OrdPathSlice<'a, E> { } } -impl<'a, E: Encoding> Binary for OrdPathSlice<'a, E> { +impl Binary for OrdPathSlice<'_, E> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Binary::fmt(&self.raw, f) } } -impl<'a, E: Encoding> LowerHex for OrdPathSlice<'a, E> { +impl LowerHex for OrdPathSlice<'_, E> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { LowerHex::fmt(&self.raw, f) } } -impl<'a, E: Encoding> UpperHex for OrdPathSlice<'a, E> { +impl UpperHex for OrdPathSlice<'_, E> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { UpperHex::fmt(&self.raw, f) diff --git a/src/raw.rs b/src/raw.rs index baaa8b0..0a62a4c 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -304,30 +304,30 @@ impl<'a> RawOrdPathSlice<'a> { } } -impl<'a> PartialEq for RawOrdPathSlice<'a> { +impl PartialEq for RawOrdPathSlice<'_> { #[inline] fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() } } -impl<'a> Eq for RawOrdPathSlice<'a> {} +impl Eq for RawOrdPathSlice<'_> {} -impl<'a> PartialOrd for RawOrdPathSlice<'a> { +impl PartialOrd for RawOrdPathSlice<'_> { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl<'a> Ord for RawOrdPathSlice<'a> { +impl Ord for RawOrdPathSlice<'_> { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.bytes().cmp(other.bytes()) } } -impl<'a> Binary for RawOrdPathSlice<'a> { +impl Binary for RawOrdPathSlice<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for b in self.bytes() { write!(f, "{b:0>8b}")?; @@ -336,7 +336,7 @@ impl<'a> Binary for RawOrdPathSlice<'a> { } } -impl<'a> LowerHex for RawOrdPathSlice<'a> { +impl LowerHex for RawOrdPathSlice<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for b in self.bytes() { write!(f, "{b:0>2x}")?; @@ -345,7 +345,7 @@ impl<'a> LowerHex for RawOrdPathSlice<'a> { } } -impl<'a> UpperHex for RawOrdPathSlice<'a> { +impl UpperHex for RawOrdPathSlice<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for b in self.bytes() { write!(f, "{b:0>2X}")?;