diff --git a/crates/jacquard-common/src/bos.rs b/crates/jacquard-common/src/bos.rs index e23263ce..aa2076b7 100644 --- a/crates/jacquard-common/src/bos.rs +++ b/crates/jacquard-common/src/bos.rs @@ -189,6 +189,72 @@ impl<'a> Bos for CowStr<'a> { /// for strings of 22 bytes or fewer. pub type DefaultStr = SmolStr; +/// Construct `S` from either a borrowed `&'de str` or an owned `SmolStr`. +/// +/// Validated string types (Handle, Did, Nsid, etc.) may need to normalise input during +/// deserialization (e.g. lowercasing handles). The normalisation always produces a `SmolStr`, +/// but when the input is already valid the deserializer wants to borrow directly from the +/// input buffer. This trait provides the two construction paths so that a single custom +/// deserialize visitor can produce any backing type. +pub trait StrConsumer<'de, 'r>: Bos + Sized { + /// Construct from a borrowed string slice (zero-copy path). + fn from_borrowed_str(s: &'de str) -> Self; + + /// Construct from an owned `SmolStr` (normalisation/allocation path). + fn from_smolstr(s: &'r SmolStr) -> Self; +} + +impl<'de, 'r> StrConsumer<'de, 'r> for SmolStr { + #[inline] + fn from_borrowed_str(s: &'de str) -> Self { + SmolStr::new(s) + } + + #[inline] + fn from_smolstr(s: &'r SmolStr) -> Self { + s.clone() + } +} + +impl<'de, 'r> StrConsumer<'de, 'r> for String { + #[inline] + fn from_borrowed_str(s: &'de str) -> Self { + s.into() + } + + #[inline] + fn from_smolstr(s: &'r SmolStr) -> Self { + s.clone().into() + } +} + +impl<'de, 'r> StrConsumer<'de, 'r> for &'de str +where + 'r: 'de, +{ + #[inline] + fn from_borrowed_str(s: &'de str) -> Self { + s + } + + #[inline] + fn from_smolstr(s: &'r SmolStr) -> Self { + s.as_str() + } +} + +impl<'de, 'r> StrConsumer<'de, 'r> for CowStr<'de> { + #[inline] + fn from_borrowed_str(s: &'de str) -> Self { + CowStr::Borrowed(s) + } + + #[inline] + fn from_smolstr(s: &'r SmolStr) -> Self { + CowStr::Owned(s.clone()) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/jacquard-common/src/lib.rs b/crates/jacquard-common/src/lib.rs index 3d050eea..069fd4dc 100644 --- a/crates/jacquard-common/src/lib.rs +++ b/crates/jacquard-common/src/lib.rs @@ -214,7 +214,7 @@ pub use spin::Lazy; pub use cowstr::CowStr; pub use into_static::IntoStatic; -pub use bos::{Bos, BorrowOrShare, DefaultStr}; +pub use bos::{Bos, BorrowOrShare, DefaultStr, StrConsumer}; /// A copy-on-write immutable string type that uses [`smol_str::SmolStr`] for /// the "owned" variant.