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