acton_ern/
lib.rs

1//! # Acton Entity Resource Name (ERN) Library
2//!
3//! `acton-ern` is a Rust library for working with Entity Resource Names (ERNs), which are structured identifiers
4//! used to uniquely identify and manage hierarchical resources across different services and partitions in distributed systems.
5//! While ERNs follow the Uniform Resource Name (URN) format defined in [RFC 8141](https://tools.ietf.org/html/rfc8141),
6//! they extend beyond standard URNs by offering additional features like k-sortability and type-safe construction.
7//!
8//! ## Key Features
9//!
10//! - **Structured Resource Naming**: Create standardized, hierarchical resource identifiers that are both human-readable and machine-parseable
11//! - **K-Sortable Identifiers**: When using `UnixTime` or `Timestamp` ID types, ERNs can be efficiently sorted and queried by creation time
12//! - **Content-Addressable IDs**: When using `SHA1Name` ID type, generate deterministic IDs based on content
13//! - **Type-Safe Construction**: The builder pattern ensures ERNs are constructed correctly at compile time
14//! - **Flexible ID Types**: Choose the right ID type for your use case (time-based ordering or content-based addressing)
15//! - **Hierarchical Relationships**: Model parent-child relationships between resources naturally
16//! - **Serialization Support**: Serialize and deserialize ERNs to/from JSON and YAML (with the `serde` feature)
17//!
18//! ## Crate Structure
19//!
20//! - `builder`: Type-safe builder pattern for constructing ERNs
21//! - `parser`: Tools for parsing ERN strings into structured components
22//! - `model`: Component models (Domain, Category, Account, Root, Part)
23//! - `traits`: Common traits used across the crate
24//!
25//! ## Basic Usage
26//!
27//! ```rust,ignore
28//! use acton_ern::prelude::*;
29//!
30//! // Create a time-ordered, sortable ERN
31//! let ern = ErnBuilder::new()
32//!     .with::<Domain>("my-app")?
33//!     .with::<Category>("users")?
34//!     .with::<Account>("tenant123")?
35//!     .with::<EntityRoot>("profile")?
36//!     .with::<Part>("settings")?
37//!     .build()?;
38//!
39//! // Parse an ERN from a string
40//! let ern_str = "ern:my-app:users:tenant123:profile_01h9xz7n2e5p6q8r3t1u2v3w4x/settings";
41//! let parsed_ern = ErnParser::new(ern_str.to_string()).parse()?;
42//! ```
43//!
44//! ## Serialization/Deserialization
45//!
46//! With the `serde` feature enabled, ERNs can be serialized to and deserialized from formats like JSON and YAML:
47//!
48//! ```rust,ignore
49//! // Enable the serde feature in Cargo.toml:
50//! // acton-ern = { version = "1.0.0", features = ["serde"] }
51//!
52//! use acton_ern::prelude::*;
53//! use serde_json;
54//!
55//! // Create an ERN
56//! let ern = ErnBuilder::new()
57//!     .with::<Domain>("my-app")?
58//!     .with::<Category>("users")?
59//!     .with::<Account>("tenant123")?
60//!     .with::<EntityRoot>("profile")?
61//!     .build()?;
62//!
63//! // Serialize to JSON
64//! let json = serde_json::to_string(&ern)?;
65//!
66//! // Deserialize from JSON
67//! let deserialized: Ern = serde_json::from_str(&json)?;
68//! ```
69//!
70
71#![allow(missing_docs)]
72
73extern crate core;
74
75// Re-exporting the public API under the root of the crate for direct access
76pub use builder::*;
77pub use model::*;
78pub use parser::*;
79pub use traits::*;
80
81mod builder;
82mod errors;
83mod model;
84mod parser;
85mod traits;
86
87pub mod prelude {
88    //! The prelude module for `acton-ern`.
89    //!
90    //! This module re-exports essential traits and structures for easy use in your application.
91    //! Import this module with `use acton_ern::prelude::*;` to get access to all the commonly used
92    //! types and traits without having to import them individually.
93
94    pub use super::builder::ErnBuilder;
95    pub use super::errors::ErnError;
96    pub use super::model::{Account, Category, Domain, EntityRoot, Ern, Part, Parts, SHA1Name};
97    pub use super::parser::ErnParser;
98    pub use super::traits::*;
99}
100
101#[cfg(test)]
102mod tests {
103    use std::sync::Once;
104
105    use tracing::Level;
106    use tracing_subscriber::{EnvFilter, FmtSubscriber};
107    use tracing_subscriber::fmt::format::FmtSpan;
108
109    static INIT: Once = Once::new();
110
111    pub fn init_tracing() {
112        INIT.call_once(|| {
113            // Define an environment filter to suppress logs from the specific function
114
115            // let filter = EnvFilter::new("")
116            //     // .add_directive("acton_core::common::context::emit_pool=trace".parse().unwrap())
117            //     // .add_directive("acton_core::common::context::my_func=trace".parse().unwrap())
118            //     .add_directive("acton_core::common::context[my_func]=trace".parse().unwrap())
119            //     .add_directive(Level::INFO.into()); // Set global log level to INFO
120
121            let filter = EnvFilter::new("")
122                .add_directive("acton-ern::parser::tests=trace".parse().unwrap())
123                .add_directive("broker_tests=trace".parse().unwrap())
124                .add_directive("launchpad_tests=trace".parse().unwrap())
125                .add_directive("lifecycle_tests=info".parse().unwrap())
126                .add_directive("actor_tests=info".parse().unwrap())
127                .add_directive("load_balancer_tests=info".parse().unwrap())
128                .add_directive(
129                    "acton::tests::setup::actors::pool_item=info"
130                        .parse()
131                        .unwrap(),
132                )
133                .add_directive("messaging_tests=info".parse().unwrap());
134            // .add_directive(tracing_subscriber::filter::LevelFilter::INFO.into()); // Set global log level to TRACE
135
136            let subscriber = FmtSubscriber::builder()
137                // .with_span_events(FmtSpan::ENTER | FmtSpan::EXIT)
138                .with_span_events(FmtSpan::NONE)
139                .with_max_level(Level::TRACE)
140                .compact()
141                .with_line_number(true)
142                .without_time()
143                .with_env_filter(filter)
144                .finish();
145
146            tracing::subscriber::set_global_default(subscriber)
147                .expect("setting default subscriber failed");
148        });
149    }
150}