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}