dpp/voting/vote_choices/resource_vote_choice/
mod.rs

1#[cfg(feature = "json-conversion")]
2use crate::serialization::JsonConvertible;
3#[cfg(feature = "value-conversion")]
4use crate::serialization::ValueConvertible;
5use crate::voting::vote_choices::resource_vote_choice::ResourceVoteChoice::{
6    Abstain, Lock, TowardsIdentity,
7};
8use crate::ProtocolError;
9use bincode::{Decode, Encode};
10use platform_value::Identifier;
11#[cfg(feature = "serde-conversion")]
12use serde::{Deserialize, Serialize};
13use std::fmt;
14
15/// A resource votes is a votes determining what we should do with a contested resource.
16/// For example Alice and Bob both want the username "Malaka"
17/// Some would vote for Alice to get it by putting in her Identifier.
18/// Some would vote for Bob to get it by putting in Bob's Identifier.
19/// Let's say someone voted, but is now not quite sure of their votes, they can abstain.
20/// Lock is there to signal that the shared resource should be given to no one.
21/// In this case Malaka might have a bad connotation in Greek, hence some might votes to Lock
22/// the name.
23///
24#[derive(Debug, Clone, Copy, Encode, Decode, Ord, Eq, PartialOrd, PartialEq, Default)]
25#[cfg_attr(
26    feature = "serde-conversion",
27    derive(Serialize, Deserialize),
28    serde(tag = "type", content = "data", rename_all = "camelCase")
29)]
30#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
31pub enum ResourceVoteChoice {
32    TowardsIdentity(Identifier),
33    #[default]
34    Abstain,
35    Lock,
36}
37
38impl fmt::Display for ResourceVoteChoice {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            ResourceVoteChoice::TowardsIdentity(identifier) => {
42                write!(f, "TowardsIdentity({})", identifier)
43            }
44            ResourceVoteChoice::Abstain => write!(f, "Abstain"),
45            ResourceVoteChoice::Lock => write!(f, "Lock"),
46        }
47    }
48}
49
50// Manual impl because ResourceVoteChoice is a flat enum (not versioned V0/V1).
51#[cfg(feature = "json-conversion")]
52impl JsonConvertible for ResourceVoteChoice {}
53
54#[cfg(all(test, feature = "json-conversion"))]
55mod tests {
56    use super::*;
57    use crate::serialization::JsonConvertible;
58
59    #[test]
60    fn resource_vote_choice_towards_identity_json_round_trip() {
61        let id = Identifier::from([0x42u8; 32]);
62        let choice = ResourceVoteChoice::TowardsIdentity(id);
63
64        let json = choice.to_json().expect("to_json should succeed");
65        let json_str = serde_json::to_string(&json).unwrap();
66        let expected_base58 = id.to_string(platform_value::string_encoding::Encoding::Base58);
67        assert!(
68            json_str.contains(&expected_base58),
69            "JSON should contain base58 identifier {}, got: {}",
70            expected_base58,
71            json_str
72        );
73
74        let restored = ResourceVoteChoice::from_json(json).expect("from_json should succeed");
75        assert_eq!(choice, restored);
76    }
77
78    #[test]
79    fn resource_vote_choice_abstain_json_round_trip() {
80        let choice = ResourceVoteChoice::Abstain;
81        let json = choice.to_json().expect("to_json should succeed");
82        let restored = ResourceVoteChoice::from_json(json).expect("from_json should succeed");
83        assert_eq!(choice, restored);
84    }
85
86    #[test]
87    fn resource_vote_choice_lock_json_round_trip() {
88        let choice = ResourceVoteChoice::Lock;
89        let json = choice.to_json().expect("to_json should succeed");
90        let restored = ResourceVoteChoice::from_json(json).expect("from_json should succeed");
91        assert_eq!(choice, restored);
92    }
93}
94
95impl TryFrom<(i32, Option<Vec<u8>>)> for ResourceVoteChoice {
96    type Error = ProtocolError;
97
98    fn try_from(value: (i32, Option<Vec<u8>>)) -> Result<Self, Self::Error> {
99        match value.0 {
100            0 => Ok(TowardsIdentity(value.1.ok_or(ProtocolError::DecodingError("identifier needed when trying to cast from an i32 to a resource vote choice".to_string()))?.try_into()?)),
101            1 => Ok(Abstain),
102            2 => Ok(Lock),
103            n => Err(ProtocolError::DecodingError(format!("identifier must be 0, 1, or 2, got {}", n)))
104        }
105    }
106}