Skip to main content

gmt_fem_code_builder/
names.rs

1use std::{
2    fmt::{self, Display},
3    ops::Deref,
4};
5
6/// FEM inputs/ouputs names & descriptions
7#[derive(Default)]
8pub struct Name {
9    pub name: String,
10    pub description: Vec<String>,
11}
12impl fmt::Debug for Name {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        f.debug_struct("Name")
15            .field("name", &self.name)
16            .field("description", &self.description[0])
17            .finish()
18    }
19}
20impl Deref for Name {
21    type Target = str;
22
23    fn deref(&self) -> &Self::Target {
24        self.name.as_str()
25    }
26}
27impl Display for Name {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        write!(f, "{}", self.name)
30    }
31}
32impl<S: Into<String>> From<S> for Name {
33    fn from(name: S) -> Self {
34        Name {
35            name: name.into(),
36            ..Default::default()
37        }
38    }
39}
40impl From<&Name> for String {
41    fn from(value: &Name) -> Self {
42        value.name.clone()
43    }
44}
45impl Name {
46    /// Adds to the [Name] description
47    pub fn push_description(&mut self, description: String) {
48        self.description.push(description);
49    }
50    /// Returns the input or output `name` as `Enum` variant type
51    pub fn variant(&self) -> String {
52        self.split("_")
53            .map(|s| {
54                let (first, last) = s.split_at(1);
55                first.to_uppercase() + last
56            })
57            .collect::<String>()
58    }
59    /**
60    Returns the code representing the input or ouput as an empty `Enum`
61
62    ```
63    pub enum {variant} {}
64    ```
65    */
66    pub fn enum_variant(&self) -> String {
67        let descriptions: Vec<_> = self
68            .description
69            .iter()
70            .map(|d| {
71                format!(
72                    r##"
73 1. {}
74            "##,
75                    d
76                )
77            })
78            .collect();
79        format!(
80            r##"
81            #[doc = "{name}"]
82            #[doc = ""]
83            #[doc = "{descriptions}"]
84        #[derive(Debug, ::interface::UID)]
85        pub enum {variant} {{}}
86        "##,
87            name = self.name,
88            descriptions = descriptions.join("\n"),
89            variant = self.variant()
90        )
91    }
92    /**
93    Returns the code implementing `FemIo<variant>`
94
95    ```
96        impl FemIo<{variant}> for Vec<Option<{io}>> {
97            fn position(&self) -> Option<usize>{
98                self.iter().filter_map(|x| x.as_ref())
99                        .position(|x| if let {io}::{variant}(_) = x {true} else {false})
100            }
101        }
102    ```
103    where `io` is another `Enum` that may have the same `variant`
104    */
105    pub fn impl_enum_variant_for_io(&self, io: &str) -> String {
106        format!(
107            r##"
108        impl FemIo<{variant}> for Vec<Option<{io}>> {{
109            fn position(&self) -> Option<usize>{{
110                self.iter().filter_map(|x| x.as_ref())
111                        .position(|x| if let {io}::{variant}(_) = x {{true}} else {{false}})
112            }}
113        }}
114        "##,
115            variant = self.variant(),
116            io = io
117        )
118    }
119}
120
121/// A list of FEM inputs or outputs [Name]
122#[derive(Debug, Default)]
123pub struct Names(Vec<Name>);
124impl Names {
125    /// Searches for a particular name
126    ///
127    /// Return `Some(name)` if it exists
128    pub fn find<S: AsRef<str>>(&self, aname: S) -> Option<String> {
129        self.iter()
130            .find(|name| name.variant().as_str() == aname.as_ref())
131            .map(|name| name.name.clone())
132    }
133}
134impl FromIterator<Name> for Names {
135    fn from_iter<T: IntoIterator<Item = Name>>(iter: T) -> Self {
136        Self(iter.into_iter().collect())
137    }
138}
139impl FromIterator<String> for Names {
140    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
141        Self(iter.into_iter().map(|x| x.into()).collect())
142    }
143}
144impl Deref for Names {
145    type Target = Vec<Name>;
146
147    fn deref(&self) -> &Self::Target {
148        &self.0
149    }
150}
151impl Display for Names {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        for variant in self.iter() {
154            write!(f, "{}", variant.enum_variant())?;
155        }
156        Ok(())
157    }
158}