1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Node features advertized on the network.
use std::{fmt, ops};

/// Advertized node features. Signals what services the node supports.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Features(u64);

impl Features {
    /// `NONE` means no features are supported.
    pub const NONE: Features = Features(0b00000000);

    /// `SEED` is the base feature set all seed nodes must support.
    pub const SEED: Features = Features(0b00000001);

    /// Returns [`Features`] with the other features added.
    #[must_use]
    pub fn with(self, other: Features) -> Features {
        Self(self.0 | other.0)
    }

    /// Returns [`Features`] without the other features.
    #[must_use]
    pub fn without(self, other: Features) -> Features {
        Self(self.0 ^ other.0)
    }

    /// Check whether [`Features`] are included.
    pub fn has(self, flags: Features) -> bool {
        (self.0 | flags.0) == self.0
    }
}

impl Default for Features {
    fn default() -> Self {
        Self::NONE
    }
}

impl ops::Deref for Features {
    type Target = u64;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl fmt::LowerHex for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::LowerHex::fmt(&self.0, f)
    }
}

impl fmt::UpperHex for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::UpperHex::fmt(&self.0, f)
    }
}

impl fmt::Display for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if *self == Features::NONE {
            write!(f, "Features(NONE)")
        } else {
            write!(f, "Features(0x{:x})", self.0)
        }
    }
}

impl From<u64> for Features {
    fn from(f: u64) -> Self {
        Features(f)
    }
}

impl From<Features> for u64 {
    fn from(flags: Features) -> Self {
        flags.0
    }
}

impl ops::BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        self.with(rhs)
    }
}

impl ops::BitOrAssign for Features {
    fn bitor_assign(&mut self, rhs: Self) {
        *self = self.with(rhs);
    }
}

impl ops::BitXor for Features {
    type Output = Self;

    fn bitxor(self, rhs: Self) -> Self {
        self.without(rhs)
    }
}

impl ops::BitXorAssign for Features {
    fn bitxor_assign(&mut self, rhs: Self) {
        *self = self.without(rhs);
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_operations() {
        assert_eq!(Features::NONE.with(Features::SEED), Features::SEED);

        assert!(!Features::from(u64::MAX)
            .without(Features::SEED)
            .has(Features::SEED));

        assert!(Features::from(u64::MIN)
            .with(Features::SEED)
            .has(Features::SEED));

        assert_eq!(
            Features::NONE.with(Features::SEED).without(Features::SEED),
            Features::NONE
        );
    }
}