singletons 0.1.0

Type-keyed data structures: SingletonSet stores one instance per type, SingletonMap<V> maps types to values
Documentation

This crate provides type-keyed data structures that use Rust types as keys, allowing you to store one value per type.

Data Structures

SingletonSet

A SingletonSet stores at most one value of each type. Think of it as a HashSet where the type of the value is the key.

use singletons::SingletonSet;

let mut set = SingletonSet::new();

// Insert values of different types
set.insert(42u32);
set.insert("hello");
set.insert(3.14f64);

// Each type has its own slot - inserting again replaces the value
set.insert(100u32);  // Replaces 42

// Retrieve values by type
assert_eq!(set.get::<u32>(), &100);
assert_eq!(set.get::<&str>(), &"hello");

// Check if a type is present
assert!(set.contains::<f64>());
assert!(!set.contains::<i32>());

This is useful for creating locally-scoped singletons without polluting the global scope. It ensures there is only one instance of any type, similar to a traditional Singleton pattern, but with proper scoping.

SingletonMap

A SingletonMap<V> maps types to values of a single value type V. Think of it as a HashMap<TypeId, V> with a more ergonomic API.

use singletons::SingletonMap;

let mut descriptions: SingletonMap<&str> = SingletonMap::new();

// Map types to descriptions
descriptions.insert::<u8>("An unsigned 8-bit integer");
descriptions.insert::<i8>("A signed 8-bit integer");
descriptions.insert::<String>("A heap-allocated string");

// Retrieve by type
assert_eq!(descriptions.get::<u8>(), Some(&"An unsigned 8-bit integer"));
assert_eq!(descriptions.get::<bool>(), None);

// Use the entry API for conditional insertion
descriptions.entry::<f64>().or_insert("A 64-bit float");

This is useful when you need to associate metadata, configuration, or handlers with specific types.

Features

  • Type Safety: Leverages Rust's type system to ensure compile-time safety when working with type-keyed collections.
  • Flexible Initialization: Types implementing Default can be auto-initialized, or use explicit values and closures for full control.
  • Scoped Singletons: Unlike global singletons, these collections can be scoped as needed, avoiding global state issues.
  • Insertion Order: Both structures preserve insertion order (backed by IndexMap).

Feature Flags

This crate provides two feature flags, both enabled by default:

  • set - Enables SingletonSet
  • map - Enables SingletonMap

Installation

cargo add singletons

Or add the following to your Cargo.toml:

[dependencies]
singletons = "0.1"

Contributing

Contributions are welcome! Please open an issue or submit a pull request if you have any suggestions, bug reports, or feature requests.

License

Licensed under either of the Apache License, Version 2.0 or the MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.