Skip to main content

ic_query/nns/neuron/report/
classification.rs

1//! Module: nns::neuron::report::classification
2//!
3//! Responsibility: define native NNS neuron classifications and their stable labels.
4//! Does not own: raw Governance DTOs, report assembly, or text layout.
5//! Boundary: retains unrecognized numeric codes instead of collapsing protocol evidence.
6
7use crate::nns::governance::{native_code_classification, native_optional_code_classification};
8
9native_code_classification! {
10    "state";
11    ///
12    /// NnsNeuronState
13    ///
14    /// Native NNS Governance neuron state with unrecognized codes retained.
15    ///
16
17    pub enum NnsNeuronState {
18        /// Governance supplied the unspecified state code.
19        Unspecified = 0 => "unspecified",
20        /// Neuron is not dissolving.
21        NotDissolving = 1 => "not-dissolving",
22        /// Neuron is dissolving.
23        Dissolving = 2 => "dissolving",
24        /// Neuron has dissolved.
25        Dissolved = 3 => "dissolved",
26        /// Neuron is spawning.
27        Spawning = 4 => "spawning",
28        ; unknown Unknown(i32),
29    }
30}
31
32native_optional_code_classification! {
33    "visibility";
34    ///
35    /// NnsNeuronVisibility
36    ///
37    /// Native optional NNS Governance neuron visibility with unknown evidence retained.
38    ///
39
40    pub enum NnsNeuronVisibility {
41        /// Governance omitted the optional visibility code.
42        Unknown,
43        /// Governance supplied the unspecified visibility code.
44        Unspecified = 0 => "unspecified",
45        /// Neuron is private.
46        Private = 1 => "private",
47        /// Neuron is public.
48        Public = 2 => "public",
49        ; unknown UnknownCode(i32),
50    }
51}
52
53native_optional_code_classification! {
54    "type";
55    ///
56    /// NnsNeuronType
57    ///
58    /// Native optional NNS Governance neuron type with unknown evidence retained.
59    ///
60
61    pub enum NnsNeuronType {
62        /// Governance omitted the optional neuron-type code.
63        Unknown,
64        /// Governance supplied the unspecified neuron-type code.
65        Unspecified = 0 => "unspecified",
66        /// Seed neuron.
67        Seed = 1 => "seed",
68        /// Early-contributor-token neuron.
69        Ect = 2 => "ect",
70        ; unknown UnknownCode(i32),
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::{NnsNeuronState, NnsNeuronType, NnsNeuronVisibility};
77
78    #[test]
79    fn required_classifications_preserve_codes_and_labels() {
80        for (code, state, label) in [
81            (0, NnsNeuronState::Unspecified, "unspecified"),
82            (1, NnsNeuronState::NotDissolving, "not-dissolving"),
83            (2, NnsNeuronState::Dissolving, "dissolving"),
84            (3, NnsNeuronState::Dissolved, "dissolved"),
85            (4, NnsNeuronState::Spawning, "spawning"),
86            (99, NnsNeuronState::Unknown(99), "unknown(99)"),
87        ] {
88            assert_eq!(NnsNeuronState::from_code(code), state);
89            assert_eq!(state.code(), code);
90            assert_eq!(state.to_string(), label);
91            assert_eq!(serde_json::to_value(state).expect("serialize state"), label);
92        }
93    }
94
95    #[test]
96    fn optional_classifications_distinguish_absent_and_unknown_codes() {
97        for (code, visibility, label) in [
98            (None, NnsNeuronVisibility::Unknown, "unknown"),
99            (Some(0), NnsNeuronVisibility::Unspecified, "unspecified"),
100            (Some(1), NnsNeuronVisibility::Private, "private"),
101            (Some(2), NnsNeuronVisibility::Public, "public"),
102            (
103                Some(99),
104                NnsNeuronVisibility::UnknownCode(99),
105                "unknown(99)",
106            ),
107        ] {
108            assert_eq!(NnsNeuronVisibility::from_code(code), visibility);
109            assert_eq!(visibility.code(), code);
110            assert_eq!(visibility.to_string(), label);
111            assert_eq!(
112                serde_json::to_value(visibility).expect("serialize visibility"),
113                label
114            );
115        }
116        for (code, neuron_type, label) in [
117            (None, NnsNeuronType::Unknown, "unknown"),
118            (Some(0), NnsNeuronType::Unspecified, "unspecified"),
119            (Some(1), NnsNeuronType::Seed, "seed"),
120            (Some(2), NnsNeuronType::Ect, "ect"),
121            (Some(99), NnsNeuronType::UnknownCode(99), "unknown(99)"),
122        ] {
123            assert_eq!(NnsNeuronType::from_code(code), neuron_type);
124            assert_eq!(neuron_type.code(), code);
125            assert_eq!(neuron_type.to_string(), label);
126            assert_eq!(
127                serde_json::to_value(neuron_type).expect("serialize neuron type"),
128                label
129            );
130        }
131    }
132
133    #[test]
134    fn classifications_read_canonical_cache_labels_only() {
135        assert_eq!(
136            serde_json::from_str::<NnsNeuronState>("\"unknown(-9)\"")
137                .expect("deserialize unknown state"),
138            NnsNeuronState::Unknown(-9)
139        );
140        assert_eq!(
141            serde_json::from_str::<NnsNeuronVisibility>("\"unknown\"")
142                .expect("deserialize absent visibility"),
143            NnsNeuronVisibility::Unknown
144        );
145        assert_eq!(
146            serde_json::from_str::<NnsNeuronType>("\"unknown(9)\"")
147                .expect("deserialize unknown neuron type"),
148            NnsNeuronType::UnknownCode(9)
149        );
150        assert!(serde_json::from_str::<NnsNeuronState>("\"unknown(+9)\"").is_err());
151        assert!(
152            serde_json::from_str::<crate::nns::governance::NnsGovernanceVote>("\"maybe\"").is_err()
153        );
154    }
155}