···189189/// for strings of 22 bytes or fewer.
190190pub type DefaultStr = SmolStr;
191191192192+/// Construct `S` from either a borrowed `&'de str` or an owned `SmolStr`.
193193+///
194194+/// Validated string types (Handle, Did, Nsid, etc.) may need to normalise input during
195195+/// deserialization (e.g. lowercasing handles). The normalisation always produces a `SmolStr`,
196196+/// but when the input is already valid the deserializer wants to borrow directly from the
197197+/// input buffer. This trait provides the two construction paths so that a single custom
198198+/// deserialize visitor can produce any backing type.
199199+pub trait StrConsumer<'de, 'r>: Bos<str> + Sized {
200200+ /// Construct from a borrowed string slice (zero-copy path).
201201+ fn from_borrowed_str(s: &'de str) -> Self;
202202+203203+ /// Construct from an owned `SmolStr` (normalisation/allocation path).
204204+ fn from_smolstr(s: &'r SmolStr) -> Self;
205205+}
206206+207207+impl<'de, 'r> StrConsumer<'de, 'r> for SmolStr {
208208+ #[inline]
209209+ fn from_borrowed_str(s: &'de str) -> Self {
210210+ SmolStr::new(s)
211211+ }
212212+213213+ #[inline]
214214+ fn from_smolstr(s: &'r SmolStr) -> Self {
215215+ s.clone()
216216+ }
217217+}
218218+219219+impl<'de, 'r> StrConsumer<'de, 'r> for String {
220220+ #[inline]
221221+ fn from_borrowed_str(s: &'de str) -> Self {
222222+ s.into()
223223+ }
224224+225225+ #[inline]
226226+ fn from_smolstr(s: &'r SmolStr) -> Self {
227227+ s.clone().into()
228228+ }
229229+}
230230+231231+impl<'de, 'r> StrConsumer<'de, 'r> for &'de str
232232+where
233233+ 'r: 'de,
234234+{
235235+ #[inline]
236236+ fn from_borrowed_str(s: &'de str) -> Self {
237237+ s
238238+ }
239239+240240+ #[inline]
241241+ fn from_smolstr(s: &'r SmolStr) -> Self {
242242+ s.as_str()
243243+ }
244244+}
245245+246246+impl<'de, 'r> StrConsumer<'de, 'r> for CowStr<'de> {
247247+ #[inline]
248248+ fn from_borrowed_str(s: &'de str) -> Self {
249249+ CowStr::Borrowed(s)
250250+ }
251251+252252+ #[inline]
253253+ fn from_smolstr(s: &'r SmolStr) -> Self {
254254+ CowStr::Owned(s.clone())
255255+ }
256256+}
257257+192258#[cfg(test)]
193259mod tests {
194260 use super::*;
+1-1
crates/jacquard-common/src/lib.rs
···214214215215pub use cowstr::CowStr;
216216pub use into_static::IntoStatic;
217217-pub use bos::{Bos, BorrowOrShare, DefaultStr};
217217+pub use bos::{Bos, BorrowOrShare, DefaultStr, StrConsumer};
218218219219/// A copy-on-write immutable string type that uses [`smol_str::SmolStr`] for
220220/// the "owned" variant.