use rustev_contract::calibration::CalibrationArtifact;
use rustev_contract::descriptor::BackendDescriptor;
use rustev_contract::limits::DESCRIPTOR_V1;
use rustev_contract::{Document, DocumentError};
use crate::host::{Host, IoFail};
#[derive(Debug, Clone, Copy, Default)]
pub struct DepArgs<'a> {
pub descriptors: &'a [String],
pub rules: &'a [String],
pub calibrations: &'a [String],
}
#[derive(Debug, Default)]
pub struct Deps {
pub descriptors: Vec<BackendDescriptor>,
pub calibrations: Vec<CalibrationArtifact>,
}
#[derive(Debug)]
pub enum DepFail {
Io(IoFail),
Parse {
subject: String,
detail: String,
},
Rules {
path: String,
detail: String,
},
}
pub type RulesHook<'h> = dyn FnMut(&str, &[u8]) -> Result<BackendDescriptor, String> + 'h;
fn parse<T: Document>(host: &dyn Host, kind: &str, label: &str) -> Result<T, DepFail> {
let bytes = host
.read(label, DESCRIPTOR_V1.max_bytes)
.map_err(DepFail::Io)?;
T::parse(&bytes).map_err(|e: DocumentError| DepFail::Parse {
subject: format!("{kind}:{label}"),
detail: e.to_string(),
})
}
pub fn load(
host: &dyn Host,
args: DepArgs<'_>,
rules: &mut RulesHook<'_>,
) -> Result<Deps, DepFail> {
let mut deps = Deps::default();
for label in args.descriptors {
deps.descriptors.push(parse(host, "descriptor", label)?);
}
for label in args.rules {
let bytes = host
.read(label, DESCRIPTOR_V1.max_bytes)
.map_err(DepFail::Io)?;
let descriptor = rules(label, &bytes).map_err(|detail| DepFail::Rules {
path: label.clone(),
detail,
})?;
deps.descriptors.push(descriptor);
}
for label in args.calibrations {
deps.calibrations.push(parse(host, "calibration", label)?);
}
Ok(deps)
}
pub fn no_rules(_: &str, _: &[u8]) -> Result<BackendDescriptor, String> {
Err("this host runs no rules backend".into())
}