use std::{hash::Hash, ptr::NonNull}; /// Wrapper for an interned str pointer, required to /// quickly check using a hash if a string is inside an [`Interner`][`super::Interner`]. /// /// # Safety /// /// This struct could cause Undefined Behaviour on: /// - Use without ensuring the referenced memory is still allocated. /// - Construction of an [`InternedStr`] from an invalid [`NonNull`] pointer. /// - Construction of an [`InternedStr`] from a [`NonNull`] pointer /// without checking if the pointed memory of the [`NonNull`] outlives /// the [`InternedStr`]. /// /// In general, this should not be used outside of an [`Interner`][`super::Interner`]. #[derive(Debug)] pub(super) struct InternedStr { ptr: NonNull<[Char]>, } impl InternedStr { /// Create a new interned string from the given `*const u8` pointer, /// length and encoding kind /// /// # Safety /// /// Not maintaining the invariants specified on the struct definition /// could cause Undefined Behaviour. pub(super) const unsafe fn new(ptr: NonNull<[Char]>) -> Self { Self { ptr } } /// Returns a shared reference to the underlying string. /// /// # Safety /// /// Not maintaining the invariants specified on the struct definition /// could cause Undefined Behaviour. pub(super) unsafe fn as_ref(&self) -> &[Char] { // SAFETY: // The caller must ensure `ptr` is still valid throughout the // lifetime of `self`. unsafe { self.ptr.as_ref() } } } impl Clone for InternedStr { fn clone(&self) -> Self { Self { ptr: self.ptr } } } impl Copy for InternedStr {} impl Eq for InternedStr where Char: Eq {} impl PartialEq for InternedStr where Char: PartialEq, { fn eq(&self, other: &Self) -> bool { // SAFETY: The caller must verify the invariants // specified in the struct definition. unsafe { self.as_ref() == other.as_ref() } } } impl Hash for InternedStr where Char: Hash, { fn hash(&self, state: &mut H) { // SAFETY: // The caller must ensure `ptr` is still valid throughout the // lifetime of `self`. unsafe { self.as_ref().hash(state); } } }