1use dypdl::variable_type;
4use dypdl::StateMetadata;
5use std::convert::TryFrom;
6use std::error;
7use std::fmt;
8use std::str;
9use yaml_rust::{yaml::Array, Yaml};
10
11#[derive(Debug, Clone)]
13pub struct YamlContentErr(String);
14
15impl YamlContentErr {
16 pub fn new(message: String) -> YamlContentErr {
18 YamlContentErr(format!("Error in yaml contents: {message}"))
19 }
20}
21
22impl fmt::Display for YamlContentErr {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 write!(f, "{}", self.0)
25 }
26}
27
28impl error::Error for YamlContentErr {}
29
30pub fn get_map(
36 value: &Yaml,
37) -> Result<&linked_hash_map::LinkedHashMap<Yaml, Yaml>, YamlContentErr> {
38 match value {
39 Yaml::Hash(map) => Ok(map),
40 _ => Err(YamlContentErr::new(
41 format!("expected Hash, but {value:?}",),
42 )),
43 }
44}
45
46pub fn get_yaml_by_key<'a>(
52 map: &'a linked_hash_map::LinkedHashMap<Yaml, Yaml>,
53 key: &str,
54) -> Result<&'a Yaml, YamlContentErr> {
55 match map.get(&Yaml::String(String::from(key))) {
56 Some(value) => Ok(value),
57 None => Err(YamlContentErr::new(format!("no such key `{key}` in yaml",))),
58 }
59}
60
61pub fn get_array(value: &Yaml) -> Result<&Vec<Yaml>, YamlContentErr> {
67 match value {
68 Yaml::Array(array) => Ok(array),
69 _ => Err(YamlContentErr::new(format!(
70 "expected Array, but is `{value:?}`",
71 ))),
72 }
73}
74
75pub fn get_bool(value: &Yaml) -> Result<bool, YamlContentErr> {
81 match value {
82 Yaml::Boolean(value) => Ok(*value),
83 _ => Err(YamlContentErr::new(format!(
84 "expected Boolean, but is `{value:?}`",
85 ))),
86 }
87}
88
89pub fn get_bool_by_key(
95 map: &linked_hash_map::LinkedHashMap<Yaml, Yaml>,
96 key: &str,
97) -> Result<bool, YamlContentErr> {
98 match map.get(&Yaml::String(String::from(key))) {
99 Some(value) => get_bool(value),
100 None => Err(YamlContentErr::new(format!("key `{key}` not found"))),
101 }
102}
103
104pub fn get_usize(value: &Yaml) -> Result<usize, YamlContentErr> {
110 if let Yaml::Integer(value) = value {
111 match variable_type::Element::try_from(*value) {
112 Ok(value) => Ok(value),
113 Err(e) => Err(YamlContentErr::new(format!(
114 "cannot convert {value} to usize: {e:?}",
115 ))),
116 }
117 } else {
118 Err(YamlContentErr::new(format!(
119 "expected Integer, but is `{value:?}`",
120 )))
121 }
122}
123
124pub fn get_usize_array(value: &Yaml) -> Result<Vec<usize>, YamlContentErr> {
130 if let Yaml::Array(array) = value {
131 let mut result = Vec::with_capacity(array.len());
132 for value in array {
133 result.push(get_usize(value)?);
134 }
135 Ok(result)
136 } else {
137 Err(YamlContentErr::new(format!(
138 "expected Array, but is `{value:?}`",
139 )))
140 }
141}
142
143pub fn get_usize_by_key(
149 map: &linked_hash_map::LinkedHashMap<Yaml, Yaml>,
150 key: &str,
151) -> Result<usize, YamlContentErr> {
152 match map.get(&Yaml::String(String::from(key))) {
153 Some(value) => get_usize(value),
154 None => Err(YamlContentErr::new(format!("key `{key}` not found"))),
155 }
156}
157
158pub fn get_usize_array_by_key(
164 map: &linked_hash_map::LinkedHashMap<Yaml, Yaml>,
165 key: &str,
166) -> Result<Vec<usize>, YamlContentErr> {
167 match map.get(&Yaml::String(String::from(key))) {
168 Some(value) => get_usize_array(value),
169 None => Err(YamlContentErr::new(format!("key `{key}` not found"))),
170 }
171}
172
173pub fn get_numeric<T: str::FromStr + num_traits::FromPrimitive>(
179 value: &Yaml,
180) -> Result<T, YamlContentErr>
181where
182 <T as str::FromStr>::Err: fmt::Debug,
183{
184 match value {
185 Yaml::Integer(value) => match T::from_i64(*value) {
186 Some(value) => Ok(value),
187 None => Err(YamlContentErr::new(format!(
188 "could not parse {} as a number",
189 *value,
190 ))),
191 },
192 Yaml::Real(value) => value.parse().map_err(|e| {
193 YamlContentErr::new(format!("could not parse {value} as a number: {e:?}"))
194 }),
195 _ => Err(YamlContentErr::new(format!(
196 "expected Integer or Real, but is {value:?}",
197 ))),
198 }
199}
200
201pub fn get_numeric_by_key<T: str::FromStr + num_traits::FromPrimitive>(
207 map: &linked_hash_map::LinkedHashMap<Yaml, Yaml>,
208 key: &str,
209) -> Result<T, YamlContentErr>
210where
211 <T as str::FromStr>::Err: fmt::Debug,
212{
213 match map.get(&Yaml::String(String::from(key))) {
214 Some(value) => get_numeric(value),
215 None => Err(YamlContentErr::new(format!("key `{key}` not found"))),
216 }
217}
218
219pub fn get_string(value: &Yaml) -> Result<String, YamlContentErr> {
225 match value {
226 Yaml::String(string) => Ok(string.clone()),
227 _ => Err(YamlContentErr::new(format!(
228 "expected String, but {value:?}",
229 ))),
230 }
231}
232
233pub fn get_string_array(value: &Yaml) -> Result<Vec<String>, YamlContentErr> {
239 match value {
240 Yaml::Array(value) => parse_string_array(value),
241 _ => Err(YamlContentErr::new(format!(
242 "expected Array, but is `{value:?}`",
243 ))),
244 }
245}
246
247pub fn get_size_from_yaml(
255 item: &Yaml,
256 metadata: &StateMetadata,
257) -> Result<usize, Box<dyn error::Error>> {
258 match item {
259 Yaml::String(object) => {
260 if let Some(index) = metadata.name_to_object_type.get(object) {
261 Ok(metadata.object_numbers[*index])
262 } else {
263 Err(YamlContentErr::new(format!("no such object `{object}`",)).into())
264 }
265 }
266 Yaml::Integer(size) => Ok(usize::try_from(*size)?),
267 _ => Err(YamlContentErr::new("Invalid table arg elements".to_owned()).into()),
268 }
269}
270
271pub fn get_table_arg_array(
279 arg_array: &Array,
280 metadata: &StateMetadata,
281) -> Result<Vec<usize>, Box<dyn error::Error>> {
282 arg_array
283 .iter()
284 .map(|item: &Yaml| get_size_from_yaml(item, metadata))
285 .collect()
286}
287
288pub fn get_string_by_key(
294 map: &linked_hash_map::LinkedHashMap<Yaml, Yaml>,
295 key: &str,
296) -> Result<String, YamlContentErr> {
297 match map.get(&Yaml::String(String::from(key))) {
298 Some(value) => get_string(value),
299 None => Err(YamlContentErr::new(format!("key `{key}` not found"))),
300 }
301}
302
303fn parse_string_array(array: &[Yaml]) -> Result<Vec<String>, YamlContentErr> {
309 let mut result = Vec::with_capacity(array.len());
310 for v in array {
311 result.push(get_string(v)?);
312 }
313 Ok(result)
314}
315
316#[cfg(test)]
317mod tests {
318 use rustc_hash::FxHashMap;
319
320 use super::*;
321
322 #[test]
323 fn get_map_ok() {
324 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
325 map.insert(Yaml::Integer(0), Yaml::Integer(2));
326 let yaml = Yaml::Hash(map);
327 let map = get_map(&yaml);
328 assert!(map.is_ok());
329 let map = map.unwrap();
330 assert_eq!(map.len(), 1);
331 assert!(matches!(map.get(&Yaml::Integer(0)), Some(Yaml::Integer(2))));
332 }
333
334 #[test]
335 fn get_map_err() {
336 let yaml = Yaml::Array(vec![Yaml::Integer(0), Yaml::Integer(1), Yaml::Integer(2)]);
337 let map = get_map(&yaml);
338 assert!(map.is_err());
339 }
340
341 #[test]
342 fn get_yaml_by_key_ok() {
343 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
344 map.insert(Yaml::String(String::from("yaml")), Yaml::Integer(2));
345 let yaml = get_yaml_by_key(&map, "yaml");
346 assert!(yaml.is_ok());
347 assert!(matches!(yaml.unwrap(), Yaml::Integer(2)));
348 }
349
350 #[test]
351 fn get_yaml_by_key_err() {
352 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
353 map.insert(Yaml::String(String::from("yaml")), Yaml::Integer(2));
354 let yaml = get_yaml_by_key(&map, "json");
355 assert!(yaml.is_err());
356 }
357
358 #[test]
359 fn get_array_ok() {
360 let yaml = Yaml::Array(vec![Yaml::Integer(0), Yaml::Integer(1)]);
361 let array = get_array(&yaml);
362 assert!(array.is_ok());
363 let array = array.unwrap();
364 assert_eq!(array.len(), 2);
365 assert!(matches!(array[0], Yaml::Integer(0)));
366 assert!(matches!(array[1], Yaml::Integer(1)));
367 }
368
369 #[test]
370 fn get_array_err() {
371 let yaml = Yaml::Integer(0);
372 let array = get_array(&yaml);
373 assert!(array.is_err());
374 }
375
376 #[test]
377 fn get_bool_ok() {
378 let yaml = Yaml::Boolean(true);
379 let result = get_bool(&yaml);
380 assert!(result.is_ok());
381 assert!(result.unwrap());
382 }
383
384 #[test]
385 fn get_bool_err() {
386 let yaml = Yaml::Integer(0);
387 let result = get_bool(&yaml);
388 assert!(result.is_err());
389 }
390
391 #[test]
392 fn get_bool_by_key_ok() {
393 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
394 map.insert(Yaml::String(String::from("bool")), Yaml::Boolean(true));
395 let result = get_bool_by_key(&map, "bool");
396 assert!(result.is_ok());
397 assert!(result.unwrap());
398 }
399
400 #[test]
401 fn get_bool_by_key_err() {
402 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
403 map.insert(Yaml::String(String::from("integer")), Yaml::Integer(0));
404 let result = get_bool_by_key(&map, "array");
405 assert!(result.is_err());
406 let result = get_bool_by_key(&map, "integer");
407 assert!(result.is_err());
408 }
409
410 #[test]
411 fn get_usize_ok() {
412 let yaml = Yaml::Integer(0);
413 let result = get_usize(&yaml);
414 assert!(result.is_ok());
415 assert_eq!(result.unwrap(), 0);
416 }
417
418 #[test]
419 fn get_usize_err() {
420 let yaml = Yaml::Real(String::from("0.0"));
421 let result = get_usize(&yaml);
422 assert!(result.is_err());
423
424 let yaml = Yaml::Integer(-1);
425 let result = get_usize(&yaml);
426 assert!(result.is_err());
427 }
428
429 #[test]
430 fn get_usize_array_ok() {
431 let yaml = Yaml::Array(vec![Yaml::Integer(0), Yaml::Integer(1)]);
432 let array = get_usize_array(&yaml);
433 assert!(array.is_ok());
434 assert_eq!(array.unwrap(), vec![0, 1]);
435 }
436
437 #[test]
438 fn get_usize_array_err() {
439 let yaml = Yaml::Integer(0);
440 let array = get_usize_array(&yaml);
441 assert!(array.is_err());
442
443 let yaml = Yaml::Array(vec![Yaml::Integer(0), Yaml::Boolean(true)]);
444 let array = get_usize_array(&yaml);
445 assert!(array.is_err());
446
447 let yaml = Yaml::Array(vec![Yaml::Integer(0), Yaml::Integer(-1)]);
448 let array = get_usize_array(&yaml);
449 assert!(array.is_err());
450 }
451
452 #[test]
453 fn get_usize_by_key_ok() {
454 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
455 map.insert(Yaml::String(String::from("usize")), Yaml::Integer(0));
456 let result = get_usize_by_key(&map, "usize");
457 assert!(result.is_ok());
458 assert_eq!(result.unwrap(), 0);
459 }
460
461 #[test]
462 fn get_usize_by_key_err() {
463 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
464 map.insert(Yaml::String(String::from("bool")), Yaml::Boolean(true));
465 map.insert(Yaml::String(String::from("integer")), Yaml::Integer(-1));
466 let result = get_usize_by_key(&map, "array");
467 assert!(result.is_err());
468 let result = get_usize_by_key(&map, "bool");
469 assert!(result.is_err());
470 let result = get_usize_by_key(&map, "integer");
471 assert!(result.is_err());
472 }
473
474 #[test]
475 fn get_usize_array_by_key_ok() {
476 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
477 map.insert(
478 Yaml::String(String::from("array")),
479 Yaml::Array(vec![Yaml::Integer(0), Yaml::Integer(1)]),
480 );
481 let array = get_usize_array_by_key(&map, "array");
482 assert!(array.is_ok());
483 assert_eq!(array.unwrap(), vec![0, 1]);
484 }
485
486 #[test]
487 fn get_usize_array_by_key_err() {
488 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
489 map.insert(
490 Yaml::String(String::from("array1")),
491 Yaml::Array(vec![Yaml::Integer(0), Yaml::Boolean(true)]),
492 );
493 map.insert(
494 Yaml::String(String::from("array2")),
495 Yaml::Array(vec![Yaml::Integer(0), Yaml::Integer(-1)]),
496 );
497 let array = get_usize_array_by_key(&map, "array");
498 assert!(array.is_err());
499 let array = get_usize_array_by_key(&map, "array1");
500 assert!(array.is_err());
501 let array = get_usize_array_by_key(&map, "array2");
502 assert!(array.is_err());
503 }
504
505 #[test]
506 fn get_numeric_ok() {
507 let yaml = Yaml::Integer(0);
508 let result = get_numeric::<variable_type::Integer>(&yaml);
509 assert!(result.is_ok());
510 assert_eq!(result.unwrap(), 0);
511 }
512
513 #[test]
514 fn get_numeric_err() {
515 let yaml = Yaml::Real(String::from("0.5"));
516 let result = get_numeric::<variable_type::Integer>(&yaml);
517 assert!(result.is_err());
518 let yaml = Yaml::Boolean(true);
519 let result = get_numeric::<variable_type::Integer>(&yaml);
520 assert!(result.is_err());
521 }
522
523 #[test]
524 fn get_numeric_by_key_ok() {
525 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
526 map.insert(Yaml::String(String::from("numeric")), Yaml::Integer(0));
527 let result = get_numeric_by_key::<variable_type::Integer>(&map, "numeric");
528 assert!(result.is_ok());
529 assert_eq!(result.unwrap(), 0);
530 }
531
532 #[test]
533 fn get_numeric_by_key_err() {
534 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
535 map.insert(
536 Yaml::String(String::from("numeric")),
537 Yaml::Real(String::from("0.5")),
538 );
539 map.insert(Yaml::String(String::from("bool")), Yaml::Boolean(true));
540 let result = get_numeric_by_key::<variable_type::Integer>(&map, "integer");
541 assert!(result.is_err());
542 let result = get_numeric_by_key::<variable_type::Integer>(&map, "bool");
543 assert!(result.is_err());
544 let result = get_numeric_by_key::<variable_type::Integer>(&map, "numeric");
545 assert!(result.is_err());
546 }
547
548 #[test]
549 fn get_string_ok() {
550 let yaml = Yaml::String(String::from("string"));
551 let result = get_string(&yaml);
552 assert!(result.is_ok());
553 assert_eq!(result.unwrap(), String::from("string"));
554 }
555
556 #[test]
557 fn get_string_err() {
558 let yaml = Yaml::Real(String::from("0.0"));
559 let result = get_string(&yaml);
560 assert!(result.is_err());
561 }
562
563 #[test]
564 fn get_string_array_ok() {
565 let yaml = Yaml::Array(vec![
566 Yaml::String(String::from("0")),
567 Yaml::String(String::from("1")),
568 ]);
569 let array = get_string_array(&yaml);
570 assert!(array.is_ok());
571 assert_eq!(array.unwrap(), vec![String::from("0"), String::from("1")]);
572 }
573
574 #[test]
575 fn get_string_array_err() {
576 let yaml = Yaml::Integer(0);
577 let array = get_string_array(&yaml);
578 assert!(array.is_err());
579
580 let yaml = Yaml::Array(vec![Yaml::String(String::from("0")), Yaml::Boolean(true)]);
581 let array = get_string_array(&yaml);
582 assert!(array.is_err());
583 }
584
585 #[test]
586 fn get_size_from_yaml_ok() {
587 let yaml = Yaml::Integer(1);
588 let size = get_size_from_yaml(&yaml, &StateMetadata::default());
589 assert!(size.is_ok());
590 assert_eq!(size.unwrap(), 1);
591
592 let yaml = Yaml::String("object".to_owned());
593 let mut name_to_object_type = FxHashMap::default();
594 name_to_object_type.insert("object".to_owned(), 0);
595 let state_metadata = StateMetadata {
596 name_to_object_type,
597 object_numbers: vec![10],
598 ..Default::default()
599 };
600 let size = get_size_from_yaml(&yaml, &state_metadata);
601 assert!(size.is_ok());
602 assert_eq!(size.unwrap(), 10);
603 }
604
605 #[test]
606 fn get_size_from_yaml_err() {
607 let yaml = Yaml::Array(vec![]);
608 let size = get_size_from_yaml(&yaml, &StateMetadata::default());
609 assert!(size.is_err());
610
611 let yaml = Yaml::String("object".to_owned());
612 let size = get_size_from_yaml(&yaml, &StateMetadata::default());
613 assert!(size.is_err());
614 }
615
616 #[test]
617 fn get_table_arg_array_ok() {
618 let arg_array = vec![Yaml::Integer(1), Yaml::String("object".to_owned())];
619 let mut name_to_object_type = FxHashMap::default();
620 name_to_object_type.insert("object".to_owned(), 0);
621 let state_metadata = StateMetadata {
622 name_to_object_type,
623 object_numbers: vec![10],
624 ..Default::default()
625 };
626
627 let sizes = get_table_arg_array(&arg_array, &state_metadata);
628 assert!(sizes.is_ok());
629 assert_eq!(sizes.unwrap(), vec![1, 10]);
630 }
631
632 #[test]
633 fn get_table_arg_array_err() {
634 let arg_array = vec![
635 Yaml::Integer(1),
636 Yaml::String("non_exist_object".to_owned()),
637 ];
638 let mut name_to_object_type = FxHashMap::default();
639 name_to_object_type.insert("object".to_owned(), 0);
640 let state_metadata = StateMetadata {
641 name_to_object_type,
642 object_numbers: vec![10],
643 ..Default::default()
644 };
645
646 let sizes = get_table_arg_array(&arg_array, &state_metadata);
647 assert!(sizes.is_err());
648 }
649
650 #[test]
651 fn get_string_by_key_ok() {
652 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
653 map.insert(
654 Yaml::String(String::from("string")),
655 Yaml::String(String::from("0")),
656 );
657 let result = get_string_by_key(&map, "string");
658 assert!(result.is_ok());
659 assert_eq!(result.unwrap(), String::from("0"));
660 }
661
662 #[test]
663 fn get_string_by_key_err() {
664 let mut map = linked_hash_map::LinkedHashMap::<Yaml, Yaml>::new();
665 map.insert(Yaml::String(String::from("bool")), Yaml::Boolean(true));
666 let result = get_string_by_key(&map, "array");
667 assert!(result.is_err());
668 let result = get_string_by_key(&map, "bool");
669 assert!(result.is_err());
670 }
671}