pub struct Key<T: KeyDomain> { /* private fields */ }Expand description
High-performance generic key type with advanced optimizations
This is the core key type that provides type safety through the domain
marker T. Keys are immutable after creation and use SmartString for
optimal memory usage (stack allocation for short keys, heap for longer ones).
§Performance Characteristics
- Memory Layout: 32 bytes total (fits in single cache line)
- Hash Access: O(1) via pre-computed hash
- Length Access: O(1) via cached length field
- String Access: Direct reference to internal storage
- Clone: Efficient via
SmartString’s copy-on-write semantics
§Type Parameters
T- A domain marker type that implementsKeyDomain
§Memory Layout
Key<T> struct (32 bytes, cache-line friendly):
┌─────────────────────┬──────────┬─────────┬─────────────┐
│ SmartString (24B) │ hash (8B)│ len (4B)│ marker (0B) │
└─────────────────────┴──────────┴─────────┴─────────────┘Keys use SmartString which stores strings up to 23 bytes inline on the stack,
only allocating on the heap for longer strings. Additionally, the pre-computed
hash is stored for O(1) hash operations.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct UserDomain;
impl Domain for UserDomain {
const DOMAIN_NAME: &'static str = "user";
}
impl KeyDomain for UserDomain {
const MAX_LENGTH: usize = 32;
}
type UserKey = Key<UserDomain>;
let key = UserKey::new("john_doe")?;
assert_eq!(key.as_str(), "john_doe");
assert_eq!(key.domain(), "user");
assert_eq!(key.len(), 8);Implementations§
Source§impl<T: KeyDomain> Key<T>
impl<T: KeyDomain> Key<T>
Sourcepub fn new(key: impl AsRef<str>) -> Result<Self, KeyParseError>
pub fn new(key: impl AsRef<str>) -> Result<Self, KeyParseError>
Creates a new key with comprehensive validation and optimization
This method performs both common validation (length, characters) and domain-specific validation according to the key’s domain type. It automatically chooses the optimal creation path based on the input characteristics and domain configuration.
§Arguments
key- String-like input that will be normalized and validated
§Returns
Ok(Key<T>)if the key is validErr(KeyParseError)with the specific validation failure
§Errors
Returns KeyParseError if the key fails common validation (empty, too
long, invalid characters) or domain-specific validation rules
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("valid_key")?;
assert_eq!(key.as_str(), "valid_key");
// Invalid keys return descriptive errors
let error = TestKey::new("").unwrap_err();
assert!(matches!(error, domain_key::KeyParseError::Empty));Sourcepub fn from_string(key: String) -> Result<Self, KeyParseError>
pub fn from_string(key: String) -> Result<Self, KeyParseError>
Creates a new key from an owned String with optimized handling
This method is more efficient when you already have a String as it
can reuse the allocation when possible.
§Arguments
key- Owned string that will be normalized and validated
§Errors
Returns KeyParseError if the key fails validation
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key_string = "test_key".to_string();
let key = TestKey::from_string(key_string)?;
assert_eq!(key.as_str(), "test_key");Sourcepub fn from_parts(
parts: &[&str],
delimiter: &str,
) -> Result<Self, KeyParseError>
pub fn from_parts( parts: &[&str], delimiter: &str, ) -> Result<Self, KeyParseError>
Create a key from multiple parts separated by a delimiter
This method efficiently constructs a key from multiple string parts, using pre-calculated sizing to minimize allocations.
§Arguments
parts- Array of string parts to joindelimiter- String to use as separator between parts
§Returns
Ok(Key<T>)if the constructed key is validErr(KeyParseError)if validation fails
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::from_parts(&["user", "123", "profile"], "_")?;
assert_eq!(key.as_str(), "user_123_profile");§Errors
Returns KeyParseError if the constructed key fails validation
Sourcepub fn try_from_parts(parts: &[&str], delimiter: &str) -> Option<Self>
pub fn try_from_parts(parts: &[&str], delimiter: &str) -> Option<Self>
Try to create a key from multiple parts, returning None on failure
This is a convenience method for when you want to handle validation failures by ignoring invalid keys rather than handling errors.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let valid = TestKey::try_from_parts(&["user", "123"], "_").unwrap();
let invalid = TestKey::try_from_parts(&["", ""], "_"); // Returns None
assert!(invalid.is_none());Sourcepub fn from_static_unchecked(key: &'static str) -> Self
pub fn from_static_unchecked(key: &'static str) -> Self
Creates a key from a static string without runtime validation
§Warning
The caller must ensure that the static string follows all validation rules for the domain (allowed characters, length limits, normalization, domain-specific rules). Invalid keys created this way will violate internal invariants and may cause unexpected behavior.
Prefer try_from_static or the static_key! macro
for safe creation of static keys.
§Panics
Panics in debug builds if the key is empty or exceeds u32::MAX length.
§Arguments
key- A static string literal that represents a valid key
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::from_static_unchecked("static_key");
assert_eq!(key.as_str(), "static_key");Sourcepub fn try_from_static(key: &'static str) -> Result<Self, KeyParseError>
pub fn try_from_static(key: &'static str) -> Result<Self, KeyParseError>
Creates a key from a static string with validation
This is a safer alternative to from_static_unchecked that validates
the key at runtime. The validation cost is paid once, and subsequent
uses of the key are as fast as the unchecked version.
§Arguments
key- A static string literal to validate and convert
§Errors
Returns KeyParseError if the static key fails validation
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::try_from_static("static_key")?;
assert_eq!(key.as_str(), "static_key");
let invalid = TestKey::try_from_static("");
assert!(invalid.is_err());§Errors
Returns KeyParseError if the constructed key fails validation
Sourcepub fn try_new(key: impl AsRef<str>) -> Option<Self>
pub fn try_new(key: impl AsRef<str>) -> Option<Self>
Try to create a key, returning None on validation failure
This is a convenience method for when you want to handle validation failures by ignoring invalid keys rather than handling errors.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let valid = TestKey::try_new("valid_key").unwrap();
let invalid = TestKey::try_new(""); // Returns None
assert!(invalid.is_none());Source§impl<T: KeyDomain> Key<T>
impl<T: KeyDomain> Key<T>
Sourcepub fn as_str(&self) -> &str
pub fn as_str(&self) -> &str
Returns the key as a string slice
This is the primary way to access the string content of a key. The returned reference is valid for the lifetime of the key.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("example")?;
assert_eq!(key.as_str(), "example");Sourcepub const fn domain(&self) -> &'static str
pub const fn domain(&self) -> &'static str
Returns the domain name for this key type
This is a compile-time constant that identifies which domain this key belongs to.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct UserDomain;
impl Domain for UserDomain {
const DOMAIN_NAME: &'static str = "user";
}
impl KeyDomain for UserDomain {}
type UserKey = Key<UserDomain>;
let key = UserKey::new("john")?;
assert_eq!(key.domain(), "user");Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the length of the key string
This is an O(1) operation using a cached length value.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("example")?;
assert_eq!(key.len(), 7);Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns true if the key is empty (this should never happen for valid keys)
Since empty keys are rejected during validation, this method should
always return false for properly constructed keys. It’s provided
for completeness and debugging purposes.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("example")?;
assert!(!key.is_empty());Sourcepub const fn hash(&self) -> u64
pub const fn hash(&self) -> u64
Returns the cached hash value
This hash is computed once during key creation and cached for the lifetime of the key. It’s used internally for hash-based collections and can be useful for custom hash-based data structures.
Note: The hash algorithm depends on the active feature flags
(fast, secure, crypto, or the default hasher). Keys created
with different feature configurations will produce different hash
values. Do not persist or compare hash values across builds with
different features.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key1 = TestKey::new("example")?;
let key2 = TestKey::new("example")?;
let key3 = TestKey::new("different")?;
// Same keys have same hash
assert_eq!(key1.hash(), key2.hash());
// Different keys have different hashes (with high probability)
assert_ne!(key1.hash(), key3.hash());Sourcepub fn starts_with(&self, prefix: &str) -> bool
pub fn starts_with(&self, prefix: &str) -> bool
Checks if this key starts with the given prefix
This is a simple string prefix check that can be useful for categorizing or filtering keys.
§Arguments
prefix- The prefix string to check for
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("user_profile")?;
assert!(key.starts_with("user_"));
assert!(!key.starts_with("admin_"));Sourcepub fn ends_with(&self, suffix: &str) -> bool
pub fn ends_with(&self, suffix: &str) -> bool
Checks if this key ends with the given suffix
This is a simple string suffix check that can be useful for categorizing or filtering keys.
§Arguments
suffix- The suffix string to check for
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("user_profile")?;
assert!(key.ends_with("_profile"));
assert!(!key.ends_with("_settings"));Sourcepub fn contains(&self, pattern: &str) -> bool
pub fn contains(&self, pattern: &str) -> bool
Checks if this key contains the given substring
This performs a substring search within the key.
§Arguments
pattern- The substring to search for
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("user_profile_settings")?;
assert!(key.contains("profile"));
assert!(!key.contains("admin"));Sourcepub fn chars(&self) -> Chars<'_>
pub fn chars(&self) -> Chars<'_>
Returns an iterator over the characters of the key
This provides access to individual characters in the key string.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("abc")?;
let chars: Vec<char> = key.chars().collect();
assert_eq!(chars, vec!['a', 'b', 'c']);Sourcepub fn split(&self, delimiter: char) -> SplitIterator<'_> ⓘ
pub fn split(&self, delimiter: char) -> SplitIterator<'_> ⓘ
Splits the key by a delimiter and returns an iterator
This method provides consistent split functionality.
§Arguments
delimiter- Character to split on
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("user_profile_settings")?;
let parts: Vec<&str> = key.split('_').collect();
assert_eq!(parts, vec!["user", "profile", "settings"]);Sourcepub fn split_cached(&self, delimiter: char) -> SplitCache<'_>
pub fn split_cached(&self, delimiter: char) -> SplitCache<'_>
Split operation for consistent API
This method provides the same functionality as split() but with explicit naming
for cases where caching behavior needs to be clear.
Sourcepub fn split_str<'a>(&'a self, delimiter: &'a str) -> Split<'a, &'a str> ⓘ
pub fn split_str<'a>(&'a self, delimiter: &'a str) -> Split<'a, &'a str> ⓘ
Splits the key by a string delimiter and returns an iterator
This method splits the key using a string pattern rather than a single character.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("user-and-profile-and-settings")?;
let parts: Vec<&str> = key.split_str("-and-").collect();
assert_eq!(parts, vec!["user", "profile", "settings"]);Sourcepub fn ensure_prefix(&self, prefix: &str) -> Result<Self, KeyParseError>
pub fn ensure_prefix(&self, prefix: &str) -> Result<Self, KeyParseError>
Returns the key with a prefix if it doesn’t already have it
This method efficiently adds a prefix to a key if it doesn’t already start with that prefix.
§Arguments
prefix- The prefix to ensure is present
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("profile")?;
let prefixed = key.ensure_prefix("user_")?;
assert_eq!(prefixed.as_str(), "user_profile");
// If prefix already exists, returns the same key
let already_prefixed = prefixed.ensure_prefix("user_")?;
assert_eq!(already_prefixed.as_str(), "user_profile");§Errors
Returns KeyParseError if the prefixed key would be invalid or too long
Sourcepub fn ensure_suffix(&self, suffix: &str) -> Result<Self, KeyParseError>
pub fn ensure_suffix(&self, suffix: &str) -> Result<Self, KeyParseError>
Returns the key with a suffix if it doesn’t already have it
This method efficiently adds a suffix to a key if it doesn’t already end with that suffix.
§Arguments
suffix- The suffix to ensure is present
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {}
type TestKey = Key<TestDomain>;
let key = TestKey::new("user")?;
let suffixed = key.ensure_suffix("_profile")?;
assert_eq!(suffixed.as_str(), "user_profile");
// If suffix already exists, returns the same key
let already_suffixed = suffixed.ensure_suffix("_profile")?;
assert_eq!(already_suffixed.as_str(), "user_profile");§Errors
Returns KeyParseError if the prefixed key would be invalid or too long
Sourcepub fn validation_info(&self) -> KeyValidationInfo
pub fn validation_info(&self) -> KeyValidationInfo
Get validation rules that this key satisfies
Returns detailed information about the validation characteristics of this key and its domain, useful for debugging and introspection.
§Examples
use domain_key::{Key, Domain, KeyDomain};
#[derive(Debug)]
struct TestDomain;
impl Domain for TestDomain {
const DOMAIN_NAME: &'static str = "test";
}
impl KeyDomain for TestDomain {
const MAX_LENGTH: usize = 32;
const HAS_CUSTOM_VALIDATION: bool = true;
}
type TestKey = Key<TestDomain>;
let key = TestKey::new("example")?;
let info = key.validation_info();
assert_eq!(info.domain_info.name, "test");
assert_eq!(info.domain_info.max_length, 32);
assert_eq!(info.length, 7);
assert!(info.domain_info.has_custom_validation);Trait Implementations§
Source§impl<T: KeyDomain> Clone for Key<T>
impl<T: KeyDomain> Clone for Key<T>
Source§fn clone(&self) -> Self
fn clone(&self) -> Self
Efficient clone implementation
Cloning a key is efficient due to SmartString’s optimizations:
- For inline strings (≤23 chars): Simple memory copy
- For heap strings: Reference counting or copy-on-write
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<'de, T: KeyDomain> Deserialize<'de> for Key<T>
Available on crate feature serde only.
impl<'de, T: KeyDomain> Deserialize<'de> for Key<T>
serde only.Source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Deserialize and validate a key from its string representation
This implementation chooses the optimal deserialization strategy based on the format (human-readable vs binary) for best performance.
Source§impl<T: KeyDomain> Display for Key<T>
Display implementation shows the key value
impl<T: KeyDomain> Display for Key<T>
Display implementation shows the key value
Outputs just the key string, consistent with AsRef<str>, From<Key<T>> for String,
and serde serialization. Use Key::domain separately when domain context is needed.
Source§impl<T: KeyDomain> Hash for Key<T>
impl<T: KeyDomain> Hash for Key<T>
Source§impl<T: KeyDomain> Ord for Key<T>
impl<T: KeyDomain> Ord for Key<T>
Source§impl<T: KeyDomain> PartialOrd for Key<T>
impl<T: KeyDomain> PartialOrd for Key<T>
Source§impl<T: KeyDomain> TryFrom<&str> for Key<T>
TryFrom<&str> implementation for borrowed string conversion
impl<T: KeyDomain> TryFrom<&str> for Key<T>
TryFrom<&str> implementation for borrowed string conversion
Source§impl<T: KeyDomain> TryFrom<String> for Key<T>
TryFrom<String> implementation for owned string conversion
impl<T: KeyDomain> TryFrom<String> for Key<T>
TryFrom<String> implementation for owned string conversion
This avoids re-borrowing through &str when you already have a String.