1use std::collections::HashSet;
2use std::str::FromStr;
3
4use once_cell::sync::Lazy;
5use serde::Deserialize;
6
7use crate::book::{BookDeclarations, Property, Struct};
8use crate::messages::{Field, Message, MessageDeclarations};
9use crate::*;
10
11pub const DATA_STR: &str =
12 include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/declarations/MessagesToBook.toml"));
13
14pub static DATA: Lazy<MessagesToBookDeclarations<'static>> = Lazy::new(|| {
15 let rules: TomlStruct = toml::from_str(DATA_STR).unwrap();
16 let book = &book::DATA;
17 let messages = &messages::DATA;
18
19 let mut decls: Vec<_> = rules
20 .rule
21 .into_iter()
22 .map(|r| {
23 let msg = messages.get_message(&r.from);
24 let msg_fields =
25 msg.attributes.iter().map(|a| messages.get_field(a)).collect::<Vec<_>>();
26 let book_struct = book
27 .structs
28 .iter()
29 .find(|s| s.name == r.to)
30 .unwrap_or_else(|| panic!("Cannot find struct {}", r.to));
31
32 let mut ev = Event {
33 op: r.operation.parse().expect("Failed to parse operation"),
34 id: r.id.iter().map(|s| find_field(s, &msg_fields)).collect(),
35 msg,
36 book_struct,
37 rules: r
38 .properties
39 .into_iter()
40 .map(|p| {
41 assert!(p.is_valid());
42
43 let find_prop = |name, book_struct: &'static Struct| -> &'static Property {
44 if let Some(prop) =
45 book_struct.properties.iter().find(|p| p.name == name)
46 {
47 return prop;
48 }
49 panic!(
50 "No such (nested) property {} found in struct {}",
51 name, book_struct.name,
52 );
53 };
54
55 if p.function.is_some() {
56 RuleKind::Function {
57 name: p.function.unwrap(),
58 to: p
59 .tolist
60 .unwrap()
61 .into_iter()
62 .map(|p| find_prop(p, book_struct))
63 .collect(),
64 }
65 } else {
66 RuleKind::Map {
67 from: find_field(&p.from.unwrap(), &msg_fields),
68 to: find_prop(p.to.unwrap(), book_struct),
69 op: p
70 .operation
71 .map(|s| s.parse().expect("Invalid operation for property"))
72 .unwrap_or(RuleOp::Update),
73 }
74 }
75 })
76 .collect(),
77 };
78
79 let used_flds = ev
82 .rules
83 .iter()
84 .filter_map(|f| match *f {
85 RuleKind::Map { from, .. } => Some(from),
86 _ => None,
87 })
88 .collect::<HashSet<_>>();
89
90 let mut used_props = vec![];
91 for rule in &ev.rules {
92 if let RuleKind::Function { to, .. } = rule {
93 for p in to {
94 used_props.push(p.name.clone());
95 }
96 }
97 }
98
99 for fld in &msg_fields {
100 if used_flds.contains(fld) {
101 continue;
102 }
103 if let Some(prop) = book
104 .get_struct(&ev.book_struct.name)
105 .properties
106 .iter()
107 .find(|p| p.name == fld.pretty)
108 {
109 if used_props.contains(&prop.name) {
110 continue;
111 }
112
113 ev.rules.push(RuleKind::Map { from: fld, to: prop, op: RuleOp::Update });
114 }
115 }
116
117 ev
118 })
119 .collect();
120
121 decls.retain(|ev| ev.msg.name != "InitServer");
123
124 MessagesToBookDeclarations { book, messages, decls }
125});
126
127#[derive(Debug)]
128pub struct MessagesToBookDeclarations<'a> {
129 pub book: &'a BookDeclarations,
130 pub messages: &'a MessageDeclarations,
131 pub decls: Vec<Event<'a>>,
132}
133
134#[derive(Debug)]
135pub struct Event<'a> {
136 pub op: RuleOp,
137 pub id: Vec<&'a Field>,
139 pub msg: &'a Message,
140 pub book_struct: &'a Struct,
141 pub rules: Vec<RuleKind<'a>>,
142}
143
144#[derive(Debug)]
145pub enum RuleKind<'a> {
146 Map { from: &'a Field, to: &'a Property, op: RuleOp },
147 Function { name: String, to: Vec<&'a Property> },
148}
149
150#[derive(Debug, PartialEq, Eq, Clone, Copy)]
151pub enum RuleOp {
152 Add,
153 Remove,
154 Update,
155}
156
157#[derive(Clone, Deserialize, Debug)]
158#[serde(deny_unknown_fields)]
159struct TomlStruct {
160 rule: Vec<Rule>,
161}
162
163#[derive(Clone, Deserialize, Debug)]
164#[serde(deny_unknown_fields)]
165struct Rule {
166 id: Vec<String>,
167 from: String,
168 to: String,
169 operation: String,
170 #[serde(default = "Vec::new")]
171 properties: Vec<RuleProperty>,
172}
173
174#[derive(Clone, Deserialize, Debug)]
175#[serde(deny_unknown_fields)]
176struct RuleProperty {
177 from: Option<String>,
178 to: Option<String>,
179 operation: Option<String>,
180
181 function: Option<String>,
182 tolist: Option<Vec<String>>,
183}
184
185impl Event<'_> {
186 pub fn get_id_args(&self, msg: &str) -> String {
190 let mut res = String::new();
191 for f in &self.id {
192 if !res.is_empty() {
193 res.push_str(", ");
194 }
195 if !f.get_type("").unwrap().is_primitive() {
196 res.push('&');
197 }
198 res.push_str(&format!("{}.{}", msg, f.get_rust_name()));
199 }
200 res
201 }
202
203 pub fn get_property_id(&self, p: &Property, from: &Field, msg: &str) -> String {
207 let mut ids = self.get_id_args(msg);
208 if let Some(m) = &p.modifier {
209 if !ids.is_empty() {
210 ids.push_str(", ");
211 }
212 if m == "map" || m == "array" || m == "set" {
213 ids.push_str(&format!("{}.{}", msg, from.get_rust_name()));
214 } else {
215 panic!("Unknown modifier {}", m);
216 }
217 }
218 format!("PropertyId::{}{}{}", self.book_struct.name, p.get_name(), embrace(&ids))
219 }
220}
221
222impl RuleProperty {
223 fn is_valid(&self) -> bool {
224 if self.from.is_some() {
225 self.to.is_some() && self.function.is_none() && self.tolist.is_none()
226 } else {
227 self.from.is_none()
228 && self.to.is_none()
229 && self.operation.is_none()
230 && self.function.is_some()
231 && self.tolist.is_some()
232 }
233 }
234}
235
236impl FromStr for RuleOp {
237 type Err = fmt::Error;
238 fn from_str(s: &str) -> Result<Self> {
239 if s == "add" {
240 Ok(RuleOp::Add)
241 } else if s == "remove" {
242 Ok(RuleOp::Remove)
243 } else if s == "update" {
244 Ok(RuleOp::Update)
245 } else {
246 eprintln!("Cannot parse operation, needs to be add, remove or update");
247 Err(fmt::Error)
248 }
249 }
250}
251
252fn find_field<'a>(name: &str, msg_fields: &[&'a Field]) -> &'a Field {
254 *msg_fields
255 .iter()
256 .find(|f| f.pretty == name)
257 .unwrap_or_else(|| panic!("Cannot find field '{}'", name))
258}
259
260impl<'a> RuleKind<'a> {
261 pub fn is_function(&self) -> bool { matches!(self, RuleKind::Function { .. }) }
262}