1use rustev_contract::calibration::CalibrationArtifact;
5use rustev_contract::descriptor::BackendDescriptor;
6use rustev_contract::limits::DESCRIPTOR_V1;
7use rustev_contract::{Document, DocumentError};
8
9use crate::host::{Host, IoFail};
10
11#[derive(Debug, Clone, Copy, Default)]
13pub struct DepArgs<'a> {
14 pub descriptors: &'a [String],
15 pub rules: &'a [String],
16 pub calibrations: &'a [String],
17}
18
19#[derive(Debug, Default)]
21pub struct Deps {
22 pub descriptors: Vec<BackendDescriptor>,
24 pub calibrations: Vec<CalibrationArtifact>,
25}
26
27#[derive(Debug)]
29pub enum DepFail {
30 Io(IoFail),
31 Parse {
34 subject: String,
35 detail: String,
36 },
37 Rules {
39 path: String,
40 detail: String,
41 },
42}
43
44pub type RulesHook<'h> = dyn FnMut(&str, &[u8]) -> Result<BackendDescriptor, String> + 'h;
47
48fn parse<T: Document>(host: &dyn Host, kind: &str, label: &str) -> Result<T, DepFail> {
49 let bytes = host
50 .read(label, DESCRIPTOR_V1.max_bytes)
51 .map_err(DepFail::Io)?;
52 T::parse(&bytes).map_err(|e: DocumentError| DepFail::Parse {
53 subject: format!("{kind}:{label}"),
54 detail: e.to_string(),
55 })
56}
57
58pub fn load(
60 host: &dyn Host,
61 args: DepArgs<'_>,
62 rules: &mut RulesHook<'_>,
63) -> Result<Deps, DepFail> {
64 let mut deps = Deps::default();
65 for label in args.descriptors {
66 deps.descriptors.push(parse(host, "descriptor", label)?);
67 }
68 for label in args.rules {
69 let bytes = host
70 .read(label, DESCRIPTOR_V1.max_bytes)
71 .map_err(DepFail::Io)?;
72 let descriptor = rules(label, &bytes).map_err(|detail| DepFail::Rules {
73 path: label.clone(),
74 detail,
75 })?;
76 deps.descriptors.push(descriptor);
77 }
78 for label in args.calibrations {
79 deps.calibrations.push(parse(host, "calibration", label)?);
80 }
81 Ok(deps)
82}
83
84pub fn no_rules(_: &str, _: &[u8]) -> Result<BackendDescriptor, String> {
86 Err("this host runs no rules backend".into())
87}