1use std::collections::BTreeMap;
4use std::path::Path;
5use std::sync::Arc;
6
7use phoxal_model::Robot;
8use phoxal_runtime_contract::identity::{ParticipantArtifactId, ParticipantId};
9
10use crate::{
11 BinaryReference, BundleError, BundleRoot, ParticipantAssets, RuntimeDocument,
12 RuntimeParticipant, SelectionError, read_runtime_document, require_layout_directories,
13 validate_layout,
14};
15
16#[derive(Clone, Debug)]
18pub struct ParticipantRuntimeInputs {
19 robot: Arc<Robot>,
20 participant: RuntimeParticipant,
21 artifact: BinaryReference,
23 assets: ParticipantAssets,
24}
25
26impl ParticipantRuntimeInputs {
27 #[must_use]
29 pub fn robot(&self) -> &Robot {
30 self.robot.as_ref()
31 }
32
33 #[must_use]
35 pub const fn participant(&self) -> &RuntimeParticipant {
36 &self.participant
37 }
38
39 #[must_use]
41 pub const fn artifact(&self) -> &BinaryReference {
42 &self.artifact
43 }
44
45 #[must_use]
47 pub const fn assets(&self) -> &ParticipantAssets {
48 &self.assets
49 }
50}
51
52#[derive(Clone, Debug)]
54pub struct RuntimeBundle {
55 root: BundleRoot,
56 document: RuntimeDocument,
57 assets: ParticipantAssets,
58}
59
60impl RuntimeBundle {
61 pub fn open_verified(root: impl AsRef<Path>) -> Result<Self, BundleError> {
66 let root = BundleRoot::open(root.as_ref())?;
67 let document = read_runtime_document(&root)?;
68 validate_layout(&root, document.runtime())?;
69 Ok(Self {
70 assets: ParticipantAssets::new(root.clone(), &document.runtime().assets),
71 root,
72 document,
73 })
74 }
75
76 #[must_use]
78 pub fn root(&self) -> &Path {
79 self.root.path()
80 }
81
82 #[must_use]
84 pub const fn document(&self) -> &RuntimeDocument {
85 &self.document
86 }
87
88 #[must_use]
90 pub fn robot(&self) -> &Robot {
91 self.document.robot()
92 }
93
94 #[must_use]
96 pub fn robot_id(&self) -> &phoxal_model::identity::RobotId {
97 self.document.robot_id()
98 }
99
100 #[must_use]
102 pub fn participants(&self) -> &[RuntimeParticipant] {
103 self.document.participants()
104 }
105
106 #[must_use]
108 pub fn artifacts(&self) -> &BTreeMap<ParticipantArtifactId, BinaryReference> {
109 self.document.artifacts()
110 }
111
112 #[must_use]
114 pub const fn assets(&self) -> &ParticipantAssets {
115 &self.assets
116 }
117
118 pub fn participant(&self, id: &ParticipantId) -> Result<&RuntimeParticipant, SelectionError> {
120 self.document.participant(id)
121 }
122
123 pub fn participant_inputs(
125 &self,
126 id: &ParticipantId,
127 ) -> Result<ParticipantRuntimeInputs, SelectionError> {
128 selected_inputs(&self.document, self.assets.clone(), id)
129 }
130
131 pub(crate) fn relocated(mut self, path: std::path::PathBuf) -> Self {
132 self.root.relocate(path.clone());
133 self.assets.relocate(path);
134 self
135 }
136}
137
138#[derive(Clone, Debug)]
140pub struct ParticipantBundle {
141 root: BundleRoot,
142 inputs: ParticipantRuntimeInputs,
143}
144
145impl ParticipantBundle {
146 pub fn open(root: impl AsRef<Path>, id: &ParticipantId) -> Result<Self, BundleError> {
151 let root = BundleRoot::open(root.as_ref())?;
152 let document = read_runtime_document(&root)?;
153 require_layout_directories(&root)?;
154 let assets = ParticipantAssets::new(root.clone(), &document.runtime().assets);
155 let inputs = selected_inputs(&document, assets, id)?;
156 Ok(Self { root, inputs })
157 }
158
159 #[must_use]
161 pub const fn inputs(&self) -> &ParticipantRuntimeInputs {
162 &self.inputs
163 }
164
165 #[must_use]
167 pub fn into_inputs(self) -> ParticipantRuntimeInputs {
168 self.inputs
169 }
170
171 #[must_use]
173 pub fn root(&self) -> &Path {
174 self.root.path()
175 }
176}
177
178fn selected_inputs(
179 document: &RuntimeDocument,
180 assets: ParticipantAssets,
181 id: &ParticipantId,
182) -> Result<ParticipantRuntimeInputs, SelectionError> {
183 let participant = document.participant(id)?.clone();
184 let artifact = document
185 .artifacts()
186 .get(&participant.artifact)
187 .cloned()
188 .ok_or_else(|| SelectionError::MissingArtifact {
189 participant: participant.id.clone(),
190 artifact: participant.artifact.clone(),
191 })?;
192 Ok(ParticipantRuntimeInputs {
193 robot: Arc::new(document.robot().clone()),
194 participant,
195 artifact,
196 assets,
197 })
198}