1use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum Kind {
11 Token,
12 Data,
13}
14
15impl Default for Kind {
16 fn default() -> Self {
17 Kind::Data
18 }
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct State {
24 pub id: String,
25
26 #[serde(default, skip_serializing_if = "is_default_kind")]
27 pub kind: Kind,
28
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub initial: Option<serde_json::Value>,
31
32 #[serde(default, skip_serializing_if = "String::is_empty")]
33 #[serde(rename = "type")]
34 pub typ: String,
35
36 #[serde(default, skip_serializing_if = "is_false")]
37 pub exported: bool,
38}
39
40fn is_default_kind(k: &Kind) -> bool {
41 *k == Kind::Data
42}
43
44fn is_false(b: &bool) -> bool {
45 !b
46}
47
48impl State {
49 pub fn is_token(&self) -> bool {
50 self.kind == Kind::Token
51 }
52
53 pub fn is_data(&self) -> bool {
54 self.kind == Kind::Data
55 }
56
57 pub fn initial_tokens(&self) -> i64 {
59 if !self.is_token() {
60 return 0;
61 }
62 match &self.initial {
63 Some(v) => v.as_i64().unwrap_or(0),
64 None => 0,
65 }
66 }
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct Action {
72 pub id: String,
73
74 #[serde(default, skip_serializing_if = "String::is_empty")]
75 pub guard: String,
76
77 #[serde(default, skip_serializing_if = "String::is_empty")]
78 pub event_id: String,
79
80 #[serde(default, skip_serializing_if = "Option::is_none")]
81 pub event_bindings: Option<HashMap<String, String>>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct Arc {
87 pub source: String,
88 pub target: String,
89
90 #[serde(default, skip_serializing_if = "Vec::is_empty")]
91 pub keys: Vec<String>,
92
93 #[serde(default, skip_serializing_if = "String::is_empty")]
94 pub value: String,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct Constraint {
100 pub id: String,
101 pub expr: String,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct Event {
107 pub id: String,
108 pub signature: String,
109
110 #[serde(default, skip_serializing_if = "String::is_empty")]
111 pub topic: String,
112
113 #[serde(default)]
114 pub parameters: Vec<EventParameter>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct EventParameter {
120 pub name: String,
121
122 #[serde(rename = "type")]
123 pub typ: String,
124
125 #[serde(default, skip_serializing_if = "is_false")]
126 pub indexed: bool,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct Schema {
132 #[serde(default, skip_serializing_if = "String::is_empty")]
133 pub name: String,
134
135 #[serde(default, skip_serializing_if = "String::is_empty")]
136 pub version: String,
137
138 pub states: Vec<State>,
139 pub actions: Vec<Action>,
140 pub arcs: Vec<Arc>,
141
142 #[serde(default, skip_serializing_if = "Vec::is_empty")]
143 pub constraints: Vec<Constraint>,
144
145 #[serde(default, skip_serializing_if = "Vec::is_empty")]
146 pub events: Vec<Event>,
147}
148
149impl Schema {
150 pub fn new(name: impl Into<String>) -> Self {
151 Self {
152 name: name.into(),
153 version: "1.0.0".into(),
154 states: Vec::new(),
155 actions: Vec::new(),
156 arcs: Vec::new(),
157 constraints: Vec::new(),
158 events: Vec::new(),
159 }
160 }
161
162 pub fn add_state(&mut self, st: State) -> &mut Self {
163 self.states.push(st);
164 self
165 }
166
167 pub fn add_token_state(&mut self, id: impl Into<String>, initial: i64) -> &mut Self {
168 self.states.push(State {
169 id: id.into(),
170 kind: Kind::Token,
171 initial: Some(serde_json::Value::Number(initial.into())),
172 typ: "int".into(),
173 exported: false,
174 });
175 self
176 }
177
178 pub fn add_data_state(
179 &mut self,
180 id: impl Into<String>,
181 typ: impl Into<String>,
182 initial: Option<serde_json::Value>,
183 exported: bool,
184 ) -> &mut Self {
185 self.states.push(State {
186 id: id.into(),
187 kind: Kind::Data,
188 typ: typ.into(),
189 initial,
190 exported,
191 });
192 self
193 }
194
195 pub fn add_action(&mut self, a: Action) -> &mut Self {
196 self.actions.push(a);
197 self
198 }
199
200 pub fn add_arc(&mut self, a: Arc) -> &mut Self {
201 self.arcs.push(a);
202 self
203 }
204
205 pub fn add_constraint(&mut self, c: Constraint) -> &mut Self {
206 self.constraints.push(c);
207 self
208 }
209
210 pub fn add_event(&mut self, e: Event) -> &mut Self {
211 self.events.push(e);
212 self
213 }
214
215 pub fn state_by_id(&self, id: &str) -> Option<&State> {
216 self.states.iter().find(|s| s.id == id)
217 }
218
219 pub fn action_by_id(&self, id: &str) -> Option<&Action> {
220 self.actions.iter().find(|a| a.id == id)
221 }
222
223 pub fn event_by_id(&self, id: &str) -> Option<&Event> {
224 self.events.iter().find(|e| e.id == id)
225 }
226
227 pub fn action_for_event(&self, event_id: &str) -> Option<&Action> {
228 self.actions.iter().find(|a| a.event_id == event_id)
229 }
230
231 pub fn input_arcs(&self, action_id: &str) -> Vec<&Arc> {
233 self.arcs.iter().filter(|a| a.target == action_id).collect()
234 }
235
236 pub fn output_arcs(&self, action_id: &str) -> Vec<&Arc> {
238 self.arcs.iter().filter(|a| a.source == action_id).collect()
239 }
240
241 pub fn token_states(&self) -> Vec<&State> {
242 self.states.iter().filter(|s| s.is_token()).collect()
243 }
244
245 pub fn data_states(&self) -> Vec<&State> {
246 self.states.iter().filter(|s| s.is_data()).collect()
247 }
248}