celox/component/
injected.rs1use std::sync::Arc;
2
3use crate::HashMap;
4
5use veryl_metadata::ComponentManifest;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
9pub enum InjectedValue {
10 Bits {
11 words: Vec<u64>,
12 mask_xz: Vec<u64>,
13 width: u32,
14 },
15 String(String),
16 Unit,
17}
18
19#[derive(Clone, Debug, PartialEq, Eq)]
21pub enum InjectedHook {
22 Create,
23 Init,
24 Reset,
25 Clock,
26 Finish,
27 Method {
28 name: String,
29 args: Vec<InjectedValue>,
30 },
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
34pub struct InjectedNamedValue {
35 pub name: String,
36 pub value: InjectedValue,
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct InjectedPort {
41 pub name: String,
42 pub direction: String,
43 pub role: Option<String>,
44 pub width: u32,
45}
46
47#[derive(Clone, Debug)]
49pub struct InjectedCall {
50 pub instance: String,
51 pub hook: InjectedHook,
52 pub inputs: Vec<InjectedNamedValue>,
53 pub params: Vec<InjectedNamedValue>,
54 pub ports: Vec<InjectedPort>,
55 pub cycle: u64,
56 pub time: u64,
57 pub seed: u64,
58 pub fired_clock: Option<String>,
59 pub four_state: bool,
60}
61
62#[derive(Clone, Debug, Default)]
65pub struct InjectedResult {
66 pub outputs: Vec<InjectedNamedValue>,
67 pub return_value: Option<InjectedValue>,
68 pub failures: Vec<String>,
69 pub logs: Vec<String>,
70 pub finish: bool,
71}
72
73pub trait InjectedComponentHandler: Send + Sync + 'static {
75 fn call(&self, call: InjectedCall) -> Result<InjectedResult, String>;
76}
77
78#[derive(Clone)]
79pub(crate) struct InjectedComponentDefinition {
80 pub manifest: ComponentManifest,
81 pub kind: u32,
82 pub handler: Arc<dyn InjectedComponentHandler>,
83}
84
85#[derive(Clone, Default)]
87pub struct InjectedComponents {
88 pub(crate) definitions: HashMap<String, InjectedComponentDefinition>,
89}
90
91impl InjectedComponents {
92 pub fn new() -> Self {
93 Self::default()
94 }
95
96 pub fn insert(
97 &mut self,
98 name: impl Into<String>,
99 manifest_json: &str,
100 handler: Arc<dyn InjectedComponentHandler>,
101 ) -> Result<(), String> {
102 let name = name.into();
103 if name.is_empty() || name.contains("::") {
104 return Err("injected component names must be non-empty identifiers".into());
105 }
106 let manifest = ComponentManifest::parse(manifest_json)
107 .ok_or_else(|| format!("manifest of injected component `{name}` cannot be parsed"))?;
108 let kind = match manifest.kind.as_deref() {
109 Some("clocked") => veryl_component_sys::VRL_KIND_CLOCKED,
110 Some("method_only") => veryl_component_sys::VRL_KIND_METHOD_ONLY,
111 Some(kind) => return Err(format!("unsupported component kind `{kind}`")),
112 None => {
113 return Err(format!(
114 "manifest of injected component `{name}` has no kind"
115 ));
116 }
117 };
118 if self.definitions.contains_key(&name) {
119 return Err(format!(
120 "injected component `{name}` is defined more than once"
121 ));
122 }
123 self.definitions.insert(
124 name,
125 InjectedComponentDefinition {
126 manifest,
127 kind,
128 handler,
129 },
130 );
131 Ok(())
132 }
133
134 pub(crate) fn get(&self, name: &str) -> Option<&InjectedComponentDefinition> {
135 self.definitions.get(name)
136 }
137
138 pub(crate) fn manifests(&self) -> Vec<(String, ComponentManifest)> {
139 self.definitions
140 .iter()
141 .map(|(name, definition)| (name.clone(), definition.manifest.clone()))
142 .collect()
143 }
144}