Skip to main content

eml_nl/utils/
voting_method.rs

1use thiserror::Error;
2
3use crate::{EMLError, EMLValueResultExt as _, utils::StringValueData};
4
5/// Voting method used in the election.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum VotingMethod {
8    /// Additional Member System
9    AMS,
10    /// First Past the Post
11    FPP,
12    /// Instant Runoff Voting
13    IRV,
14    /// Norwegian Voting
15    NOR,
16    /// Optional Preferential Voting
17    OPV,
18    /// Ranked Choice Voting
19    RCV,
20    /// Single Preferential Vote
21    SPV,
22    /// Single Transferable Vote
23    STV,
24    /// Cumulative Voting
25    Cumulative,
26    /// Approval Voting
27    Approval,
28    /// Block Voting
29    Block,
30    /// Supporter List Voting
31    SupporterList,
32    /// Partisan Voting
33    Partisan,
34    /// Supplementary Vote
35    SupplementaryVote,
36    /// Other Voting Method
37    Other,
38}
39
40impl VotingMethod {
41    /// Create a new VotingMethod from a string, validating its format.
42    pub fn new(s: impl AsRef<str>) -> Result<Self, EMLError> {
43        Self::from_eml_value(s).wrap_value_error()
44    }
45
46    /// Create a VotingMethod from a `&str`, if possible.
47    pub fn from_eml_value(s: impl AsRef<str>) -> Result<Self, UnknownVotingMethodError> {
48        let data = s.as_ref();
49        match data {
50            "AMS" => Ok(VotingMethod::AMS),
51            "FPP" => Ok(VotingMethod::FPP),
52            "IRV" => Ok(VotingMethod::IRV),
53            "NOR" => Ok(VotingMethod::NOR),
54            "OPV" => Ok(VotingMethod::OPV),
55            "RCV" => Ok(VotingMethod::RCV),
56            "SPV" => Ok(VotingMethod::SPV),
57            "STV" => Ok(VotingMethod::STV),
58            "cumulative" => Ok(VotingMethod::Cumulative),
59            "approval" => Ok(VotingMethod::Approval),
60            "block" => Ok(VotingMethod::Block),
61            "supporterlist" => Ok(VotingMethod::SupporterList),
62            "partisan" => Ok(VotingMethod::Partisan),
63            "supplementaryvote" => Ok(VotingMethod::SupplementaryVote),
64            "other" => Ok(VotingMethod::Other),
65            _ => Err(UnknownVotingMethodError(data.to_string())),
66        }
67    }
68
69    /// Get the `&str` representation of this VotingMethod.
70    pub fn to_eml_value(&self) -> &'static str {
71        match self {
72            VotingMethod::AMS => "AMS",
73            VotingMethod::FPP => "FPP",
74            VotingMethod::IRV => "IRV",
75            VotingMethod::NOR => "NOR",
76            VotingMethod::OPV => "OPV",
77            VotingMethod::RCV => "RCV",
78            VotingMethod::SPV => "SPV",
79            VotingMethod::STV => "STV",
80            VotingMethod::Cumulative => "cumulative",
81            VotingMethod::Approval => "approval",
82            VotingMethod::Block => "block",
83            VotingMethod::SupporterList => "supporterlist",
84            VotingMethod::Partisan => "partisan",
85            VotingMethod::SupplementaryVote => "supplementaryvote",
86            VotingMethod::Other => "other",
87        }
88    }
89}
90
91/// Error returned when an unknown voting method string is encountered.
92#[derive(Debug, Clone, Error, PartialEq, Eq)]
93#[error("Unknown voting method: {0}")]
94pub struct UnknownVotingMethodError(String);
95
96impl StringValueData for VotingMethod {
97    type Error = UnknownVotingMethodError;
98
99    fn parse_from_str(s: &str) -> Result<Self, Self::Error>
100    where
101        Self: Sized,
102    {
103        Self::from_eml_value(s)
104    }
105
106    fn to_raw_value(&self) -> String {
107        self.to_eml_value().to_string()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_voting_method_from_str() {
117        assert_eq!(VotingMethod::from_eml_value("AMS"), Ok(VotingMethod::AMS));
118        assert_eq!(VotingMethod::from_eml_value("FPP"), Ok(VotingMethod::FPP));
119        assert_eq!(VotingMethod::from_eml_value("SPV"), Ok(VotingMethod::SPV));
120        assert_eq!(
121            VotingMethod::from_eml_value("UNKNOWN"),
122            Err(UnknownVotingMethodError("UNKNOWN".to_string()))
123        );
124    }
125
126    #[test]
127    fn test_voting_method_to_str() {
128        assert_eq!(VotingMethod::AMS.to_eml_value(), "AMS");
129        assert_eq!(VotingMethod::FPP.to_eml_value(), "FPP");
130        assert_eq!(VotingMethod::SPV.to_eml_value(), "SPV");
131    }
132}