cube2rust/
utils.rs

1use std::collections::HashMap;
2use std::convert::TryFrom;
3
4use anyhow::{anyhow, bail};
5
6pub fn parse_optional_param<'a, T>(
7    parameters: &'a HashMap<&str, &str>,
8    param_name: &str,
9) -> anyhow::Result<Option<T>, anyhow::Error>
10where
11    T: TryFrom<&'a str, Error = anyhow::Error>,
12{
13    parameters
14        .get(param_name)
15        .map(|s| T::try_from(*s))
16        .transpose()
17}
18
19pub fn parse_mandatory_param<'a, T>(
20    parameters: &'a HashMap<&str, &str>,
21    param_name: &str,
22) -> anyhow::Result<T, anyhow::Error>
23where
24    T: TryFrom<&'a str, Error = anyhow::Error>,
25{
26    let &param = parameters
27        .get(param_name)
28        .ok_or_else(|| anyhow!("{} parameter required", param_name))?;
29    T::try_from(param)
30}
31
32pub fn parse_mandatory_u32(
33    parameters: &HashMap<&str, &str>,
34    param_name: &str,
35) -> anyhow::Result<u32> {
36    Ok(parameters
37        .get(param_name)
38        .ok_or_else(|| anyhow!(f!("{param_name} parameter not found")))?
39        .parse()
40        .map_err(|_| anyhow!(f!("{param_name} parameter invalid integer")))?)
41}
42
43pub fn parse_optional_u32(
44    parameters: &HashMap<&str, &str>,
45    param_name: &str,
46) -> anyhow::Result<Option<u32>> {
47    parameters
48        .get(param_name)
49        .map(|s| {
50            s.parse()
51                .map_err(|_| anyhow!(f!("{param_name} parameter invalid integer")))
52        })
53        .transpose()
54}
55
56// Generate an enum with an TryFrom<&str> implementation that converts from a string to a enum variant
57// enum will also derive Debug, Copy, Clone, PartialEq
58macro_rules! parameter {
59    ($enumname:ident, [$($variant: ident), *]) => {
60        #[allow(non_camel_case_types)]
61        #[derive(Debug, Copy, Clone, PartialEq)]
62        pub enum $enumname {
63            $(
64                $variant,
65            )*
66        }
67
68        impl std::convert::TryFrom<&str> for $enumname {
69            type Error = anyhow::Error;
70
71            fn try_from(text: &str) -> anyhow::Result<Self, Self::Error> {
72                match text {
73                    $(
74                        stringify!($variant) => Ok($enumname::$variant),
75                    )*
76                    _ => bail!(concat!("invalid ", stringify!($enumname), " {}"), text),
77                }
78            }
79        }
80    };
81    ($enumname:ident, [$($variant: ident), *], default=$default_variant: ident) => {
82        parameter!($enumname, [$($variant), *]);
83        impl Default for $enumname {
84            fn default() -> Self {
85                $enumname::$default_variant
86            }
87        }
88    };
89}
90
91parameter!(
92    MCUFamily,
93    [
94        STM32F0, STM32F1, STM32F2, STM32F3, STM32F4, STM32F7, STM32G0, STM32G4, STM32H7, STM32L0,
95        STM32L1, STM32L4, STM32L5, STM32MP1, STM32WB, STM32WL
96    ]
97);
98
99pub struct GeneratedString {
100    pub string: String,
101    indent: usize,
102}
103
104impl GeneratedString {
105    pub fn new() -> Self {
106        GeneratedString {
107            string: String::new(),
108            indent: 0,
109        }
110    }
111
112    pub fn line<T: AsRef<str>>(&mut self, line: T) {
113        let indent = " ".repeat(self.indent);
114        let content = line.as_ref();
115        self.string.push_str(&f!("{indent}{content}\n"));
116    }
117
118    pub fn empty_line(&mut self) {
119        self.string.push_str("\n");
120    }
121
122    pub fn indent_right(&mut self) {
123        self.indent += 4;
124    }
125
126    pub fn indent_left(&mut self) {
127        self.indent = self.indent.saturating_sub(4);
128    }
129}