polydat_core/kernel/subcontext/name.rs
1// Copyright 2024-2026 Jonathan Shook
2// SPDX-License-Identifier: Apache-2.0
3
4//! [`ChildName`] — structured identifier for a spawned child.
5//!
6//! Per SRD-67 §"Named-child registry": each parent records the
7//! names it has spawned children under so duplicate spawn under
8//! the same name is caught at the API boundary. Names are
9//! `PathBuf`-shaped (hierarchical, comparable, debug-printable);
10//! the runtime constructs them from workload scope-tree node
11//! labels (phase / op-template / iteration coordinate).
12
13use std::fmt;
14
15/// Hierarchical identifier for a spawned sub-context.
16///
17/// Internally a slash-separated string of segments. Constructors
18/// match common workload-tree shapes:
19///
20/// - [`ChildName::phase`] — `phase/<name>`
21/// - [`ChildName::op`] — `op/<name>`
22/// - [`ChildName::iteration`] — `iter/<coord>`
23/// - [`ChildName::compose`] — append a segment under a parent name
24///
25/// Two names compare equal when their segment vectors are equal.
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub struct ChildName {
28 segments: Vec<String>,
29}
30
31impl ChildName {
32 /// Create from raw segments. Used by tests / advanced callers
33 /// that have a pre-built path; production code prefers the
34 /// shape-specific constructors below.
35 pub fn from_segments<I, S>(segments: I) -> Self
36 where
37 I: IntoIterator<Item = S>,
38 S: Into<String>,
39 {
40 Self {
41 segments: segments.into_iter().map(Into::into).collect(),
42 }
43 }
44
45 /// `phase/<name>` — for a workload phase scope.
46 pub fn phase(name: impl Into<String>) -> Self {
47 Self {
48 segments: vec!["phase".into(), name.into()],
49 }
50 }
51
52 /// `op/<name>` — for an op-template scope under a phase.
53 pub fn op(name: impl Into<String>) -> Self {
54 Self {
55 segments: vec!["op".into(), name.into()],
56 }
57 }
58
59 /// `iter/<coord>` — for one iteration of a comprehension scope.
60 /// `coord` is the coordinate-tuple debug rendering used by the
61 /// scope-tree pre-walk.
62 pub fn iteration(coord: impl Into<String>) -> Self {
63 Self {
64 segments: vec!["iter".into(), coord.into()],
65 }
66 }
67
68 /// Compose: append `segment` to `parent_name`'s path.
69 pub fn compose(parent_name: &ChildName, segment: impl Into<String>) -> Self {
70 let mut segments = parent_name.segments.clone();
71 segments.push(segment.into());
72 Self { segments }
73 }
74
75 /// Borrow the segment list.
76 pub fn segments(&self) -> &[String] {
77 &self.segments
78 }
79
80 /// Render as a slash-joined path for diagnostics.
81 pub fn display(&self) -> String {
82 self.segments.join("/")
83 }
84}
85
86impl fmt::Display for ChildName {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 f.write_str(&self.display())
89 }
90}