Skip to main content

eml_nl/utils/
election_category.rs

1use thiserror::Error;
2
3use crate::{EMLError, EMLValueResultExt as _, utils::StringValueData};
4
5/// Election category used in the election.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum ElectionCategory {
8    /// Eerste Kamer
9    EK,
10    /// Tweede Kamer
11    TK,
12    /// Europees Parlement
13    EP,
14    /// Provinciale Staten
15    PS,
16    /// Waterschapsverkiezingen
17    AB,
18    /// Gemeenteraad
19    GR,
20    /// Bestuurscommissie (Amsterdam, unused)
21    BC,
22    /// Gebiedscommissie (Rotterdam, unused)
23    GC,
24    /// Eilandsraad
25    ER,
26    /// Todo: Unknown meaning
27    NR,
28    /// Todo: Unknown meaning
29    PR,
30    /// Todo: Unknown meaning
31    LR,
32    /// Todo: Unknown meaning
33    IR,
34}
35
36impl ElectionCategory {
37    /// Create a new ElectionCategory from a string, validating its format
38    pub fn new(s: impl AsRef<str>) -> Result<Self, EMLError> {
39        Self::from_eml_value(s).wrap_value_error()
40    }
41
42    /// Create an [`ElectionCategory`] from a `&str`, if possible.
43    pub fn from_eml_value(s: impl AsRef<str>) -> Result<Self, UnknownElectionCategoryError> {
44        let data = s.as_ref();
45        match data {
46            "EK" => Ok(ElectionCategory::EK),
47            "TK" => Ok(ElectionCategory::TK),
48            "EP" => Ok(ElectionCategory::EP),
49            "PS" => Ok(ElectionCategory::PS),
50            "AB" => Ok(ElectionCategory::AB),
51            "GR" => Ok(ElectionCategory::GR),
52            "BC" => Ok(ElectionCategory::BC),
53            "GC" => Ok(ElectionCategory::GC),
54            "ER" => Ok(ElectionCategory::ER),
55            "NR" => Ok(ElectionCategory::NR),
56            "PR" => Ok(ElectionCategory::PR),
57            "LR" => Ok(ElectionCategory::LR),
58            "IR" => Ok(ElectionCategory::IR),
59            _ => Err(UnknownElectionCategoryError(data.to_string())),
60        }
61    }
62
63    /// Get the `&str` representation of this [`ElectionCategory`].
64    pub fn to_eml_value(&self) -> &'static str {
65        match self {
66            ElectionCategory::EK => "EK",
67            ElectionCategory::TK => "TK",
68            ElectionCategory::EP => "EP",
69            ElectionCategory::PS => "PS",
70            ElectionCategory::AB => "AB",
71            ElectionCategory::GR => "GR",
72            ElectionCategory::BC => "BC",
73            ElectionCategory::GC => "GC",
74            ElectionCategory::ER => "ER",
75            ElectionCategory::NR => "NR",
76            ElectionCategory::PR => "PR",
77            ElectionCategory::LR => "LR",
78            ElectionCategory::IR => "IR",
79        }
80    }
81}
82
83/// Error returned when an unknown election category string is encountered.
84#[derive(Debug, Clone, Error, PartialEq, Eq)]
85#[error("Unknown election category: {0}")]
86pub struct UnknownElectionCategoryError(String);
87
88impl StringValueData for ElectionCategory {
89    type Error = UnknownElectionCategoryError;
90
91    fn parse_from_str(s: &str) -> Result<Self, Self::Error>
92    where
93        Self: Sized,
94    {
95        Self::from_eml_value(s)
96    }
97
98    fn to_raw_value(&self) -> String {
99        self.to_eml_value().to_string()
100    }
101}
102
103/// Subcategory of the election, providing more specific information about the type of election.
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105pub enum ElectionSubcategory {
106    /// Provinciale Staten (one electoral district)
107    PS1,
108    /// Provinciale Staten (multiple electoral districts)
109    PS2,
110    /// Waterschapsverkiezingen (less than 19 seats)
111    AB1,
112    /// Waterschapsverkiezingen (19 or more seats)
113    AB2,
114    /// Gemeenteraad (less than 19 seats)
115    GR1,
116    /// Gemeenteraad (19 or more seats)
117    GR2,
118    /// Bestuurscommissie (Amsterdam, unused)
119    BC,
120    /// Gebiedscommissie (Rotterdam, unused)
121    GC,
122    /// Eilandsraad (less than 19 seats, all eilandraden have this)
123    ER1,
124    /// Tweede kamer
125    TK,
126    /// Eerste kamer
127    EK,
128    /// Europees Parlement
129    EP,
130    /// Todo: Unknown meaning
131    NR,
132    /// Todo: Unknown meaning
133    PR,
134    /// Todo: Unknown meaning
135    LR,
136    /// Todo: Unknown meaning
137    IR,
138}
139
140impl ElectionSubcategory {
141    /// Create a new ElectionSubcategory from a string, validating its format
142    pub fn new(s: impl AsRef<str>) -> Result<Self, EMLError> {
143        Self::from_eml_value(s).wrap_value_error()
144    }
145
146    /// Create a ElectionSubcategory from a `&str`, if possible.
147    pub fn from_eml_value(s: impl AsRef<str>) -> Result<Self, UnknownElectionSubcategoryError> {
148        let data = s.as_ref();
149        match data {
150            "PS1" => Ok(ElectionSubcategory::PS1),
151            "PS2" => Ok(ElectionSubcategory::PS2),
152            "AB1" => Ok(ElectionSubcategory::AB1),
153            "AB2" => Ok(ElectionSubcategory::AB2),
154            "GR1" => Ok(ElectionSubcategory::GR1),
155            "GR2" => Ok(ElectionSubcategory::GR2),
156            "BC" => Ok(ElectionSubcategory::BC),
157            "GC" => Ok(ElectionSubcategory::GC),
158            "ER1" => Ok(ElectionSubcategory::ER1),
159            "TK" => Ok(ElectionSubcategory::TK),
160            "EK" => Ok(ElectionSubcategory::EK),
161            "EP" => Ok(ElectionSubcategory::EP),
162            "NR" => Ok(ElectionSubcategory::NR),
163            "PR" => Ok(ElectionSubcategory::PR),
164            "LR" => Ok(ElectionSubcategory::LR),
165            "IR" => Ok(ElectionSubcategory::IR),
166            _ => Err(UnknownElectionSubcategoryError(data.to_string())),
167        }
168    }
169
170    /// Get the `&str` representation of this ElectionSubcategory.
171    pub fn to_eml_value(&self) -> &'static str {
172        match self {
173            ElectionSubcategory::PS1 => "PS1",
174            ElectionSubcategory::PS2 => "PS2",
175            ElectionSubcategory::AB1 => "AB1",
176            ElectionSubcategory::AB2 => "AB2",
177            ElectionSubcategory::GR1 => "GR1",
178            ElectionSubcategory::GR2 => "GR2",
179            ElectionSubcategory::BC => "BC",
180            ElectionSubcategory::GC => "GC",
181            ElectionSubcategory::ER1 => "ER1",
182            ElectionSubcategory::TK => "TK",
183            ElectionSubcategory::EK => "EK",
184            ElectionSubcategory::EP => "EP",
185            ElectionSubcategory::NR => "NR",
186            ElectionSubcategory::PR => "PR",
187            ElectionSubcategory::LR => "LR",
188            ElectionSubcategory::IR => "IR",
189        }
190    }
191
192    /// Check if this election subcategory is a subcategory of the given election category.
193    pub fn is_subcategory_of(self, category: ElectionCategory) -> bool {
194        match self {
195            ElectionSubcategory::PS1 | ElectionSubcategory::PS2 => category == ElectionCategory::PS,
196            ElectionSubcategory::AB1 | ElectionSubcategory::AB2 => category == ElectionCategory::AB,
197            ElectionSubcategory::GR1 | ElectionSubcategory::GR2 => category == ElectionCategory::GR,
198            ElectionSubcategory::BC => category == ElectionCategory::BC,
199            ElectionSubcategory::GC => category == ElectionCategory::GC,
200            ElectionSubcategory::ER1 => category == ElectionCategory::ER,
201            ElectionSubcategory::TK => category == ElectionCategory::TK,
202            ElectionSubcategory::EK => category == ElectionCategory::EK,
203            ElectionSubcategory::EP => category == ElectionCategory::EP,
204            ElectionSubcategory::NR => category == ElectionCategory::NR,
205            ElectionSubcategory::PR => category == ElectionCategory::PR,
206            ElectionSubcategory::LR => category == ElectionCategory::LR,
207            ElectionSubcategory::IR => category == ElectionCategory::IR,
208        }
209    }
210}
211
212/// Error returned when an unknown election subcategory string is encountered.
213#[derive(Debug, Clone, Error, PartialEq, Eq)]
214#[error("Unknown election subcategory: {0}")]
215pub struct UnknownElectionSubcategoryError(String);
216
217impl StringValueData for ElectionSubcategory {
218    type Error = UnknownElectionSubcategoryError;
219
220    fn parse_from_str(s: &str) -> Result<Self, Self::Error>
221    where
222        Self: Sized,
223    {
224        Self::from_eml_value(s)
225    }
226
227    fn to_raw_value(&self) -> String {
228        self.to_eml_value().to_string()
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235
236    #[test]
237    fn test_election_category_from_str() {
238        assert_eq!(
239            ElectionCategory::from_eml_value("EK"),
240            Ok(ElectionCategory::EK)
241        );
242        assert_eq!(
243            ElectionCategory::from_eml_value("TK"),
244            Ok(ElectionCategory::TK)
245        );
246        assert_eq!(
247            ElectionCategory::from_eml_value("UNKNOWN"),
248            Err(UnknownElectionCategoryError("UNKNOWN".to_string()))
249        );
250    }
251
252    #[test]
253    fn test_election_category_to_str() {
254        assert_eq!(ElectionCategory::EK.to_eml_value(), "EK");
255        assert_eq!(ElectionCategory::TK.to_eml_value(), "TK");
256    }
257}