1use std::collections::HashMap;
2use std::path::PathBuf;
3
4use serde::{Deserialize, Serialize};
5
6use ssd_data::{Namespace, SsdModule, TypeName};
7
8#[derive(Serialize, Deserialize, Hash, Eq, PartialEq)]
9#[serde(untagged)]
10enum StringOrVec {
11 String(String),
12 Vec(Vec<String>),
13}
14
15pub fn print_or_write(out: Option<PathBuf>, result: &str) -> anyhow::Result<()> {
16 if let Some(out) = out {
17 std::fs::write(out, result)?;
18 } else {
19 println!("{result}");
20 }
21 Ok(())
22}
23
24pub fn parse_raw_data(file: PathBuf) -> anyhow::Result<serde_value::Value> {
25 let content = std::fs::read_to_string(file)?;
26 let result = serde_json::from_str(&content)
27 .or_else(|_| toml::from_str(&content))
28 .or_else(|_| serde_yaml::from_str(&content))
29 .or_else(|_| rsn::from_str(&content));
30 #[cfg(feature = "ron")]
31 let result = result.or_else(|_| ron::from_str(&content));
32 Ok(result?)
33}
34
35#[cfg(not(feature = "_bin"))]
36pub fn update_types(mut module: SsdModule, typemap: &str) -> anyhow::Result<SsdModule> {
37 let mappings: HashMap<StringOrVec, StringOrVec> = toml::from_str(typemap)?;
38 let mappings: HashMap<String, String> = mappings
39 .iter()
40 .map(|(k, v)| match (k, v) {
41 (StringOrVec::Vec(k), StringOrVec::Vec(v)) => (k.join("::"), v.join("::")),
42 (StringOrVec::Vec(k), StringOrVec::String(v)) => (k.join("::"), v.clone()),
43 (StringOrVec::String(k), StringOrVec::Vec(v)) => (k.clone(), v.join("::")),
44 (StringOrVec::String(k), StringOrVec::String(v)) => (k.clone(), v.clone()),
45 })
46 .collect();
47 for (_dt_name, dt) in &mut module.data_types {
48 for (_name, prop) in &mut dt.properties {
49 let name = prop.typ.to_string();
50 if let Some(v) = mappings.get(&name) {
51 prop.typ = Namespace::new(v);
52 }
53 }
54 }
55
56 for (_service_name, service) in &mut module.services {
57 for (_handler_name, h) in &mut service.functions {
58 if let Some(TypeName {
59 typ,
60 is_list,
61 count,
62 attributes,
63 comments,
64 }) = &h.return_type
65 {
66 let name = typ.to_string();
67 let mut comments = comments.clone();
68 if let Some(v) = mappings.get(&name) {
69 h.return_type = Some(
70 TypeName::new(Namespace::new(v), *is_list, *count, attributes.clone())
71 .with_comments(&mut comments),
72 );
73 }
74 }
75 for (_arg_name, arg) in &mut h.arguments {
76 let name = arg.typ.to_string();
77 if let Some(v) = mappings.get(&name) {
78 arg.typ = Namespace::new(v);
79 }
80 }
81 }
82 for (_event_name, h) in &mut service.events {
83 for (_arg_name, arg) in &mut h.arguments {
84 let name = arg.typ.to_string();
85 if let Some(v) = mappings.get(&name) {
86 arg.typ = Namespace::new(v);
87 }
88 }
89 }
90 }
91
92 Ok(module)
93}
94
95pub fn update_types_from_file(
96 mut module: SsdModule,
97 no_map: bool,
98 typemap: Option<PathBuf>,
99 script: Option<&PathBuf>,
100) -> anyhow::Result<SsdModule> {
101 if let (false, Some(map_file)) = (
102 no_map,
103 typemap.or_else(|| {
104 script.and_then(|script| {
105 let mut typemap = script.clone();
106 typemap.set_extension("tym");
107 typemap.exists().then_some(typemap)
108 })
109 }),
110 ) {
111 let mappings: HashMap<StringOrVec, StringOrVec> =
112 toml::from_str(&std::fs::read_to_string(map_file)?)?;
113 let mappings: HashMap<String, String> = mappings
114 .iter()
115 .map(|(k, v)| match (k, v) {
116 (StringOrVec::Vec(k), StringOrVec::Vec(v)) => (k.join("::"), v.join("::")),
117 (StringOrVec::Vec(k), StringOrVec::String(v)) => (k.join("::"), v.clone()),
118 (StringOrVec::String(k), StringOrVec::Vec(v)) => (k.clone(), v.join("::")),
119 (StringOrVec::String(k), StringOrVec::String(v)) => (k.clone(), v.clone()),
120 })
121 .collect();
122 for (_dt_name, dt) in &mut module.data_types {
123 for (_name, prop) in &mut dt.properties {
124 let name = prop.typ.to_string();
125 if let Some(v) = mappings.get(&name) {
126 prop.typ = Namespace::new(v);
127 }
128 }
129 }
130
131 for (_service_name, service) in &mut module.services {
132 for (_handler_name, h) in &mut service.functions {
133 if let Some(TypeName {
134 typ,
135 is_list,
136 count,
137 attributes,
138 comments,
139 }) = &h.return_type
140 {
141 let name = typ.to_string();
142 let mut comments = comments.clone();
143 if let Some(v) = mappings.get(&name) {
144 h.return_type = Some(
145 TypeName::new(Namespace::new(v), *is_list, *count, attributes.clone())
146 .with_comments(&mut comments),
147 );
148 }
149 }
150 for (_arg_name, arg) in &mut h.arguments {
151 let name = arg.typ.to_string();
152 if let Some(v) = mappings.get(&name) {
153 arg.typ = Namespace::new(v);
154 }
155 }
156 }
157 for (_event_name, h) in &mut service.events {
158 for (_arg_name, arg) in &mut h.arguments {
159 let name = arg.typ.to_string();
160 if let Some(v) = mappings.get(&name) {
161 arg.typ = Namespace::new(v);
162 }
163 }
164 }
165 }
166 }
167
168 Ok(module)
169}