1
//! Consensus method, including checked wrapper type
2

            
3
use super::*;
4

            
5
/// Consensus method that is supported by this crate
6
///
7
/// Contains a `ConsensusMethod`, with the additional invariant that it's supported here.
8
///
9
/// Taken as an argument by at least all pub entrypoints that might be influenced
10
/// by the consensus method, so also functions as a proof token that we are running
11
/// for a supported method.
12
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] //
13
#[derive(derive_more::Display, derive_more::Deref, derive_more::Into)]
14
pub struct SupportedConsensusMethod(ConsensusMethod);
15

            
16
/// Unsupported consensus method error
17
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, thiserror::Error)]
18
#[error("unsupported consensus method {requested_method}")]
19
pub struct UnsupportedConsensusMethod {
20
    /// the method number
21
    requested_method: ConsensusMethod,
22
}
23

            
24
impl TryFrom<ConsensusMethod> for SupportedConsensusMethod {
25
    type Error = UnsupportedConsensusMethod;
26
70
    fn try_from(requested_method: ConsensusMethod) -> Result<Self, Self::Error> {
27
70
        if SUPPORTED_METHODS
28
70
            .iter()
29
105
            .any(|r| r.contains(&requested_method))
30
        {
31
68
            Ok(SupportedConsensusMethod(requested_method))
32
        } else {
33
2
            Err(UnsupportedConsensusMethod { requested_method })
34
        }
35
70
    }
36
}
37

            
38
impl SupportedConsensusMethod {
39
    /// Iterate over all supported methods
40
64
    pub fn iter_all() -> impl Iterator<Item = SupportedConsensusMethod> {
41
64
        SUPPORTED_METHODS
42
64
            .iter()
43
160
            .flat_map(|r| map_range(r, |b| u32::from(*b)))
44
96
            .map(|v: u32| {
45
64
                SupportedConsensusMethod::try_from(ConsensusMethod(v))
46
64
                    .expect("from our own ranges of supported methods")
47
64
            })
48
64
    }
49
}
50

            
51
// Convenience impl so you can write write (eg) method < 110 rather than **method < 110.
52
impl PartialOrd<u32> for SupportedConsensusMethod {
53
2
    fn partial_cmp(&self, other: &u32) -> Option<cmp::Ordering> {
54
2
        u32::partial_cmp(&(**self).0, other)
55
2
    }
56
}
57
impl PartialEq<u32> for SupportedConsensusMethod {
58
2
    fn eq(&self, other: &u32) -> bool {
59
2
        u32::eq(&(**self).0, other)
60
2
    }
61
}
62

            
63
impl SupportedConsensusMethod {
64
    /// Most recent method supported here
65
    #[cfg(test)]
66
    pub(crate) const MAX: SupportedConsensusMethod =
67
        SupportedConsensusMethod(*SUPPORTED_METHODS.last().unwrap().end());
68

            
69
    /// Make a `SupportedConsensusMethod` out of a possibly-unsupported `ConsensusMethod`
70
    ///
71
    /// Useful for test cases that don't use real method numbers.
72
    #[cfg(test)]
73
398
    pub(crate) fn new_unchecked(method: ConsensusMethod) -> SupportedConsensusMethod {
74
398
        SupportedConsensusMethod(method)
75
398
    }
76
}
77

            
78
#[cfg(test)]
79
mod test {
80
    // @@ begin test lint list maintained by maint/add_warning @@
81
    #![allow(clippy::bool_assert_comparison)]
82
    #![allow(clippy::clone_on_copy)]
83
    #![allow(clippy::dbg_macro)]
84
    #![allow(clippy::mixed_attributes_style)]
85
    #![allow(clippy::print_stderr)]
86
    #![allow(clippy::print_stdout)]
87
    #![allow(clippy::single_char_pattern)]
88
    #![allow(clippy::unwrap_used)]
89
    #![allow(clippy::unchecked_time_subtraction)]
90
    #![allow(clippy::useless_vec)]
91
    #![allow(clippy::needless_pass_by_value)]
92
    #![allow(clippy::string_slice)] // See arti#2571
93
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
94
    use super::*;
95

            
96
    #[test]
97
    fn basic() {
98
        let v: SupportedConsensusMethod =
99
            ConsensusMethod(crate::consensus::SUPPORTED_METHODS[0].start().0)
100
                .try_into()
101
                .unwrap();
102

            
103
        assert!(v >= 100); // our methods are defined to start at 100
104
        assert_eq!(v.to_string(), u32::from(v.0).to_string(),);
105

            
106
        let e = SupportedConsensusMethod::try_from(ConsensusMethod(10_000)).unwrap_err();
107
        let m = e.to_string();
108
        assert!(m.contains("unsupported consensus method 10000"), "{m:?}");
109
    }
110

            
111
    #[test]
112
    fn iter_all() {
113
        println!("{:?}", SupportedConsensusMethod::iter_all().collect_vec());
114
    }
115
}