Skip to main content

acton_ern/traits/
ern_component.rs

1use std::str::FromStr;
2
3use crate::errors::ErnError;
4use crate::{Account, Category, Domain, EntityRoot, Part, Parts};
5
6/// Represents a component of an Entity Resource Name (ERN).
7///
8/// This trait is used to ensure type safety and proper ordering when building ERNs.
9/// Each component in an ERN implements this trait, defining its prefix and the
10/// type of the next component that should follow it in the ERN structure.
11///
12/// The trait is primarily used by the `ErnBuilder` to enforce the correct order
13/// of components during ERN construction.
14pub trait ErnComponent {
15    /// Returns the prefix string that should appear before this component in an ERN.
16    ///
17    /// For example, the `Domain` component has the prefix "ern:" to indicate the
18    /// start of an ERN string.
19    fn prefix() -> &'static str;
20
21    /// The type of the next component that should follow this one in the ERN structure.
22    ///
23    /// This associated type is used by the builder pattern to enforce the correct
24    /// sequence of components. For example, `Domain::NextState` is `Category`,
25    /// indicating that a `Category` should follow a `Domain` in an ERN.
26    type NextState;
27
28    /// Builds the ERN root component this type contributes, if it can occupy the root slot.
29    ///
30    /// `ErnBuilder` dispatches on component *position*, which is not enough to tell the
31    /// root-capable components apart: `EntityRoot` and `SHA1Name` share the same prefix
32    /// and the same `NextState`. This method carries the identifier algorithm down to the
33    /// builder, so `with::<SHA1Name>(..)` really does produce a deterministic v5 root
34    /// instead of silently falling back to a time-ordered v7 one.
35    ///
36    /// Components that never occupy the root slot use the default implementation and
37    /// return `None`.
38    fn build_root(_value: &str) -> Option<Result<EntityRoot, ErnError>> {
39        None
40    }
41}
42
43macro_rules! impl_ern_component {
44    ($type:ty, $prefix:expr, $next:ty) => {
45        impl ErnComponent for $type {
46            fn prefix() -> &'static str {
47                $prefix
48            }
49            type NextState = $next;
50        }
51    };
52}
53impl ErnComponent for EntityRoot {
54    fn prefix() -> &'static str {
55        ""
56    }
57    type NextState = Part;
58
59    fn build_root(value: &str) -> Option<Result<EntityRoot, ErnError>> {
60        Some(EntityRoot::from_str(value))
61    }
62}
63
64impl ErnComponent for Account {
65    fn prefix() -> &'static str {
66        ""
67    }
68    type NextState = EntityRoot;
69}
70
71impl_ern_component!(Domain, "ern:", Category);
72impl_ern_component!(Category, "", Account);
73impl_ern_component!(Part, "", Parts);
74
75/// Implementation for the `Parts` component of an ERN.
76///
77/// The `Parts` component represents a collection of path parts in the ERN.
78/// Its `NextState` is itself, allowing for multiple parts to be added.
79impl ErnComponent for Parts {
80    fn prefix() -> &'static str {
81        ":"
82    }
83    type NextState = Parts;
84}