nornir 0.4.30

Companion to cargo: dependency tracking, release gating, deploy, benchmarks, and documentation assembly. Project-agnostic.
//! Typed id wrappers. Newtypes keep idea/plan/node/run ids from being
//! mixed up at call sites. Underlying representation is a short
//! string so the log stays human-readable (`i-001`, `p-001`, `n-003`,
//! `r-7f3a`) — uuids are optional for plugins that want them.

use serde::{Deserialize, Serialize};
use std::fmt;

macro_rules! id_newtype {
    ($name:ident, $prefix:literal) => {
        #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
        #[serde(transparent)]
        pub struct $name(pub String);

        impl $name {
            pub fn new(raw: impl Into<String>) -> Self {
                Self(raw.into())
            }

            /// Generate a fresh id with a stable prefix. Counter is
            /// the caller's responsibility — the funnel passes the
            /// current high-water mark so ids stay monotonic.
            pub fn seq(n: u64) -> Self {
                Self(format!("{}-{:03}", $prefix, n))
            }

            pub fn as_str(&self) -> &str {
                &self.0
            }
        }

        impl fmt::Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                f.write_str(&self.0)
            }
        }

        impl From<&str> for $name {
            fn from(s: &str) -> Self {
                Self(s.to_owned())
            }
        }

        impl From<String> for $name {
            fn from(s: String) -> Self {
                Self(s)
            }
        }
    };
}

id_newtype!(IdeaId, "i");
id_newtype!(PlanId, "p");
id_newtype!(NodeId, "n");
id_newtype!(RunId, "r");