clique_types/manifest/
mod.rs1pub mod code;
2pub mod compat;
3pub mod input;
4pub mod output;
5pub mod refer;
6pub mod subtask;
7
8use std::collections::HashMap;
9use std::fmt;
10use std::str::FromStr;
11
12use anyhow::Result;
13use indexmap::IndexMap;
14use serde::{Deserialize, Serialize};
15
16use crate::value::{CliqueValueType, CustomType};
17
18pub use code::{CodeType, RawCode};
19pub use compat::{TaskCompatType, TaskCompatibility};
20pub use input::Input;
21pub use output::Output;
22pub use refer::{MapOrRefers, Reference};
23pub use subtask::RawSubTask;
24
25pub type RawCustomType = IndexMap<String, IndexMap<String, Input>>;
26
27pub(crate) type TaskName = String;
28pub(crate) type SubTaskID = String;
29pub(crate) type Identifier = String;
30pub(crate) type TaskInputRefers = Vec<(Identifier, Reference)>;
31pub(crate) type TaskOutputRefers = Vec<(Identifier, Reference)>;
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub enum ManifestType {
35 BuiltIn,
36 Schema,
37 Dynamic,
38}
39
40impl ManifestType {
41 pub fn is_buildin(&self) -> bool {
42 matches!(self, Self::BuiltIn)
43 }
44
45 pub fn is_dynamic(&self) -> bool {
46 matches!(self, Self::Dynamic)
47 }
48
49 pub fn is_schema(&self) -> bool {
50 matches!(self, Self::Schema)
51 }
52}
53
54#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
55pub enum ProofType {
56 TEE,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[serde(rename_all = "kebab-case")]
61pub struct Manifest {
62 pub name: String,
63 pub spec_version: String,
64 #[serde(rename = "type")]
65 pub type_: ManifestType,
66
67 pub proof_type: Vec<ProofType>,
68
69 #[serde(rename = "types", skip_serializing_if = "Option::is_none")]
70 pub custom_type: Option<RawCustomType>,
71
72 pub input: IndexMap<String, Input>,
73 pub output: IndexMap<String, Output>,
74
75 #[serde(rename = "code", skip_serializing_if = "Option::is_none")]
76 pub raw_code: Option<RawCode>,
77
78 #[serde(rename = "tasks", skip_serializing_if = "Option::is_none")]
79 pub subtasks: Option<Vec<RawSubTask>>,
80}
81
82impl Manifest {
83 pub fn from_file(path: impl AsRef<std::path::Path>) -> Result<Self> {
84 let manifest_str = std::fs::read_to_string(path)?;
85 Ok(Self::from_str(&manifest_str)?)
86 }
87
88 pub fn parse_input(&self) -> Result<IndexMap<String, CliqueValueType>> {
89 let custom_types = self.parse_custom_types()?;
90
91 Ok(CustomType::from_map("Input", &self.input, custom_types.as_ref())?.type_)
92 }
93
94 pub fn parse_output(&self) -> Result<MapOrRefers> {
95 if self.type_.is_schema() {
96 let mut refers = Vec::with_capacity(self.output.len());
97 for (name, output) in self.output.iter() {
98 let ref_str = output
99 .ref_
100 .as_ref()
101 .ok_or(anyhow::anyhow!("should have ref"))?;
102 let refer = Reference::from_str(ref_str)?;
103 refers.push((name.clone(), refer));
104 }
105 Ok(MapOrRefers::Refers(refers))
106 } else {
107 let mut map = IndexMap::new();
108 for (name, output) in self.output.iter() {
109 let type_str = output
110 .type_
111 .as_ref()
112 .ok_or(anyhow::anyhow!("should have type"))?
113 .clone();
114 let input = Input::new(type_str);
115 map.insert(name.clone(), input);
116 }
117
118 let custom_types = self.parse_custom_types()?;
119
120 Ok(MapOrRefers::Map(
121 CustomType::from_map("Output", &map, custom_types.as_ref())?.type_,
122 ))
123 }
124 }
125
126 pub fn parse_subtasks(&self) -> Result<HashMap<SubTaskID, (TaskName, TaskInputRefers)>> {
127 if self.subtasks.is_none() {
128 return Ok(HashMap::new());
129 }
130
131 let tasks = self.subtasks.as_ref().unwrap();
132 let mut res = HashMap::new();
133 for task in tasks {
134 let task_id = task.id.clone();
135 let task_name = task.name.clone();
136 let task_inputs = &task.input;
137 let mut list = Vec::with_capacity(task_inputs.len());
138 for (input_name, input_ref) in task_inputs {
139 let refer = Reference::from_str(&input_ref)?;
140 list.push((input_name.clone(), refer));
141 }
142 res.insert(task_id, (task_name, list));
143 }
144
145 Ok(res)
146 }
147
148 pub fn parse_custom_types(&self) -> Result<Option<IndexMap<String, CustomType>>> {
149 if self.custom_type.is_none() {
150 return Ok(None);
151 }
152
153 let mut custom_types = None;
154 for (name, map) in self.custom_type.as_ref().unwrap().iter() {
156 let new_type = CustomType::from_map(name, map, custom_types.as_ref())?;
157 if custom_types.is_none() {
158 custom_types = Some(IndexMap::new());
159 }
160 custom_types
161 .as_mut()
162 .unwrap()
163 .insert(name.clone(), new_type);
164 }
165 Ok(custom_types)
166 }
167}
168
169impl fmt::Display for Manifest {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 let serialized = toml::to_string(self).map_err(|_| fmt::Error)?;
172 write!(f, "{}", serialized)
173 }
174}
175
176impl FromStr for Manifest {
177 type Err = toml::de::Error;
178
179 fn from_str(s: &str) -> Result<Self, Self::Err> {
180 toml::from_str(s)
181 }
182}
183
184#[cfg(test)]
185mod test {
186 use super::*;
187
188 #[test]
189 fn test_manifests() {
190 test_manifest("assets/dynamic.toml");
191 test_manifest("assets/builtin.toml");
192 test_manifest("assets/schema.toml");
193 }
194
195 fn test_manifest(file_path: &str) {
196 let manifest = Manifest::from_file(file_path).unwrap();
197 let manifest_str = manifest.to_string();
198 println!("{}", manifest_str);
199
200 let input = manifest.parse_input().unwrap();
201 println!("{:?}", input);
202 }
203}