dpp/voting/vote_choices/resource_vote_choice/
mod.rs1#[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#[derive(Debug, Clone, Copy, Encode, Decode, Ord, Eq, PartialOrd, PartialEq, Default)]
25#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
33pub enum ResourceVoteChoice {
34 TowardsIdentity(Identifier),
35 #[default]
36 Abstain,
37 Lock,
38}
39
40#[cfg(feature = "serde-conversion")]
41impl Serialize for ResourceVoteChoice {
42 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
43 use serde::ser::SerializeMap;
44 match self {
45 ResourceVoteChoice::TowardsIdentity(id) => {
46 let mut m = serializer.serialize_map(Some(2))?;
47 m.serialize_entry("$type", "towardsIdentity")?;
48 m.serialize_entry("identity", id)?;
49 m.end()
50 }
51 ResourceVoteChoice::Abstain => {
52 let mut m = serializer.serialize_map(Some(1))?;
53 m.serialize_entry("$type", "abstain")?;
54 m.end()
55 }
56 ResourceVoteChoice::Lock => {
57 let mut m = serializer.serialize_map(Some(1))?;
58 m.serialize_entry("$type", "lock")?;
59 m.end()
60 }
61 }
62 }
63}
64
65#[cfg(feature = "serde-conversion")]
66impl<'de> Deserialize<'de> for ResourceVoteChoice {
67 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
68 use serde::de::{self, MapAccess, Visitor};
69
70 struct V;
71
72 impl<'de> Visitor<'de> for V {
73 type Value = ResourceVoteChoice;
74
75 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76 f.write_str("ResourceVoteChoice as a map with `type` discriminator")
77 }
78
79 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
80 let mut variant: Option<String> = None;
81 let mut identity: Option<Identifier> = None;
82
83 while let Some(key) = map.next_key::<String>()? {
84 match key.as_str() {
85 "$type" => {
86 if variant.is_some() {
87 return Err(de::Error::duplicate_field("$type"));
88 }
89 variant = Some(map.next_value()?);
90 }
91 "identity" => {
92 if identity.is_some() {
93 return Err(de::Error::duplicate_field("identity"));
94 }
95 identity = Some(map.next_value()?);
96 }
97 _ => {
98 let _: serde::de::IgnoredAny = map.next_value()?;
99 }
100 }
101 }
102
103 let variant = variant.ok_or_else(|| de::Error::missing_field("$type"))?;
104 match variant.as_str() {
105 "towardsIdentity" => {
106 let id = identity.ok_or_else(|| de::Error::missing_field("identity"))?;
107 Ok(ResourceVoteChoice::TowardsIdentity(id))
108 }
109 "abstain" => Ok(ResourceVoteChoice::Abstain),
110 "lock" => Ok(ResourceVoteChoice::Lock),
111 other => Err(de::Error::unknown_variant(
112 other,
113 &["towardsIdentity", "abstain", "lock"],
114 )),
115 }
116 }
117 }
118
119 deserializer.deserialize_map(V)
120 }
121}
122
123impl fmt::Display for ResourceVoteChoice {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 match self {
126 ResourceVoteChoice::TowardsIdentity(identifier) => {
127 write!(f, "TowardsIdentity({})", identifier)
128 }
129 ResourceVoteChoice::Abstain => write!(f, "Abstain"),
130 ResourceVoteChoice::Lock => write!(f, "Lock"),
131 }
132 }
133}
134
135#[cfg(feature = "json-conversion")]
137impl JsonConvertible for ResourceVoteChoice {}
138
139#[cfg(all(test, feature = "json-conversion"))]
140mod tests {
141 use super::*;
142 use crate::serialization::JsonConvertible;
143
144 #[test]
145 fn resource_vote_choice_towards_identity_json_round_trip() {
146 let id = Identifier::from([0x42u8; 32]);
147 let choice = ResourceVoteChoice::TowardsIdentity(id);
148
149 let json = choice.to_json().expect("to_json should succeed");
150 let json_str = serde_json::to_string(&json).unwrap();
151 let expected_base58 = id.to_string(platform_value::string_encoding::Encoding::Base58);
152 assert!(
153 json_str.contains(&expected_base58),
154 "JSON should contain base58 identifier {}, got: {}",
155 expected_base58,
156 json_str
157 );
158
159 let restored = ResourceVoteChoice::from_json(json).expect("from_json should succeed");
160 assert_eq!(choice, restored);
161 }
162
163 #[test]
164 fn resource_vote_choice_abstain_json_round_trip() {
165 let choice = ResourceVoteChoice::Abstain;
166 let json = choice.to_json().expect("to_json should succeed");
167 let restored = ResourceVoteChoice::from_json(json).expect("from_json should succeed");
168 assert_eq!(choice, restored);
169 }
170
171 #[test]
172 fn resource_vote_choice_lock_json_round_trip() {
173 let choice = ResourceVoteChoice::Lock;
174 let json = choice.to_json().expect("to_json should succeed");
175 let restored = ResourceVoteChoice::from_json(json).expect("from_json should succeed");
176 assert_eq!(choice, restored);
177 }
178}
179
180impl TryFrom<(i32, Option<Vec<u8>>)> for ResourceVoteChoice {
181 type Error = ProtocolError;
182
183 fn try_from(value: (i32, Option<Vec<u8>>)) -> Result<Self, Self::Error> {
184 match value.0 {
185 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()?)),
186 1 => Ok(Abstain),
187 2 => Ok(Lock),
188 n => Err(ProtocolError::DecodingError(format!("identifier must be 0, 1, or 2, got {}", n)))
189 }
190 }
191}
192
193#[cfg(all(
194 test,
195 feature = "json-conversion",
196 feature = "value-conversion",
197 feature = "serde-conversion"
198))]
199mod json_convertible_tests_resourcevotechoice {
200 use super::*;
201
202 #[test]
203 fn json_round_trip_resourcevotechoice() {
204 use crate::serialization::JsonConvertible;
205 let original = ResourceVoteChoice::default();
206 let json = original.to_json().expect("to_json");
207 let recovered = ResourceVoteChoice::from_json(json).expect("from_json");
208 assert_eq!(original, recovered);
209 }
210
211 #[test]
212 fn value_round_trip_resourcevotechoice() {
213 use crate::serialization::ValueConvertible;
214 let original = ResourceVoteChoice::default();
215 let value = original.to_object().expect("to_object");
216 let recovered = ResourceVoteChoice::from_object(value).expect("from_object");
217 assert_eq!(original, recovered);
218 }
219}