Skip to main content

domain_key/
lib.rs

1//! # domain-key 🚀
2//!
3//! **High-performance, type-safe, domain-agnostic key system for Rust applications.**
4//!
5//! domain-key provides a flexible and efficient foundation for creating domain-specific keys
6//! with compile-time type safety, runtime validation, and extensive performance optimizations.
7//! This library focuses on zero-cost abstractions and maximum performance through feature-based
8//! optimization profiles.
9//!
10//! ## ✨ Key Features
11//!
12//! - **🔒 Type Safety**: Different key types cannot be mixed at compile time
13//! - **🏎️ High Performance**: Up to 75% performance improvements through advanced optimizations
14//! - **🎯 Domain Agnostic**: No built-in assumptions about specific domains
15//! - **💾 Memory Efficient**: Smart string handling with stack allocation for short keys
16//! - **🛡️ `DoS` Resistant**: Optional protection against `HashDoS` attacks
17//! - **🔧 Extensible**: Easy to add new domains and validation rules
18//! - **📦 Zero-Cost Abstractions**: No runtime overhead for type separation
19//!
20//! ## 🏗️ Architecture Overview
21//!
22//! ```text
23//! ┌─────────────────────────────────────────────────────────────────┐
24//! │                     APPLICATION LAYER                          │
25//! │  Business Logic  │  Domain Models  │  API Endpoints            │
26//! └─────────────────┬───────────────────┬───────────────────────────┘
27//!                   │                   │
28//!                   ▼                   ▼
29//! ┌─────────────────────────────────────────────────────────────────┐
30//! │                   TYPE SAFETY LAYER                            │
31//! │  Key<UserDomain> │ Key<SessionDomain> │ Key<CacheDomain>        │
32//! └─────────────────┬───────────────────────────────────────────────┘
33//!                   │
34//!                   ▼
35//! ┌─────────────────────────────────────────────────────────────────┐
36//! │                 PERFORMANCE LAYER                              │
37//! │  Stack Alloc │ Caching │ Specialized Ops │ Thread-Local        │
38//! └─────────────────┬───────────────────────────────────────────────┘
39//!                   │
40//!                   ▼
41//! ┌─────────────────────────────────────────────────────────────────┐
42//! │                  STORAGE LAYER                                 │
43//! │  SmartString (32 B) + Cached Hash + Borrow<str> Lookup        │
44//! └─────────────────────────────────────────────────────────────────┘
45//! ```
46//!
47//! ## 🚀 Quick Start
48//!
49//! Add to your `Cargo.toml`:
50//!
51//! ```toml
52//! [dependencies]
53//! domain-key = { version = "0.5.2", features = ["fast"] }
54//! ```
55//!
56//! Define a domain and create keys:
57//!
58//! ```rust
59//! use domain_key::{Key, Domain, KeyDomain};
60//!
61//! // 1. Define your domain
62//! #[derive(Debug)]
63//! struct UserDomain;
64//!
65//! impl Domain for UserDomain {
66//!     const DOMAIN_NAME: &'static str = "user";
67//! }
68//!
69//! impl KeyDomain for UserDomain {
70//!     const MAX_LENGTH: usize = 32;
71//!     const TYPICALLY_SHORT: bool = true; // Optimization hint
72//! }
73//!
74//! // 2. Create a type alias
75//! type UserKey = Key<UserDomain>;
76//!
77//! // 3. Use it!
78//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
79//! let user_key = UserKey::new("john_doe")?;
80//! let composed_key = UserKey::from_parts(&["user", "123", "profile"], "_")?;
81//!
82//! println!("Domain: {}", user_key.domain());
83//! println!("Length: {}", user_key.len()); // O(1) with optimizations
84//! println!("Key: {}", user_key.as_str());
85//! # Ok(())
86//! # }
87//! ```
88//!
89//! ## Identifier Types
90//!
91//! domain-key provides four typed identifier wrappers:
92//!
93//! | Type | Storage | Use case |
94//! |------|---------|----------|
95//! | [`Key<D>`] | `SmartString` | Human-readable keys with validation |
96//! | [`Id<D>`] | `NonZeroU64` | Numeric database IDs (8 bytes, `Copy`) |
97//! | [`Uuid<D>`] | `uuid::Uuid` | UUID identifiers (16 bytes, `Copy`, feature `uuid`) |
98//! | [`Ulid<D>`] | `ulid::Ulid` | Prefixed ULIDs (16 bytes, `Copy`, feature `ulid`) |
99//!
100//! ```rust
101//! use domain_key::prelude::*;
102//!
103//! // Numeric IDs
104//! define_id_domain!(UserIdDomain, "user");
105//! id_type!(UserId, UserIdDomain);
106//!
107//! let id = UserId::new(42).unwrap();
108//! assert_eq!(id.get(), 42);
109//!
110//! // Or use the shorthand:
111//! define_id!(OrderIdDomain => OrderId);
112//! let order = OrderId::new(1).unwrap();
113//! ```
114//!
115//! All three types are domain-typed: `UserId` and `OrderId` are incompatible
116//! at compile time even though both wrap a `NonZeroU64`.
117//!
118//! ## Performance Features
119//!
120//! ### Feature-Based Optimization Profiles
121//!
122//! ```toml
123//! # Maximum performance (modern CPUs with AES-NI)
124//! features = ["fast"]
125//!
126//! # DoS protection + good performance
127//! features = ["secure"]
128//!
129//! # Cryptographic security
130//! features = ["crypto"]
131//!
132//! # All optimizations enabled
133//! features = ["fast", "std", "serde"]
134//! ```
135//!
136//! ### Build for Maximum Performance
137//!
138//! ```bash
139//! # Enable CPU-specific optimizations
140//! RUSTFLAGS="-C target-cpu=native" cargo build --release --features="fast"
141//! ```
142//!
143//! ### Performance Improvements
144//!
145//! | Operation | Standard | Optimized | Improvement |
146//! |-----------|----------|-----------|-------------|
147//! | Key Creation (short) | 100% | 128% | **28% faster** |
148//! | String Operations | 100% | 175% | **75% faster** |
149//! | Struct Size | 40 bytes | 32 bytes | **-20% memory** |
150//! | `HashMap` lookup | by Key | by `&str` | **zero-alloc via `Borrow<str>`** |
151//!
152//! ## 📖 Advanced Examples
153//!
154//! ### Performance-Optimized Usage
155//!
156//! ```rust
157//! use domain_key::{Key, Domain, KeyDomain};
158//!
159//! #[derive(Debug)]
160//! struct OptimizedDomain;
161//!
162//! impl Domain for OptimizedDomain {
163//!     const DOMAIN_NAME: &'static str = "optimized";
164//! }
165//!
166//! impl KeyDomain for OptimizedDomain {
167//!     const EXPECTED_LENGTH: usize = 16; // Optimization hint
168//!     const TYPICALLY_SHORT: bool = true; // Enable stack allocation
169//! }
170//!
171//! type OptimizedKey = Key<OptimizedDomain>;
172//!
173//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
174//! // Basic optimized key creation
175//! let user_key = OptimizedKey::new("user_12345")?;
176//! let session_key = OptimizedKey::new("session_abc123")?;
177//!
178//! // Batch operations with from_parts
179//! let user_ids = vec![1, 2, 3, 4, 5];
180//! let user_keys: Result<Vec<_>, _> = user_ids.iter()
181//!     .map(|&id| OptimizedKey::from_parts(&["user", &id.to_string()], "_"))
182//!     .collect();
183//! let user_keys = user_keys?;
184//!
185//! // Optimized operations for repeated use
186//! let key = OptimizedKey::new("user_profile_settings_theme")?;
187//! let parts: Vec<&str> = key.split('_').collect(); // Uses optimizations when available
188//! # Ok(())
189//! # }
190//! ```
191//!
192//! ## 🔧 Feature Flags Reference
193//!
194//! ### Hash Algorithm Features (choose one for best results)
195//!
196//! - `fast` - `GxHash` (40% faster, requires modern CPU with AES-NI)
197//! - `secure` - `AHash` (`DoS` protection, balanced performance)
198//! - `crypto` - Blake3 (cryptographically secure)
199//! - Default - Standard hasher (good compatibility)
200//!
201//! ### Identifier Features
202//!
203//! - `uuid` — enables `Uuid<D>` typed UUID identifiers
204//! - `uuid-v4` — enables `Uuid::new()` random UUID v4 generation
205//! - `uuid-v7` — enables `Uuid::now_v7()` time-ordered generation
206//! - `ulid` — enables [`Ulid<D>`] prefixed ULID identifiers and [`UlidDomain`]
207//! - `ulid-monotonic` — enables [`MonotonicUlidGenerator`] (requires `ulid`, hence `std`)
208//!
209//! ### Core Features
210//!
211//! - `std` - Standard library support (enabled by default)
212//! - `serde` - Serialization support (enabled by default)
213//! - `no_std` - No standard library (disables std-dependent features)
214//!
215//! ## 🛡️ Security Considerations
216//!
217//! domain-key provides multiple levels of security depending on your needs:
218//!
219//! - **`DoS` Protection**: Use `secure` feature for `AHash` with `DoS` resistance
220//! - **Cryptographic Security**: Use `crypto` feature for Blake3 cryptographic hashing
221//! - **Input Validation**: Comprehensive validation pipeline with custom rules
222//! - **Type Safety**: Compile-time prevention of key type mixing
223//! - **Memory Safety**: Rust's ownership system + additional optimizations
224
225#![cfg_attr(not(feature = "std"), no_std)]
226#![warn(missing_docs)]
227#![warn(clippy::missing_safety_doc)]
228#![warn(clippy::undocumented_unsafe_blocks)]
229
230// ============================================================================
231// EXTERNAL DEPENDENCIES
232// ============================================================================
233
234#[cfg(not(feature = "std"))]
235extern crate alloc;
236
237// ============================================================================
238// COMPILE-TIME FEATURE VALIDATION
239// ============================================================================
240
241// Improved feature validation that allows testing with --all-features
242// but warns about suboptimal configurations
243
244#[cfg(all(
245    feature = "fast",
246    feature = "secure",
247    not(test),  // Allow all features during testing
248    not(doc),
249    not(debug_assertions),
250))]
251compile_error!("Both 'fast' and 'secure' features are enabled. For optimal performance, choose only 'fast'. For security, choose only 'secure'.");
252
253#[cfg(all(
254    feature = "fast",
255    feature = "crypto",
256    not(test),  // Allow all features during testing
257    not(doc),
258    not(debug_assertions),
259))]
260compile_error!("Both 'fast' and 'crypto' features are enabled. For optimal performance, choose only 'fast'. For cryptographic security, choose only 'crypto'.");
261
262#[cfg(all(
263    feature = "secure",
264    feature = "crypto",
265    not(test),  // Allow all features during testing
266    not(doc),
267    not(debug_assertions),
268))]
269compile_error!("Both 'secure' and 'crypto' features are enabled. Choose one hash algorithm based on your security requirements.");
270
271// ============================================================================
272// INTERNAL MODULES
273// ============================================================================
274
275pub mod domain;
276pub mod error;
277pub mod id;
278pub mod key;
279pub mod utils;
280pub mod validation;
281pub mod composite_key;
282
283#[cfg(any(feature = "sqlx", feature = "axum", feature = "actix-web"))]
284mod integrations;
285
286#[cfg(feature = "uuid")]
287pub mod uuid;
288
289#[cfg(feature = "ulid")]
290pub mod ulid;
291
292#[cfg(feature = "arbitrary")]
293mod arbitrary_impls;
294
295#[cfg(feature = "proptest")]
296pub mod proptest_impls;
297
298// IMPORTANT: Macros module must be declared but not re-exported with pub use
299// because macros are automatically exported with #[macro_export]
300#[macro_use]
301mod macros;
302
303// ============================================================================
304// PUBLIC RE-EXPORTS
305// ============================================================================
306
307// Core types
308#[cfg(feature = "ulid")]
309pub use domain::UlidDomain;
310#[cfg(feature = "uuid")]
311pub use domain::UuidDomain;
312pub use domain::{
313    domain_info, DefaultDomain, Domain, DomainInfo, IdDomain, IdentifierDomain, KeyDomain,
314    PathDomain,
315};
316#[cfg(feature = "ulid")]
317pub use error::UlidParseError;
318#[cfg(feature = "uuid")]
319pub use error::UuidParseError;
320pub use error::{CompositeKeyParseError, ErrorCategory, IdParseError, KeyParseError};
321pub use id::Id;
322pub use key::Key;
323pub use composite_key::CompositeKey;
324#[cfg(feature = "ulid-monotonic")]
325pub use ulid::MonotonicUlidGenerator;
326#[cfg(feature = "ulid")]
327pub use ulid::Ulid;
328#[cfg(feature = "uuid")]
329pub use uuid::Uuid;
330#[cfg(feature = "proptest")]
331pub use proptest_impls::ProptestKeyDomain;
332/// Error from [`MonotonicUlidGenerator::generate`](crate::MonotonicUlidGenerator::generate) when
333/// ULID random bits would overflow within the same millisecond.
334#[cfg(feature = "ulid-monotonic")]
335pub type UlidMonotonicError = ::ulid::MonotonicError;
336
337// Helper types
338pub use key::{KeyValidationInfo, SplitCache, SplitIterator};
339pub use validation::IntoKey;
340
341// Utility functions
342pub use utils::{hash_algorithm, new_split_cache};
343pub use validation::*;
344
345// Constants
346pub use key::DEFAULT_MAX_KEY_LENGTH;
347
348// Hidden re-exports for macro hygiene (so macros work without caller imports)
349#[doc(hidden)]
350pub mod __private {
351    #[cfg(not(feature = "std"))]
352    pub use alloc::string::ToString;
353    #[cfg(feature = "std")]
354    pub use std::string::ToString;
355
356    #[cfg(not(feature = "std"))]
357    pub use alloc::vec::Vec;
358    #[cfg(feature = "std")]
359    pub use std::vec::Vec;
360}
361
362// Note: Macros are exported automatically by #[macro_export] in macros.rs
363// They don't need to be re-exported here
364
365// ============================================================================
366// CONVENIENCE TYPE ALIASES
367// ============================================================================
368
369/// Result type for key operations
370pub type KeyResult<T> = Result<T, KeyParseError>;
371
372// ============================================================================
373// PRELUDE MODULE
374// ============================================================================
375
376/// Prelude module for convenient imports
377///
378/// This module re-exports the most commonly used types and traits, allowing
379/// users to easily import everything they need with a single `use` statement.
380///
381/// # Examples
382///
383/// ```rust
384/// use domain_key::prelude::*;
385///
386/// #[derive(Debug)]
387/// struct MyDomain;
388///
389/// impl Domain for MyDomain {
390///     const DOMAIN_NAME: &'static str = "my";
391/// }
392/// impl KeyDomain for MyDomain {}
393///
394/// type MyKey = Key<MyDomain>;
395///
396/// let key = MyKey::new("example")?;
397/// # Ok::<(), KeyParseError>(())
398/// ```
399pub mod prelude {
400    pub use crate::{
401        is_valid_key_default, CompositeKey, CompositeKeyParseError, Domain, DomainInfo, ErrorCategory, Id, IdDomain, IdParseError,
402        IntoKey, Key, KeyDomain, KeyParseError, KeyResult, KeyValidationInfo,
403        DEFAULT_MAX_KEY_LENGTH,
404    };
405
406    #[cfg(feature = "uuid")]
407    pub use crate::{Uuid, UuidDomain, UuidParseError};
408
409    #[cfg(feature = "proptest")]
410    pub use crate::ProptestKeyDomain;
411
412    #[cfg(feature = "ulid-monotonic")]
413    pub use crate::{MonotonicUlidGenerator, UlidMonotonicError};
414    #[cfg(feature = "ulid")]
415    pub use crate::{Ulid, UlidDomain, UlidParseError};
416
417    // Re-export the macros in prelude for convenience
418    // Note: These are already available at crate root due to #[macro_export]
419    // but users might want them in prelude
420    #[doc(hidden)]
421    pub use crate::{
422        batch_keys, define_domain, define_id, define_id_domain, id_type, key_type, static_key,
423        test_domain,
424    };
425
426    #[cfg(feature = "uuid")]
427    #[doc(hidden)]
428    pub use crate::{define_uuid, define_uuid_domain, uuid_type};
429
430    #[cfg(feature = "ulid")]
431    #[doc(hidden)]
432    pub use crate::{define_ulid, define_ulid_domain, ulid_type};
433}