arcs_ctf_yaml_parser/categories/
mod.rs1pub 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}