stringid/lib.rs
1//! The `stringid` crate is a set of helpers (macros, structs, traits) to manage identifiers
2//! both as human readable string and unique number efficiently. It can be useful for using
3//! immutable strings that exist until the end of the application.
4//!
5//! The unique identifier allows for light storage + fast comparison
6//! and copy operations.
7//! While the human readable string allows convenience use in UI, serialization, debug, etc.
8//!
9//! # Why use [`StringId`] ?
10//! You can use [`StringId`] where you would like use an immutable [`String`] (or [`str`]) as an identifier.
11//! And particularly if this identifier is used in several place in the data.
12//! Two advantages of [`StringId`] are that :
13//! - it does not duplicate the string data.
14//! - it does not use string for comparison, assignation, copy of Id.
15//!
16//! ## ⚠ **Warning**
17//! The use of `StringId` with a `StaticStrStore` can (safely) *leak memory*.
18//! The memory allocated for the `str` will not be released until the end of the program, like a `'static` variable.
19//! So you probably should avoid to use [`StringId`] with not immutable `String`,
20//! if the identifiers (`String`/`str`) are likely to change regularly. Or do it knowingly.
21//!
22//! Typical uses can be :
23//! - tags.
24//! - inter-resources referencing, especially if you have to serialize/deserialize the data.
25//!
26//! # Technical design
27//!
28//! The [`StringId`] variables only store the identifier (a unique number).
29//! While [`str`] are stored separately, only one time in memory for all copy of one Id
30//! and are accessible through a dedicated type.
31//!
32//! The crate `stringid` components are designed to be used with [new-type pattern](https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction).
33//! So some macros are accessible trough the module `macros` to help define custom types.
34//!
35//! To store correspondence between a [`StringId`] and the corresponding [`str`] use an implementation of [`StrLookup`].
36//! [`StrLookupHashMap`] implement [`StrLookup`] with an [`std::collections::HashMap`] and a [`StaticStrStore`].
37//!
38//! For more details, look at respective documentations.
39//!
40//! ## Quick start
41//! ```
42//! use std::{mem::size_of, str::FromStr};
43//! use stringid::macros::{strlookup_hashmap, StringIdImpl};
44//! use stringid::{create_hash_map, BufferStrStore, StringId};
45//!
46//! // Create a struct type `CustomIdLookup`
47//! // as a `str` lookup with `BufferStrStore` as StrStore.
48//! #[strlookup_hashmap(key = u32, store = BufferStrStore, size = 128)]
49//! struct CustomIdLookup;
50//!
51//! // Create a `StringId` type who use the type `CustomIdLookup`
52//! // as `StrLookup`.
53//! #[derive(Debug, Clone, Copy, StringIdImpl)]
54//! struct CustomId(StringId<u32, CustomIdLookup>);
55//!
56//! // Create instances of CustomId from str
57//! let id_1 = CustomId::from_str("Id1").unwrap();
58//! let id_2 = CustomId::from_str("Id2").unwrap();
59//! let id_1_bis = id_1;
60//! let id_1_ter = CustomId::from_str("Id1").unwrap();
61//!
62//! // CustomId size is the size of the Id (u32 here)
63//! assert_eq!(size_of::<u32>(), size_of::<CustomId>());
64//!
65//! // The Id1 and Id2 are not equal
66//! assert_ne!(id_1,id_2);
67//! // But the id_1 and id_1_bis are
68//! assert_eq!(id_1,id_1_bis);
69//! // as well as id_1 and id_1_ter
70//! assert_eq!(id_1,id_1_ter);
71//! ```
72
73mod static_str_buffer;
74mod static_str_store;
75mod str_lookup;
76mod stringid;
77
78pub use static_str_buffer::StaticStrBuffer;
79pub use static_str_store::{BufferStrStore, StaticStrStore, StringStrStore};
80pub use str_lookup::{create_hash_map, StrLookup, StrLookupEmpty, StrLookupHashMap};
81pub use stringid::StringId;
82
83#[cfg(feature = "macros")]
84pub mod macros {
85 pub use stringid_macros::strlookup_hashmap;
86 pub use stringid_macros::StringIdImpl;
87}