Skip to main content

Interner

Struct Interner 

Source
pub struct Interner<S = FxBuildHasher> {
    pub anys: UnsafeLock<HashMap<TypeId, AnyInternSet, S>>,
    pub dropless: DroplessInterner,
}
Expand description

A generic interner for storing and deduplicating values of various types.

The Interner provides a mechanism to store values in a way that ensures each unique value is stored only once. It supports interning both static types and dropless types, allowing efficient memory usage and fast lookups.

Interning is useful when you need to store many instances of the same value and want to avoid duplication. Instead of storing multiple copies of the same value, the Interner ensures that only one instance of each unique value exists, and all references point to that instance.

§Examples

use any_intern::Interner;

#[derive(PartialEq, Eq, Hash, Debug)]
struct A(u32);

#[derive(PartialEq, Eq, Hash, Debug)]
struct B(String);

let interner = Interner::new();

// Interning integers
let int1 = interner.intern_static(42_u32);
let int2 = interner.intern_static(42_u32);
assert_eq!(int1, int2); // Same value, same reference

// Interning custom structs
let a1 = interner.intern_static(A(1));
let a2 = interner.intern_static(A(1));
assert_eq!(a1, a2); // Same value, same reference

// Interning strings
let b1 = interner.intern_dropless(&*String::from("hello"));
let b2 = interner.intern_dropless(&*String::from("hello"));
assert_eq!(b1, b2); // Same value, same reference

Fields§

§anys: UnsafeLock<HashMap<TypeId, AnyInternSet, S>>

Intern storage for static types.

§dropless: DroplessInterner

Intern storage for dropless types.

Implementations§

Source§

impl Interner

Source

pub fn new() -> Self

Source§

impl<S: BuildHasher> Interner<S>

Source

pub fn intern_static<K: Hash + Eq + 'static>(&self, value: K) -> Interned<'_, K>

Stores a value in the interner, returning a reference to the interned value.

This method inserts the given value into the interner if it does not already exist. If the value already exists, a reference to the existing value is returned.

§Examples
use any_intern::Interner;

#[derive(PartialEq, Eq, Hash, Debug)]
struct A(u32);

#[derive(PartialEq, Eq, Hash, Debug)]
struct B(String);

let interner = Interner::new();

// Interning integers
let int1 = interner.intern_static(42_u32);
let int2 = interner.intern_static(42_u32);
assert_eq!(int1, int2); // Same value, same reference
assert_eq!(int1.raw().as_ptr(), int2.raw().as_ptr());

// Interning custom structs
let a1 = interner.intern_static(A(1));
let a2 = interner.intern_static(A(1));
assert_eq!(a1, a2); // Same value, same reference
assert_eq!(a1.raw().as_ptr(), a2.raw().as_ptr());

// Interning strings
let b1 = interner.intern_static(B("hello".to_string()));
let b2 = interner.intern_static(B("hello".to_string()));
assert_eq!(b1, b2); // Same value, same reference
assert_eq!(b1.raw().as_ptr(), b2.raw().as_ptr());

// Interning different values
let b3 = interner.intern_static(B("world".to_string()));
assert_ne!(b1, b3); // Different values, different references
Source

pub fn intern_static_with<'a, K, Q, F>( &'a self, key: &Q, make_value: F, ) -> Interned<'a, K>
where K: Borrow<Q> + 'static, Q: Hash + Eq + ?Sized, F: FnOnce() -> K,

Stores a value in the interner, creating it only if it does not already exist.

This method allows you to provide a key and a closure to generate the value. If the key already exists in the interner, the closure is not called, and a reference to the existing value is returned. If the key does not exist, the closure is called to create the value, which is then stored in the interner.

This method is useful when the value is expensive to compute, as it avoids unnecessary computation if the value already exists.

§Examples
use any_intern::Interner;

#[derive(PartialEq, Eq, Hash, Debug)]
struct A(u32);

impl std::borrow::Borrow<u32> for A {
    fn borrow(&self) -> &u32 {
        &self.0
    }
}

let interner = Interner::new();

let a = interner.intern_static_with(&42, || A(42));
assert_eq!(interner.len(), 1);
assert_eq!(*a, A(42));

let b = interner.intern_static_with(&42, || A(99)); // Closure is not called
assert_eq!(interner.len(), 1);
assert_eq!(*b, A(42));

let c = interner.intern_static_with(&43, || A(43));
assert_eq!(interner.len(), 2);
assert_eq!(*c, A(43));
Source

pub fn get<K, Q>(&self, key: &Q) -> Option<Interned<'_, K>>
where K: Borrow<Q> + 'static, Q: Hash + Eq + ?Sized,

Retrieves a reference to a value in the interner based on the provided key.

This method checks if a value corresponding to the given key exists in the interner. If it exists, a reference to the interned value is returned. Otherwise, None is returned.

§Examples
use any_intern::Interner;

let interner = Interner::new();
interner.intern_static(42_u32);

assert_eq!(*interner.get::<u32, _>(&42_u32).unwrap(), 42);
assert!(interner.get::<u32, _>(&99_u32).is_none());
Source

pub fn intern_dropless<K: Dropless + ?Sized>( &self, value: &K, ) -> Interned<'_, K>

Stores the given dropless value in the interner then returns reference to the value if the interner doesn’t contain the same value yet.

If the same value exists in the interner, reference to the existing value is returned.

This method does not take the value’s ownership. Instead, it copies the value into the interner’s memory, then returns reference to that.

§Eaxmples
use any_intern::Interner;

let interner = Interner::new();
let a = interner.intern_dropless("hello");
let b = interner.intern_dropless(*Box::new("hello"));
let c = interner.intern_dropless("hi");
assert_eq!(a, b);
assert_ne!(a, c);
Source

pub fn intern_formatted_str<K: Display + ?Sized>( &self, value: &K, upper_size: usize, ) -> Result<Interned<'_, str>, Error>

Stores a value in the interner as a formatted string through Display then returns reference to the value if the interner doesn’t contain the formatted string yet.

If the same string exists in the interner, reference to the existing string is returned.

This method provides a buffer for making string. This will be benefit in terms of performance when you frequently make String via something like to_string() by exploiting chunk memory.

If you give insufficient upper_size, then error is returned.

§Examples
use any_intern::Interner;

let interner = Interner::new();
let value = 42;
let interned = interner.intern_formatted_str(&value, 10).unwrap();

assert_eq!(&*interned, "42");
Source

pub fn get_dropless<K: Dropless + ?Sized>( &self, value: &K, ) -> Option<Interned<'_, K>>

Retrieves a reference to a value in the interner based on the provided key.

This method checks if a value corresponding to the given key exists in the interner. If it exists, a reference to the interned value is returned. Otherwise, None is returned.

§Eaxmples
use any_intern::Interner;

let interner = Interner::new();
interner.intern_dropless("hello");

assert_eq!(interner.get_dropless("hello").as_deref(), Some("hello"));
assert!(interner.get_dropless("hi").is_none());
Source

pub fn len(&self) -> usize

Returns number of values the interner contains.

Source

pub fn is_empty(&self) -> bool

Returns true if the interner is empty.

Source

pub fn clear(&mut self)

Removes all values in the interner.

Although the interner support interior mutability, clear method requires mutable access to the interner to invalidate all Interneds referencing the interner.

Trait Implementations§

Source§

impl<S: Default> Default for Interner<S>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<S> Freeze for Interner<S>

§

impl<S = BuildHasherDefault<FxHasher>> !RefUnwindSafe for Interner<S>

§

impl<S> Send for Interner<S>

§

impl<S> Sync for Interner<S>

§

impl<S> Unpin for Interner<S>

§

impl<S = BuildHasherDefault<FxHasher>> !UnwindSafe for Interner<S>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.