/// A 24-bit numeric data type that is expected to be a Unicode scalar value, but is not /// validated as such. /// /// Use this type instead of `char` when you want to deal with data that is expected to be valid /// Unicode scalar values, but you want control over when or if you validate that assumption. /// /// # Examples /// /// ``` /// use potential_utf::PotentialCodePoint; /// /// assert_eq!(PotentialCodePoint::from_u24(0x68).try_to_char(), Ok('h')); /// assert_eq!(PotentialCodePoint::from_char('i').try_to_char(), Ok('i')); /// assert_eq!( /// PotentialCodePoint::from_u24(0x1F44B).try_to_char(), /// Ok('') /// ); /// /// assert!(PotentialCodePoint::from_u24(0xDE01).try_to_char().is_err()); /// assert_eq!( /// PotentialCodePoint::from_u24(0xDE01).to_char_lossy(), /// char::REPLACEMENT_CHARACTER /// ); /// ``` #[repr(transparent)] #[allow(clippy::exhaustive_structs)] // transparent newtype #[derive(PartialEq, Eq, Clone, Copy, Hash)] pubstruct PotentialCodePoint([u8; 3]);
impl PotentialCodePoint { /// Create a [`PotentialCodePoint`] from a `char`. /// /// # Examples /// /// ``` /// use potential_utf::PotentialCodePoint; /// /// let a = PotentialCodePoint::from_char('a'); /// assert_eq!(a.try_to_char().unwrap(), 'a'); /// ``` #[inline] pubconstfn from_char(c: char) -> Self { let [u0, u1, u2, _u3] = (c as u32).to_le_bytes(); Self([u0, u1, u2])
}
/// Create [`PotentialCodePoint`] from a u32 value, ignoring the most significant 8 bits. #[inline] pubconstfn from_u24(c: u32) -> Self { let [u0, u1, u2, _u3] = c.to_le_bytes(); Self([u0, u1, u2])
}
/// Attempt to convert a [`PotentialCodePoint`] to a `char`. /// /// # Examples /// /// ``` /// use potential_utf::PotentialCodePoint; /// use zerovec::ule::AsULE; /// /// let a = PotentialCodePoint::from_char('a'); /// assert_eq!(a.try_to_char(), Ok('a')); /// /// let b = PotentialCodePoint::from_unaligned([0xFF, 0xFF, 0xFF].into()); /// assert!(b.try_to_char().is_err()); /// ``` #[inline] pubfn try_to_char(self) -> Result<char, core::char::CharTryFromError> {
char::try_from(u32::from(self))
}
/// Convert a [`PotentialCodePoint`] to a `char', returning [`char::REPLACEMENT_CHARACTER`] /// if the `PotentialCodePoint` does not represent a valid Unicode scalar value. /// /// # Examples /// /// ``` /// use potential_utf::PotentialCodePoint; /// use zerovec::ule::AsULE; /// /// let a = PotentialCodePoint::from_unaligned([0xFF, 0xFF, 0xFF].into()); /// assert_eq!(a.to_char_lossy(), char::REPLACEMENT_CHARACTER); /// ``` #[inline] pubfn to_char_lossy(self) -> char { self.try_to_char().unwrap_or(char::REPLACEMENT_CHARACTER)
}
/// Convert a [`PotentialCodePoint`] to a `char` without checking that it is /// a valid Unicode scalar value. /// /// # Safety /// /// The `PotentialCodePoint` must be a valid Unicode scalar value in little-endian order. /// /// # Examples /// /// ``` /// use potential_utf::PotentialCodePoint; /// /// let a = PotentialCodePoint::from_char('a'); /// assert_eq!(unsafe { a.to_char_unchecked() }, 'a'); /// ``` #[inline] pubunsafefn to_char_unchecked(self) -> char {
char::from_u32_unchecked(u32::from(self))
}
/// For converting to the ULE type in a const context /// /// Can be removed once const traits are a thing #[inline] #[cfg(feature = "zerovec")] pubconstfn to_unaligned(self) -> zerovec::ule::RawBytesULE<3> {
zerovec::ule::RawBytesULE(self.0)
}
}
/// This impl requires enabling the optional `zerovec` Cargo feature #[cfg(feature = "zerovec")] impl zerovec::ule::AsULE for PotentialCodePoint { type ULE = zerovec::ule::RawBytesULE<3>;
// Safety: PotentialCodePoint is always the little-endian representation of a char, // which corresponds to its AsULE::ULE type /// This impl requires enabling the optional `zerovec` Cargo feature #[cfg(feature = "zerovec")] unsafeimpl zerovec::ule::EqULE for PotentialCodePoint {}
impl fmt::Debug for PotentialCodePoint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Debug as a char if possible matchself.try_to_char() {
Ok(c) => fmt::Debug::fmt(&c, f),
Err(_) => fmt::Debug::fmt(&self.0, f),
}
}
}
impl Ord for PotentialCodePoint { // custom implementation, as derived Ord would compare lexicographically fn cmp(&self, other: &Self) -> Ordering { let a = u32::from(*self); let b = u32::from(*other);
a.cmp(&b)
}
}
// backed by [PotentialCodePoint] let uvchars: Vec<_> = chars
.iter()
.copied()
.map(PotentialCodePoint::from_char)
.collect(); // backed by [RawBytesULE<3>] let zvec: ZeroVec<_> = uvchars.clone().into_iter().collect();
let ule_bytes = zvec.as_bytes(); let uvbytes; unsafe { let ptr = &uvchars[..] as *const _ as *const u8;
uvbytes = core::slice::from_raw_parts(ptr, ule_bytes.len());
}
// PotentialCodePoint is defined as little-endian, so this must be true on all platforms // also asserts that to_unaligned/from_unaligned are no-ops
assert_eq!(uvbytes, ule_bytes);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.