arcs_ctf_yaml_parser/categories/
mod.rs

1pub mod structs;
2
3use std::fmt::Display;
4
5pub use structs::Categories;
6
7use serde_yaml::Value as YamlValue;
8
9use crate::structs::{get_type, ValueType};
10
11
12#[derive(Debug, Clone, Default)]
13pub enum CategoryError {
14    InvalidCategories(Vec<String>, Vec<ValueType>),
15    InvalidBaseType(ValueType),
16    #[default]
17    MissingKey,
18}
19impl Display for CategoryError {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        use CategoryError::{InvalidBaseType, InvalidCategories, MissingKey};
22        match self {
23            InvalidCategories(names, types) => {
24                if !names.is_empty() {
25                    if names.len() == 1 {
26                        write!(f, "`{}` is not a valid category name.", names[0])?;
27                    } else {
28                        write!(f, "`{names:?}` are not valid category names.")?;
29                    }
30                }
31                if !types.is_empty() {
32                    write!(f, "Category names must also be strings.")?;
33                }
34            }
35            InvalidBaseType(t) => write!(f, "Categories should be a list, not {t}.")?,
36            MissingKey => write!(f, "You have to define `categories`.")?,
37        }
38        Ok(())
39    }
40}
41
42pub fn value_to_categories(value: &YamlValue) -> Result<Categories, CategoryError> {
43    use CategoryError::{InvalidBaseType, InvalidCategories};
44
45    if !value.is_sequence() {
46        return Err(InvalidBaseType(get_type(value)));
47    }
48
49    if let Some(sequence) = value.as_sequence() {
50        let mut cand_name = vec![];
51        let mut bad_type = vec![];
52
53        sequence.iter().for_each(
54            |val| if let Some(name) = val.as_str() {
55                cand_name.push(name);
56            } else {
57                bad_type.push(get_type(val));
58            }
59        );
60
61        match Categories::try_new(cand_name) {
62            Ok(categories) => if bad_type.is_empty() {
63                Ok(categories)
64            } else {
65                Err(InvalidCategories(Vec::new(), bad_type))
66            },
67            Err(bad_names) => Err(InvalidCategories(bad_names.into_iter().map(str::to_string).collect(), bad_type))
68        }
69    } else { unreachable!() }
70
71}