Skip to main content

obzenflow_core/id/
scc_id.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// SPDX-FileCopyrightText: 2025-2026 ObzenFlow Contributors
3// https://obzenflow.dev
4
5//! SCC identifier for cycle iteration tracking
6
7use serde::{Deserialize, Serialize};
8use std::fmt;
9use ulid::Ulid;
10
11/// Identifies which strongly connected component (SCC) a stage belongs to.
12///
13/// Parallel to `obzenflow_topology::SccId` but lives in core so that
14/// `ChainEvent` can carry SCC context without depending on the topology crate.
15/// Conversion between the two is handled by `SccIdExt` in runtime_services.
16///
17/// Each SCC's identity is derived from the minimum `StageId` in its member
18/// set, making it deterministic for a given topology without requiring
19/// sequential index allocation. This is consistent with every other
20/// identifier in the system, which uses ULID-based IDs.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
22#[serde(transparent)]
23pub struct SccId(Ulid);
24
25impl SccId {
26    /// Create from a specific ULID.
27    pub fn from_ulid(ulid: Ulid) -> Self {
28        Self(ulid)
29    }
30
31    /// Get the underlying ULID.
32    pub fn as_ulid(&self) -> Ulid {
33        self.0
34    }
35}
36
37impl fmt::Display for SccId {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        write!(f, "scc_{}", self.0)
40    }
41}
42
43impl From<Ulid> for SccId {
44    fn from(ulid: Ulid) -> Self {
45        Self(ulid)
46    }
47}
48
49impl From<SccId> for Ulid {
50    fn from(scc_id: SccId) -> Self {
51        scc_id.0
52    }
53}