dypdl/
util.rs

1use std::collections::hash_map::Entry;
2use std::error::Error;
3use std::fmt;
4
5use rustc_hash::FxHashMap;
6
7/// Error in modeling.
8#[derive(Debug)]
9pub struct ModelErr(String);
10
11impl ModelErr {
12    /// Creates a new error.
13    pub fn new(message: String) -> ModelErr {
14        ModelErr(format!("Error in problem definition: {message}"))
15    }
16}
17
18impl fmt::Display for ModelErr {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        write!(f, "{}", self.0)
21    }
22}
23
24impl Error for ModelErr {}
25
26pub fn get_id(name: &str, name_to_id: &FxHashMap<String, usize>) -> Result<usize, ModelErr> {
27    if let Some(id) = name_to_id.get(name) {
28        Ok(*id)
29    } else {
30        Err(ModelErr::new(format!("no such name `{name}`")))
31    }
32}
33
34pub fn add_name<T>(
35    name: T,
36    names: &mut Vec<String>,
37    name_to_id: &mut FxHashMap<String, usize>,
38) -> Result<usize, ModelErr>
39where
40    String: From<T>,
41{
42    let name = String::from(name);
43
44    match name_to_id.entry(name) {
45        Entry::Vacant(e) => {
46            let id = names.len();
47            names.push(e.key().clone());
48            e.insert(id);
49
50            Ok(id)
51        }
52        Entry::Occupied(e) => Err(ModelErr::new(format!(
53            "name `{key}` is already used",
54            key = e.key()
55        ))),
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_get_id() {
65        let name_to_id = FxHashMap::from(
66            [(String::from("a"), 0), (String::from("b"), 1)]
67                .into_iter()
68                .collect(),
69        );
70
71        let result = get_id("a", &name_to_id);
72        assert!(result.is_ok());
73        assert_eq!(result.unwrap(), 0);
74
75        let result = get_id("b", &name_to_id);
76        assert!(result.is_ok());
77        assert_eq!(result.unwrap(), 1);
78
79        let result = get_id("c", &name_to_id);
80        assert!(result.is_err());
81    }
82
83    #[test]
84    fn test_add_name() {
85        let mut names = Vec::default();
86        let mut name_to_id = FxHashMap::default();
87
88        let result = add_name("a", &mut names, &mut name_to_id);
89        assert!(result.is_ok());
90        assert_eq!(result.unwrap(), 0);
91
92        let result = add_name("b", &mut names, &mut name_to_id);
93        assert!(result.is_ok());
94        assert_eq!(result.unwrap(), 1);
95
96        let result = add_name("a", &mut names, &mut name_to_id);
97        assert!(result.is_err());
98    }
99}