1#[cfg(feature = "file")]
2use super::io::io_error;
3use piston_meta::{parse_errstr, MetaData, Syntax};
4#[cfg(feature = "file")]
5use piston_meta::syntax_errstr;
6#[cfg(feature = "file")]
7use std::fs::File;
8use std::io;
9#[cfg(feature = "file")]
10use std::io::Read;
11use std::sync::Arc;
12
13use crate::Variable;
14
15pub fn parse_syntax_data(rules: &Syntax, file: &str, d: &str) -> Result<Vec<Variable>, String> {
16 let mut tokens = vec![];
17 parse_errstr(rules, d, &mut tokens)
18 .map_err(|err| format!("When parsing data in `{}`:\n{}", file, err))?;
19 let mut res = vec![];
20 let b: Arc<String> = Arc::new("bool".into());
21 let s: Arc<String> = Arc::new("str".into());
22 let n: Arc<String> = Arc::new("f64".into());
23 let start: Arc<String> = Arc::new("start".into());
24 let end: Arc<String> = Arc::new("end".into());
25 for range_token in &tokens {
26 let mut data = vec![
27 Variable::f64(range_token.offset as f64),
28 Variable::f64(range_token.length as f64),
29 ];
30 match range_token.data {
31 MetaData::Bool(ref name, val) => {
32 data.push(Variable::Str(b.clone()));
33 data.push(Variable::Str(name.clone()));
34 data.push(Variable::bool(val));
35 }
36 MetaData::String(ref name, ref val) => {
37 data.push(Variable::Str(s.clone()));
38 data.push(Variable::Str(name.clone()));
39 data.push(Variable::Str(val.clone()));
40 }
41 MetaData::F64(ref name, val) => {
42 data.push(Variable::Str(n.clone()));
43 data.push(Variable::Str(name.clone()));
44 data.push(Variable::f64(val));
45 }
46 MetaData::StartNode(ref name) => {
47 data.push(Variable::Str(start.clone()));
48 data.push(Variable::Str(name.clone()));
49 }
50 MetaData::EndNode(ref name) => {
51 data.push(Variable::Str(end.clone()));
52 data.push(Variable::Str(name.clone()));
53 }
54 }
55 res.push(Variable::Array(Arc::new(data)));
56 }
57 Ok(res)
58}
59
60#[cfg(feature = "file")]
61fn load_metarules_data(meta: &str, s: &str, file: &str, d: &str) -> Result<Vec<Variable>, String> {
62 let rules = syntax_errstr(s)
63 .map_err(|err| format!("When parsing meta syntax in `{}`:\n{}", meta, err))?;
64 parse_syntax_data(&rules, file, d)
65}
66
67#[cfg(feature = "file")]
69pub fn load_meta_file(meta: &str, file: &str) -> Result<Vec<Variable>, String> {
70 let mut syntax_file = File::open(meta).map_err(|err| io_error("open", meta, &err))?;
71 let mut s = String::new();
72 syntax_file
73 .read_to_string(&mut s)
74 .map_err(|err| io_error("read", meta, &err))?;
75 let mut data_file = File::open(file).map_err(|err| io_error("open", file, &err))?;
76 let mut d = String::new();
77 data_file
78 .read_to_string(&mut d)
79 .map_err(|err| io_error("read", file, &err))?;
80 load_metarules_data(meta, &s, file, &d)
81}
82
83#[cfg(not(feature = "file"))]
84pub fn load_meta_file(_: &str, _: &str) -> Result<Vec<Variable>, String> {
85 Err(super::FILE_SUPPORT_DISABLED.into())
86}
87
88#[cfg(all(not(target_family = "wasm"), feature = "http"))]
90pub fn load_text_file_from_url(url: &str) -> Result<String, String> {
91 use reqwest::{Client, StatusCode, Url};
92
93 let url_address = Url::parse(url).map_err(|e| format!("Error parsing url:\n`{}`\n", e))?;
94 let client = Client::new();
95 let request = client.get(url_address);
96 let mut response = request.send().map_err(|e| {
97 format!(
98 "Error fetching file over http `{}`:\n{}\n",
99 url,
100 e.to_string()
101 )
102 })?;
103 if response.status() == StatusCode::OK {
104 let mut data = String::new();
105 response.read_to_string(&mut data).map_err(|e| {
106 format!(
107 "Error fetching file over http `{}`:\n{}\n",
108 url,
109 e.to_string()
110 )
111 })?;
112 Ok(data)
113 } else {
114 Err(format!(
115 "Error fetching file over http `{}:\n{}\n",
116 url,
117 response.status()
118 ))
119 }
120}
121
122#[cfg(not(all(not(target_family = "wasm"), feature = "http")))]
123pub fn load_text_file_from_url(_url: &str) -> Result<String, String> {
124 Err(super::HTTP_SUPPORT_DISABLED.into())
125}
126
127#[cfg(all(not(target_family = "wasm"), feature = "http"))]
129pub fn load_meta_url(meta: &str, url: &str) -> Result<Vec<Variable>, String> {
130 let mut syntax_file = File::open(meta).map_err(|err| io_error("open", meta, &err))?;
131 let mut s = String::new();
132 syntax_file
133 .read_to_string(&mut s)
134 .map_err(|err| io_error("read", meta, &err))?;
135 let d = load_text_file_from_url(url)?;
136 load_metarules_data(meta, &s, url, &d)
137}
138
139#[cfg(not(all(not(target_family = "wasm"), feature = "http")))]
140pub fn load_meta_url(_meta: &str, _url: &str) -> Result<Vec<Variable>, String> {
141 Err(super::HTTP_SUPPORT_DISABLED.into())
142}
143
144#[cfg(all(not(target_family = "wasm"), feature = "http"))]
146pub fn download_url_to_file(url: &str, file: &str) -> Result<String, String> {
147 use reqwest::{Client, StatusCode, Url};
148 use std::io::copy;
149
150 let url_address = Url::parse(url).map_err(|e| format!("Error parsing url:\n`{}`\n", e))?;
151 let client = Client::new();
152 let request = client.get(url_address);
153 let mut response = request.send().map_err(|e| {
154 format!(
155 "Error fetching file over http `{}`:\n{}\n",
156 url,
157 e.to_string()
158 )
159 })?;
160 if response.status() == StatusCode::OK {
161 let mut f = File::create(file)
162 .map_err(|err| format!("Could not create file `{}`:\n{}", file, err.to_string()))?;
163 copy(&mut response, &mut f).map_err(|e| {
164 format!(
165 "Error fetching file over http `{}`:\n{}\n",
166 url,
167 e.to_string()
168 )
169 })?;
170 Ok(file.into())
171 } else {
172 Err(format!(
173 "Error fetching file over http `{}:\n{}\n",
174 url,
175 response.status()
176 ))
177 }
178}
179
180#[cfg(not(all(not(target_family = "wasm"), feature = "http")))]
181pub fn download_url_to_file(_url: &str, _file: &str) -> Result<String, String> {
182 Err(super::HTTP_SUPPORT_DISABLED.into())
183}
184
185pub fn json_from_meta_data(data: &[Variable]) -> Result<String, io::Error> {
186 fn is_start_node(v: &Variable) -> bool {
187 if let Variable::Array(ref arr) = *v {
188 if let Variable::Str(ref t) = arr[2] {
189 &**t == "start"
190 } else {
191 false
192 }
193 } else {
194 false
195 }
196 }
197
198 fn is_end_node(v: &Variable) -> bool {
199 if let Variable::Array(ref arr) = *v {
200 if let Variable::Str(ref t) = arr[2] {
201 &**t == "end"
202 } else {
203 false
204 }
205 } else {
206 false
207 }
208 }
209
210 use piston_meta::json::write_string;
211 use std::cmp::{max, min};
212 use std::io::Write;
213
214 let indent_offset = 0;
215 let mut w: Vec<u8> = vec![];
216
217 let starts = data.iter().filter(|x| is_start_node(x)).count() as u32;
219 let ends = data.iter().filter(|x| is_end_node(x)).count() as u32;
220 let mut indent: u32 = max(starts, ends) - min(starts, ends);
221 let mut first = true;
222 for (i, d) in data.iter().enumerate() {
223 let is_end = if is_end_node(d) {
224 indent -= 1;
225 true
226 } else {
227 false
228 };
229 let print_comma = !first && !is_end;
230 if print_comma {
231 writeln!(w, ",")?;
232 } else if i != 0 {
233 writeln!(w)?;
234 }
235 first = false;
236 for _ in 0..indent_offset + indent {
237 write!(w, " ")?;
238 }
239 if let Variable::Array(ref arr) = *d {
240 let name = if let Variable::Str(ref t) = arr[3] {
241 t
242 } else {
243 ""
244 };
245 if let Variable::Str(ref t) = arr[2] {
246 match &***t {
247 "start" => {
248 first = true;
249 write_string(&mut w, name)?;
250 write!(w, ":{}", "{")?;
251 indent += 1;
252 }
253 "end" => {
254 write!(w, "{}", "}")?;
255 }
256 "bool" => {
257 if let Variable::Bool(val, _) = arr[4] {
258 write_string(&mut w, name)?;
259 write!(w, ":{}", val)?;
260 }
261 }
262 "f64" => {
263 if let Variable::F64(val, _) = arr[4] {
264 write_string(&mut w, name)?;
265 write!(w, ":{}", val)?;
266 }
267 }
268 "str" => {
269 if let Variable::Str(ref val) = arr[4] {
270 write_string(&mut w, name)?;
271 write!(w, ":")?;
272 write_string(&mut w, val)?;
273 }
274 }
275 _ => {}
276 }
277 }
278 }
279 }
280 writeln!(w)?;
281 Ok(String::from_utf8(w).unwrap())
282}