1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
#![cfg_attr(feature = "no-std", no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(feature = "inline-more", warn(clippy::missing_inline_in_public_items))]
// `.copied()` was unstable in 1.34
#![allow(clippy::map_clone)]
#![deny(
missing_docs,
missing_debug_implementations,
clippy::missing_safety_doc
)]
//! [![CI][1]][0]
//! [![Security Audit][2]][0]
//! [![Coverage][3]][4]
//! [![LoC][5]][0]
//! [![Docs.rs][6]][7]
//! [![Crates.io][8]][9]
//!
//! A multithreaded and single threaded string interner that allows strings to be cached with a minimal memory footprint,
//! associating them with a unique [key] that can be used to retrieve them at any time. A [`struct@Rodeo`] allows `O(1)`
//! internment and resolution and can be turned into a [`struct@RodeoReader`] to allow for contention-free resolutions
//! with both key to str and str to key operations. It can also be turned into a [`struct@RodeoResolver`] with only
//! key to str operations for the lowest possible memory usage.
//!
//! ## Which interner do I use?
//!
//! For single-threaded workloads [`struct@Rodeo`] is encouraged, while multi-threaded applications should use [`struct@ThreadedRodeo`].
//! Both of these are the only way to intern strings, but most applications will hit a stage where they are done interning
//! strings, and at that point is where the choice between [`struct@RodeoReader`] and [`struct@RodeoResolver`]. If the user needs to get
//! keys for strings still, then they must use the [`struct@RodeoReader`] (although they can still transfer into a [`struct@RodeoResolver`])
//! at this point. For users who just need key to string resolution, the [`struct@RodeoResolver`] gives contention-free access at the
//! minimum possible memory usage. Note that to gain access to [`struct@ThreadedRodeo`] the `multi-threaded` feature is required.
//!
//! | Interner | Thread-safe | Intern String | str to key | key to str | Contention Free | Memory Usage |
//! |-------------------|:-----------:|:-------------:|:----------:|:----------:|:---------------:|:------------:|
//! | [`struct@Rodeo`] | ❌ | ✅ | ✅ | ✅ | N/A | Medium |
//! | [`struct@ThreadedRodeo`] | ✅ | ✅ | ✅ | ✅ | ❌ | Most |
//! | [`struct@RodeoReader`] | ✅ | ❌ | ✅ | ✅ | ✅ | Medium |
//! | [`struct@RodeoResolver`] | ✅ | ❌ | ❌ | ✅ | ✅ | Least |
//!
//! ## Cargo Features
//!
//! By default `lasso` has one dependency, `hashbrown`, and only [`struct@Rodeo`] is exposed. Hashbrown is used since the
//! [`raw_entry` api] is currently unstable in the standard library's hashmap.
//! The raw hashmap API is used for custom hashing within the hashmaps, which works to dramatically reduce memory usage
//! To make use of [`struct@ThreadedRodeo`], you must enable the `multi-threaded` feature.
//!
//! * `multi-threaded` - Enables [`struct@ThreadedRodeo`], the interner for multi-threaded tasks
//! * `ahasher` - Use [`ahash`]'s `RandomState` as the default hasher
//! * `no-std` - Enables `no_std` + `alloc` support for [`struct@Rodeo`] and [`struct@ThreadedRodeo`]
//! * Automatically enables the following required features:
//! * `ahasher` - `no_std` hashing function
//! * `serialize` - Implements `Serialize` and `Deserialize` for all [`struct@Spur`] types and all interners
//! * `inline-more` - Annotate external apis with `#[inline]`
//!
//! ## Example: Using Rodeo
//!
//! ```rust
//! use lasso::Rodeo;
//!
//! let mut rodeo = Rodeo::default();
//! let key = rodeo.get_or_intern("Hello, world!");
//!
//! // Easily retrieve the value of a key and find the key for values
//! assert_eq!("Hello, world!", rodeo.resolve(&key));
//! assert_eq!(Some(key), rodeo.get("Hello, world!"));
//!
//! // Interning the same string again will yield the same key
//! let key2 = rodeo.get_or_intern("Hello, world!");
//!
//! assert_eq!(key, key2);
//! ```
//!
//! ## Example: Using ThreadedRodeo
//!
//! ```rust
//! # // This keeps this doctest from running under miri since
//! # // miri doesn't support threading
//! # #[cfg(not(miri))]
//! # {
//! #
//! # // This is hacky to the extreme, but it prevents failure of this doc test when
//! # // run with `--no-default-features`
//! #
//! # #[cfg(not(feature = "multi-threaded"))]
//! # #[derive(Default)]
//! # struct ThreadedRodeo;
//! #
//! # #[cfg(not(feature = "multi-threaded"))]
//! # impl ThreadedRodeo {
//! # fn get_or_intern(&self, string: &'static str) -> i32 {
//! # match string {
//! # "Hello, world!" => 0,
//! # "Hello from the thread!" => 1,
//! # _ => unreachable!("Update the docs, dude"),
//! # }
//! # }
//! #
//! # fn get(&self, string: &'static str) -> Option<i32> {
//! # match string {
//! # "Hello, world!" => Some(0),
//! # "Hello from the thread!" => Some(1),
//! # _ => unreachable!("Update the docs, dude"),
//! # }
//! # }
//! #
//! # fn resolve(&self, id: &i32) -> &'static str {
//! # match *id {
//! # 0 => "Hello, world!",
//! # 1 => "Hello from the thread!",
//! # _ => unreachable!("Update the docs, dude"),
//! # }
//! # }
//! # }
//! #
//! # #[cfg(feature = "multi-threaded")]
//! use lasso::ThreadedRodeo;
//! use std::{thread, sync::Arc};
//!
//! let rodeo = Arc::new(ThreadedRodeo::default());
//! let key = rodeo.get_or_intern("Hello, world!");
//!
//! // Easily retrieve the value of a key and find the key for values
//! assert_eq!("Hello, world!", rodeo.resolve(&key));
//! assert_eq!(Some(key), rodeo.get("Hello, world!"));
//!
//! // Interning the same string again will yield the same key
//! let key2 = rodeo.get_or_intern("Hello, world!");
//!
//! assert_eq!(key, key2);
//!
//! // ThreadedRodeo can be shared across threads
//! let moved = Arc::clone(&rodeo);
//! let hello = thread::spawn(move || {
//! assert_eq!("Hello, world!", moved.resolve(&key));
//! moved.get_or_intern("Hello from the thread!")
//! })
//! .join()
//! .unwrap();
//!
//! assert_eq!("Hello, world!", rodeo.resolve(&key));
//! assert_eq!("Hello from the thread!", rodeo.resolve(&hello));
//! # }
//! ```
//!
//! ## Example: Creating a RodeoReader
//!
//! ```rust
//! use lasso::Rodeo;
//!
//! // Rodeo and ThreadedRodeo are interchangeable here
//! let mut rodeo = Rodeo::default();
//!
//! let key = rodeo.get_or_intern("Hello, world!");
//! assert_eq!("Hello, world!", rodeo.resolve(&key));
//!
//! let reader = rodeo.into_reader();
//!
//! // Reader keeps all the strings from the parent
//! assert_eq!("Hello, world!", reader.resolve(&key));
//! assert_eq!(Some(key), reader.get("Hello, world!"));
//!
//! // The Reader can now be shared across threads, no matter what kind of Rodeo created it
//! ```
//!
//! ## Example: Creating a RodeoResolver
//!
//! ```rust
//! use lasso::Rodeo;
//!
//! // Rodeo and ThreadedRodeo are interchangeable here
//! let mut rodeo = Rodeo::default();
//!
//! let key = rodeo.get_or_intern("Hello, world!");
//! assert_eq!("Hello, world!", rodeo.resolve(&key));
//!
//! let resolver = rodeo.into_resolver();
//!
//! // Resolver keeps all the strings from the parent
//! assert_eq!("Hello, world!", resolver.resolve(&key));
//!
//! // The Resolver can now be shared across threads, no matter what kind of Rodeo created it
//! ```
//!
//! ## Example: Making a custom-ranged key
//!
//! Sometimes you want your keys to only inhabit (or *not* inhabit) a certain range of values so that you can have custom [niches],
//! meaning that an [`enum@Option`]`<`[`struct@Spur`]`>` is the same size as a [`struct@Spur`]. This allows you to pack more data into
//! what would otherwise be unused space, which can be critical for memory-sensitive applications.
//!
//! ```rust
//! use lasso::{Key, Rodeo};
//!
//! // First make our key type, this will be what we use as handles into our interner
//! #[derive(Copy, Clone, PartialEq, Eq)]
//! struct NicheKey(u32);
//!
//! // This will reserve the upper 255 values for us to use as niches
//! const NICHE: usize = 0xFF000000;
//!
//! // Implementing `Key` is unsafe and requires that anything given to `try_from_usize` must produce the
//! // same `usize` when `into_usize` is later called
//! unsafe impl Key for NicheKey {
//! fn into_usize(self) -> usize {
//! self.0 as usize
//! }
//!
//! fn try_from_usize(int: usize) -> Option<Self> {
//! if int < NICHE {
//! // The value isn't in our niche range, so we're good to go
//! Some(Self(int as u32))
//! } else {
//! // The value interferes with our niche, so we return `None`
//! None
//! }
//! }
//! }
//!
//! // To make sure we're upholding `Key`'s safety contract, let's make two small tests
//! #[test]
//! # fn a() {}
//! fn value_in_range() {
//! let key = NicheKey::try_from_usize(0).unwrap();
//! assert_eq!(key.into_usize(), 0);
//!
//! let key = NicheKey::try_from_usize(NICHE - 1).unwrap();
//! assert_eq!(key.into_usize(), NICHE - 1);
//! }
//! # value_in_range();
//!
//! #[test]
//! # fn b() {}
//! fn value_out_of_range() {
//! let key = NicheKey::try_from_usize(NICHE);
//! assert!(key.is_none());
//!
//! let key = NicheKey::try_from_usize(u32::max_value() as usize);
//! assert!(key.is_none());
//! }
//! # value_out_of_range();
//!
//! // And now we're done and can make `Rodeo`s or `ThreadedRodeo`s that use our custom key!
//! let mut rodeo: Rodeo<NicheKey> = Rodeo::new();
//! let key = rodeo.get_or_intern("It works!");
//! assert_eq!(rodeo.resolve(&key), "It works!");
//! ```
//!
//! ## Example: Creation using `FromIterator`
//!
//! ```rust
//! use lasso::Rodeo;
//! use core::iter::FromIterator;
//!
//! // Works for both `Rodeo` and `ThreadedRodeo`
//! let rodeo: Rodeo = vec!["one string", "two string", "red string", "blue string"]
//! .into_iter()
//! .collect();
//!
//! assert!(rodeo.contains("one string"));
//! assert!(rodeo.contains("two string"));
//! assert!(rodeo.contains("red string"));
//! assert!(rodeo.contains("blue string"));
//! ```
//!
//! ```rust
//! use lasso::Rodeo;
//! use core::iter::FromIterator;
//!
//! // Works for both `Rodeo` and `ThreadedRodeo`
//! let rodeo: Rodeo = Rodeo::from_iter(vec![
//! "one string",
//! "two string",
//! "red string",
//! "blue string",
//! ]);
//!
//! assert!(rodeo.contains("one string"));
//! assert!(rodeo.contains("two string"));
//! assert!(rodeo.contains("red string"));
//! assert!(rodeo.contains("blue string"));
//! ```
//!
//! ## Benchmarks
//!
//! Benchmarks were gathered with [Criterion.rs](https://github.com/bheisler/criterion.rs)
//! OS: Windows 10
//! CPU: Ryzen 9 3900X at 3800Mhz
//! RAM: 3200Mhz
//! Rustc: Stable 1.44.1
//!
//! ### Rodeo
//!
//! #### STD RandomState
//!
//! | Method | Time | Throughput |
//! |:-----------------------------|:---------:|:------------:|
//! | `resolve` | 1.9251 μs | 13.285 GiB/s |
//! | `try_resolve` | 1.9214 μs | 13.311 GiB/s |
//! | `resolve_unchecked` | 1.4356 μs | 17.816 GiB/s |
//! | `get_or_intern` (empty) | 60.350 μs | 433.96 MiB/s |
//! | `get_or_intern` (filled) | 57.415 μs | 456.15 MiB/s |
//! | `try_get_or_intern` (empty) | 58.978 μs | 444.06 MiB/s |
//! | `try_get_or_intern (filled)` | 57.421 μs | 456.10 MiB/s |
//! | `get` (empty) | 37.288 μs | 702.37 MiB/s |
//! | `get` (filled) | 55.095 μs | 475.36 MiB/s |
//!
//! #### AHash
//!
//! | Method | Time | Throughput |
//! |:-----------------------------|:---------:|:------------:|
//! | `try_resolve` | 1.9282 μs | 13.264 GiB/s |
//! | `resolve` | 1.9404 μs | 13.181 GiB/s |
//! | `resolve_unchecked` | 1.4328 μs | 17.851 GiB/s |
//! | `get_or_intern` (empty) | 38.029 μs | 688.68 MiB/s |
//! | `get_or_intern` (filled) | 33.650 μs | 778.30 MiB/s |
//! | `try_get_or_intern` (empty) | 39.392 μs | 664.84 MiB/s |
//! | `try_get_or_intern (filled)` | 33.435 μs | 783.31 MiB/s |
//! | `get` (empty) | 12.565 μs | 2.0356 GiB/s |
//! | `get` (filled) | 26.545 μs | 986.61 MiB/s |
//!
//! #### FXHash
//!
//! | Method | Time | Throughput |
//! |:-----------------------------|:---------:|:------------:|
//! | `resolve` | 1.9014 μs | 13.451 GiB/s |
//! | `try_resolve` | 1.9278 μs | 13.267 GiB/s |
//! | `resolve_unchecked` | 1.4449 μs | 17.701 GiB/s |
//! | `get_or_intern` (empty) | 32.523 μs | 805.27 MiB/s |
//! | `get_or_intern` (filled) | 30.281 μs | 864.88 MiB/s |
//! | `try_get_or_intern` (empty) | 31.630 μs | 828.00 MiB/s |
//! | `try_get_or_intern (filled)` | 31.002 μs | 844.78 MiB/s |
//! | `get` (empty) | 12.699 μs | 2.0141 GiB/s |
//! | `get` (filled) | 29.220 μs | 896.28 MiB/s |
//!
//! ### ThreadedRodeo
//!
//! #### STD RandomState
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:-----------------------------|:---------------:|:---------------------:|:-----------------:|:-----------------------:|
//! | `resolve` | 54.336 μs | 482.00 MiB/s | 364.27 μs | 71.897 MiB/s |
//! | `try_resolve` | 54.582 μs | 479.82 MiB/s | 352.67 μs | 74.261 MiB/s |
//! | `get_or_intern` (empty) | 266.03 μs | 98.447 MiB/s | N\A | N\A |
//! | `get_or_intern` (filled) | 103.04 μs | 254.17 MiB/s | 441.42 μs | 59.331 MiB/s |
//! | `try_get_or_intern` (empty) | 261.80 μs | 100.04 MiB/s | N\A | N\A |
//! | `try_get_or_intern` (filled) | 102.61 μs | 255.25 MiB/s | 447.42 μs | 58.535 MiB/s |
//! | `get` (empty) | 80.346 μs | 325.96 MiB/s | N\A | N\A |
//! | `get` (filled) | 92.669 μs | 282.62 MiB/s | 439.24 μs | 59.626 MiB/s |
//!
//! #### AHash
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:-----------------------------|:---------------:|:---------------------:|:-----------------:|:-----------------------:|
//! | `resolve` | 22.261 μs | 1.1489 GiB/s | 265.46 μs | 98.658 MiB/s |
//! | `try_resolve` | 22.378 μs | 1.1429 GiB/s | 268.58 μs | 97.513 MiB/s |
//! | `get_or_intern` (empty) | 157.86 μs | 165.91 MiB/s | N\A | N\A |
//! | `get_or_intern` (filled) | 56.320 μs | 465.02 MiB/s | 357.13 μs | 73.335 MiB/s |
//! | `try_get_or_intern` (empty) | 161.46 μs | 162.21 MiB/s | N\A | N\A |
//! | `try_get_or_intern` (filled) | 55.874 μs | 468.73 MiB/s | 360.25 μs | 72.698 MiB/s |
//! | `get` (empty) | 43.520 μs | 601.79 MiB/s | N\A | N\A |
//! | `get` (filled) | 53.720 μs | 487.52 MiB/s | 360.66 μs | 72.616 MiB/s |
//!
//! #### FXHash
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:-----------------------------|:---------------:|:---------------------:|:-----------------:|:-----------------------:|
//! | `try_resolve` | 17.289 μs | 1.4794 GiB/s | 238.29 μs | 109.91 MiB/s |
//! | `resolve` | 19.833 μs | 1.2896 GiB/s | 237.05 μs | 110.48 MiB/s |
//! | `get_or_intern` (empty) | 130.97 μs | 199.97 MiB/s | N\A | N\A |
//! | `get_or_intern` (filled) | 42.630 μs | 614.35 MiB/s | 301.60 μs | 86.837 MiB/s |
//! | `try_get_or_intern` (empty) | 129.30 μs | 202.55 MiB/s | N\A | N\A |
//! | `try_get_or_intern` (filled) | 42.508 μs | 616.12 MiB/s | 337.29 μs | 77.648 MiB/s |
//! | `get` (empty) | 28.001 μs | 935.30 MiB/s | N\A | N\A |
//! | `get` (filled) | 37.700 μs | 694.68 MiB/s | 292.15 μs | 89.645 MiB/s |
//!
//! ### RodeoReader
//!
//! #### STD RandomState
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:--------------------|:---------------:|:---------------------:|:-----------------:|:------------------------:|
//! | `resolve` | 1.9398 μs | 13.185 GiB/s | 4.3153 μs | 5.9269 GiB/s |
//! | `try_resolve` | 1.9315 μs | 13.242 GiB/s | 4.1956 μs | 6.0959 GiB/s |
//! | `resolve_unchecked` | 1.4416 μs | 17.741 GiB/s | 3.1204 μs | 8.1964 GiB/s |
//! | `get` (empty) | 38.886 μs | 673.50 MiB/s | N\A | N\A |
//! | `get` (filled) | 56.271 μs | 465.42 MiB/s | 105.12 μs | 249.14 MiB/s |
//!
//! #### AHash
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:--------------------|:---------------:|:---------------------:|:-----------------:|:-----------------------:|
//! | `resolve` | 1.9404 μs | 13.181 GiB/s | 4.1881 μs | 6.1069 GiB/s |
//! | `try_resolve` | 1.8932 μs | 13.509 GiB/s | 4.2410 μs | 6.0306 GiB/s |
//! | `resolve_unchecked` | 1.4128 μs | 18.103 GiB/s | 3.1691 μs | 8.0703 GiB/s |
//! | `get` (empty) | 11.952 μs | 2.1399 GiB/s | N\A | N\A |
//! | `get` (filled) | 27.093 μs | 966.65 MiB/s | 56.269 μs | 465.44 MiB/s |
//!
//! #### FXHash
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:--------------------|:---------------:|:---------------------:|:-----------------:|:-----------------------:|
//! | `resolve` | 1.8987 μs | 13.471 GiB/s | 4.2117 μs | 6.0727 GiB/s |
//! | `try_resolve` | 1.9103 μs | 13.389 GiB/s | 4.2254 μs | 6.0529 GiB/s |
//! | `resolve_unchecked` | 1.4469 μs | 17.677 GiB/s | 3.0923 μs | 8.2709 GiB/s |
//! | `get` (empty) | 12.994 μs | 1.9682 GiB/s | N\A | N\A |
//! | `get` (filled) | 29.745 μs | 880.49 MiB/s | 52.387 μs | 499.93 MiB/s |
//!
//! ### RodeoResolver
//!
//! | Method | Time (1 Thread) | Throughput (1 Thread) | Time (24 Threads) | Throughput (24 Threads) |
//! |:--------------------|:---------------:|:---------------------:|:-----------------:|:-----------------------:|
//! | `resolve` | 1.9416 μs | 13.172 GiB/s | 3.9114 μs | 6.5387 GiB/s |
//! | `try_resolve` | 1.9264 μs | 13.277 GiB/s | 3.9289 μs | 6.5097 GiB/s |
//! | `resolve_unchecked` | 1.6638 μs | 15.372 GiB/s | 3.1741 μs | 8.0578 GiB/s |
//!
//! [0]: https://github.com/Kixiron/lasso
//! [1]: https://github.com/Kixiron/lasso/workflows/CI/badge.svg
//! [2]: https://github.com/Kixiron/lasso/workflows/Security%20Audit/badge.svg
//! [3]: https://coveralls.io/repos/github/Kixiron/lasso/badge.svg?branch=master
//! [4]: https://coveralls.io/github/Kixiron/lasso?branch=master
//! [5]: https://tokei.rs/b1/github/Kixiron/lasso
//! [6]: https://docs.rs/lasso/badge.svg
//! [7]: https://docs.rs/lasso
//! [8]: https://img.shields.io/crates/v/lasso.svg
//! [9]: https://crates.io/crates/lasso
//! [key]: crate::Key
//! [niches]: https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html#discriminant-elision-on-option-like-enums
//! [`hashbrown`]: https://crates.io/crates/hashbrown
//! [`ahash`]: https://crates.io/crates/ahash
//! [`raw_entry` api]: https://github.com/rust-lang/rust/issues/56167
#[macro_use]
mod util;
mod arena;
mod interface;
mod keys;
mod reader;
mod resolver;
mod single_threaded;
pub use interface::{Interner, IntoReader, IntoReaderAndResolver, IntoResolver, Reader, Resolver};
pub use keys::{Key, LargeSpur, MicroSpur, MiniSpur, Spur};
pub use reader::RodeoReader;
pub use resolver::RodeoResolver;
pub use single_threaded::Rodeo;
pub use util::{Capacity, Iter, LassoError, LassoErrorKind, LassoResult, MemoryLimits, Strings};
compile! {
if #[feature = "no-std"] {
extern crate alloc;
}
if #[all(feature = "multi-threaded", not(feature = "no-std"))] {
mod multi_threaded;
pub use multi_threaded::ThreadedRodeo;
} else if #[all(feature = "multi-threaded", feature = "no-std")] {
compile_error!("The `multi-threaded` and `no-std` features are not supported together");
}
}
#[doc(hidden)]
mod hasher {
compile! {
if #[feature = "ahasher"] {
pub use ahash::RandomState;
} else {
pub use std::collections::hash_map::RandomState;
}
}
}
#[doc(hidden)]
mod locks {
compile! {
if #[feature = "no-std"] {
pub use alloc::sync::Arc;
} else {
pub use std::sync::Arc;
}
}
}
// TODO: No-alloc interner