use std::collections::BTreeMap;
use std::path::Path;
use std::sync::Arc;
use phoxal_model::Robot;
use phoxal_runtime_contract::identity::{ParticipantArtifactId, ParticipantId};
use crate::{
BinaryReference, BundleError, BundleRoot, ParticipantAssets, RuntimeDocument,
RuntimeParticipant, SelectionError, read_runtime_document, require_layout_directories,
validate_layout,
};
#[derive(Clone, Debug)]
pub struct ParticipantRuntimeInputs {
robot: Arc<Robot>,
participant: RuntimeParticipant,
artifact: BinaryReference,
assets: ParticipantAssets,
}
impl ParticipantRuntimeInputs {
#[must_use]
pub fn robot(&self) -> &Robot {
self.robot.as_ref()
}
#[must_use]
pub const fn participant(&self) -> &RuntimeParticipant {
&self.participant
}
#[must_use]
pub const fn artifact(&self) -> &BinaryReference {
&self.artifact
}
#[must_use]
pub const fn assets(&self) -> &ParticipantAssets {
&self.assets
}
}
#[derive(Clone, Debug)]
pub struct RuntimeBundle {
root: BundleRoot,
document: RuntimeDocument,
assets: ParticipantAssets,
}
impl RuntimeBundle {
pub fn open_verified(root: impl AsRef<Path>) -> Result<Self, BundleError> {
let root = BundleRoot::open(root.as_ref())?;
let document = read_runtime_document(&root)?;
validate_layout(&root, document.runtime())?;
Ok(Self {
assets: ParticipantAssets::new(root.clone(), &document.runtime().assets),
root,
document,
})
}
#[must_use]
pub fn root(&self) -> &Path {
self.root.path()
}
#[must_use]
pub const fn document(&self) -> &RuntimeDocument {
&self.document
}
#[must_use]
pub fn robot(&self) -> &Robot {
self.document.robot()
}
#[must_use]
pub fn robot_id(&self) -> &phoxal_model::identity::RobotId {
self.document.robot_id()
}
#[must_use]
pub fn participants(&self) -> &[RuntimeParticipant] {
self.document.participants()
}
#[must_use]
pub fn artifacts(&self) -> &BTreeMap<ParticipantArtifactId, BinaryReference> {
self.document.artifacts()
}
#[must_use]
pub const fn assets(&self) -> &ParticipantAssets {
&self.assets
}
pub fn participant(&self, id: &ParticipantId) -> Result<&RuntimeParticipant, SelectionError> {
self.document.participant(id)
}
pub fn participant_inputs(
&self,
id: &ParticipantId,
) -> Result<ParticipantRuntimeInputs, SelectionError> {
selected_inputs(&self.document, self.assets.clone(), id)
}
pub(crate) fn relocated(mut self, path: std::path::PathBuf) -> Self {
self.root.relocate(path.clone());
self.assets.relocate(path);
self
}
}
#[derive(Clone, Debug)]
pub struct ParticipantBundle {
root: BundleRoot,
inputs: ParticipantRuntimeInputs,
}
impl ParticipantBundle {
pub fn open(root: impl AsRef<Path>, id: &ParticipantId) -> Result<Self, BundleError> {
let root = BundleRoot::open(root.as_ref())?;
let document = read_runtime_document(&root)?;
require_layout_directories(&root)?;
let assets = ParticipantAssets::new(root.clone(), &document.runtime().assets);
let inputs = selected_inputs(&document, assets, id)?;
Ok(Self { root, inputs })
}
#[must_use]
pub const fn inputs(&self) -> &ParticipantRuntimeInputs {
&self.inputs
}
#[must_use]
pub fn into_inputs(self) -> ParticipantRuntimeInputs {
self.inputs
}
#[must_use]
pub fn root(&self) -> &Path {
self.root.path()
}
}
fn selected_inputs(
document: &RuntimeDocument,
assets: ParticipantAssets,
id: &ParticipantId,
) -> Result<ParticipantRuntimeInputs, SelectionError> {
let participant = document.participant(id)?.clone();
let artifact = document
.artifacts()
.get(&participant.artifact)
.cloned()
.ok_or_else(|| SelectionError::MissingArtifact {
participant: participant.id.clone(),
artifact: participant.artifact.clone(),
})?;
Ok(ParticipantRuntimeInputs {
robot: Arc::new(document.robot().clone()),
participant,
artifact,
assets,
})
}