1pub mod v0;
2
3use crate::data_contract::document_type::DocumentTypeRef;
4use crate::data_contract::DataContract;
5use crate::document::Document;
6#[cfg(feature = "json-conversion")]
7use crate::serialization::JsonConvertible;
8#[cfg(feature = "value-conversion")]
9use crate::serialization::ValueConvertible;
10use crate::serialization::{PlatformDeserializableUntrusted, PlatformSerializable};
11use crate::voting::contender_structs::contender::v0::ContenderV0;
12use crate::voting::contender_structs::ContenderWithSerializedDocumentV0;
13use crate::ProtocolError;
14use bincode::{Decode, DecodeUntrusted, Encode};
15use derive_more::From;
16use platform_serialization_derive::{
17 PlatformDeserializeTrusted, PlatformDeserializeUntrusted, PlatformSerialize,
18};
19use platform_value::Identifier;
20use platform_version::version::PlatformVersion;
21
22#[derive(Debug, PartialEq, Clone, From)]
27pub enum Contender {
28 V0(ContenderV0),
30}
31
32#[cfg_attr(
38 all(feature = "json-conversion", feature = "serde-conversion"),
39 derive(JsonConvertible)
40)]
41#[derive(
42 Debug,
43 PartialEq,
44 Eq,
45 Clone,
46 From,
47 Encode,
48 Decode,
49 PlatformSerialize,
50 PlatformDeserializeTrusted,
51 PlatformDeserializeUntrusted,
52 DecodeUntrusted,
53)]
54#[cfg_attr(
55 feature = "serde-conversion",
56 derive(serde::Serialize, serde::Deserialize),
57 serde(tag = "$formatVersion")
58)]
59#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
60#[platform_serialize(unversioned)]
61pub enum ContenderWithSerializedDocument {
62 #[cfg_attr(feature = "serde-conversion", serde(rename = "0"))]
64 V0(ContenderWithSerializedDocumentV0),
65}
66
67impl Contender {
68 pub fn identity_id(&self) -> Identifier {
69 match self {
70 Contender::V0(v0) => v0.identity_id,
71 }
72 }
73
74 pub fn identity_id_ref(&self) -> &Identifier {
75 match self {
76 Contender::V0(v0) => &v0.identity_id,
77 }
78 }
79
80 pub fn document(&self) -> &Option<Document> {
81 match self {
82 Contender::V0(v0) => &v0.document,
83 }
84 }
85
86 pub fn take_document(&mut self) -> Option<Document> {
87 match self {
88 Contender::V0(v0) => v0.document.take(),
89 }
90 }
91
92 pub fn vote_tally(&self) -> Option<u32> {
93 match self {
94 Contender::V0(v0) => v0.vote_tally,
95 }
96 }
97}
98
99impl ContenderWithSerializedDocument {
100 pub fn identity_id(&self) -> Identifier {
101 match self {
102 ContenderWithSerializedDocument::V0(v0) => v0.identity_id,
103 }
104 }
105
106 pub fn identity_id_ref(&self) -> &Identifier {
107 match self {
108 ContenderWithSerializedDocument::V0(v0) => &v0.identity_id,
109 }
110 }
111
112 pub fn serialized_document(&self) -> &Option<Vec<u8>> {
113 match self {
114 ContenderWithSerializedDocument::V0(v0) => &v0.serialized_document,
115 }
116 }
117
118 pub fn take_serialized_document(&mut self) -> Option<Vec<u8>> {
119 match self {
120 ContenderWithSerializedDocument::V0(v0) => v0.serialized_document.take(),
121 }
122 }
123
124 pub fn vote_tally(&self) -> Option<u32> {
125 match self {
126 ContenderWithSerializedDocument::V0(v0) => v0.vote_tally,
127 }
128 }
129}
130
131impl ContenderWithSerializedDocument {
132 pub fn try_into_contender(
133 self,
134 document_type_ref: DocumentTypeRef,
135 platform_version: &PlatformVersion,
136 ) -> Result<Contender, ProtocolError> {
137 match self {
138 ContenderWithSerializedDocument::V0(v0) => Ok(v0
139 .try_into_contender(document_type_ref, platform_version)?
140 .into()),
141 }
142 }
143
144 pub fn try_to_contender(
145 &self,
146 document_type_ref: DocumentTypeRef,
147 platform_version: &PlatformVersion,
148 ) -> Result<Contender, ProtocolError> {
149 match self {
150 ContenderWithSerializedDocument::V0(v0) => Ok(v0
151 .try_to_contender(document_type_ref, platform_version)?
152 .into()),
153 }
154 }
155}
156
157impl Contender {
158 pub fn try_into_contender_with_serialized_document(
159 self,
160 document_type_ref: DocumentTypeRef,
161 data_contract: &DataContract,
162 platform_version: &PlatformVersion,
163 ) -> Result<ContenderWithSerializedDocument, ProtocolError> {
164 match self {
165 Contender::V0(v0) => Ok(v0
166 .try_into_contender_with_serialized_document(
167 document_type_ref,
168 data_contract,
169 platform_version,
170 )?
171 .into()),
172 }
173 }
174
175 pub fn try_to_contender_with_serialized_document(
176 &self,
177 document_type_ref: DocumentTypeRef,
178 data_contract: &DataContract,
179 platform_version: &PlatformVersion,
180 ) -> Result<ContenderWithSerializedDocument, ProtocolError> {
181 match self {
182 Contender::V0(v0) => Ok(v0
183 .try_to_contender_with_serialized_document(
184 document_type_ref,
185 data_contract,
186 platform_version,
187 )?
188 .into()),
189 }
190 }
191
192 pub fn serialize(
193 &self,
194 document_type: DocumentTypeRef,
195 data_contract: &DataContract,
196 platform_version: &PlatformVersion,
197 ) -> Result<Vec<u8>, ProtocolError> {
198 self.try_to_contender_with_serialized_document(
199 document_type,
200 data_contract,
201 platform_version,
202 )?
203 .serialize_to_bytes()
204 }
205
206 pub fn serialize_consume(
207 self,
208 document_type: DocumentTypeRef,
209 data_contract: &DataContract,
210 platform_version: &PlatformVersion,
211 ) -> Result<Vec<u8>, ProtocolError> {
212 self.try_into_contender_with_serialized_document(
213 document_type,
214 data_contract,
215 platform_version,
216 )?
217 .serialize_to_bytes()
218 }
219
220 pub fn from_bytes(
221 serialized_contender: &[u8],
222 document_type: DocumentTypeRef,
223 platform_version: &PlatformVersion,
224 ) -> Result<Self, ProtocolError>
225 where
226 Self: Sized,
227 {
228 let serialized_contender =
229 ContenderWithSerializedDocument::deserialize_from_bytes_untrusted(
230 serialized_contender,
231 )?;
232 serialized_contender.try_into_contender(document_type, platform_version)
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239 use crate::voting::contender_structs::contender::v0::{
240 ContenderV0, ContenderWithSerializedDocumentV0,
241 };
242 use platform_value::Identifier;
243
244 mod contender_construction {
245 use super::*;
246
247 #[test]
248 fn contender_v0_default() {
249 let contender = ContenderV0::default();
250 assert_eq!(contender.identity_id, Identifier::default());
251 assert!(contender.document.is_none());
252 assert!(contender.vote_tally.is_none());
253 }
254
255 #[test]
256 fn contender_v0_with_fields() {
257 let id = Identifier::new([1u8; 32]);
258 let contender = ContenderV0 {
259 identity_id: id,
260 document: None,
261 vote_tally: Some(42),
262 };
263 assert_eq!(contender.identity_id, id);
264 assert!(contender.document.is_none());
265 assert_eq!(contender.vote_tally, Some(42));
266 }
267
268 #[test]
269 fn contender_from_v0() {
270 let id = Identifier::new([2u8; 32]);
271 let v0 = ContenderV0 {
272 identity_id: id,
273 document: None,
274 vote_tally: Some(100),
275 };
276 let contender: Contender = v0.into();
277 assert_eq!(contender.identity_id(), id);
278 assert_eq!(contender.vote_tally(), Some(100));
279 }
280 }
281
282 mod contender_accessors {
283 use super::*;
284
285 #[test]
286 fn identity_id_returns_correct_value() {
287 let id = Identifier::new([3u8; 32]);
288 let contender = Contender::V0(ContenderV0 {
289 identity_id: id,
290 document: None,
291 vote_tally: None,
292 });
293 assert_eq!(contender.identity_id(), id);
294 }
295
296 #[test]
297 fn identity_id_ref_returns_reference() {
298 let id = Identifier::new([4u8; 32]);
299 let contender = Contender::V0(ContenderV0 {
300 identity_id: id,
301 document: None,
302 vote_tally: None,
303 });
304 assert_eq!(*contender.identity_id_ref(), id);
305 }
306
307 #[test]
308 fn document_returns_none_when_empty() {
309 let contender = Contender::V0(ContenderV0::default());
310 assert!(contender.document().is_none());
311 }
312
313 #[test]
314 fn vote_tally_returns_none_when_not_set() {
315 let contender = Contender::V0(ContenderV0::default());
316 assert!(contender.vote_tally().is_none());
317 }
318
319 #[test]
320 fn vote_tally_returns_value_when_set() {
321 let contender = Contender::V0(ContenderV0 {
322 identity_id: Identifier::default(),
323 document: None,
324 vote_tally: Some(999),
325 });
326 assert_eq!(contender.vote_tally(), Some(999));
327 }
328
329 #[test]
330 fn take_document_returns_none_and_leaves_none() {
331 let mut contender = Contender::V0(ContenderV0::default());
332 let doc = contender.take_document();
333 assert!(doc.is_none());
334 assert!(contender.document().is_none());
335 }
336 }
337
338 mod contender_with_serialized_document {
339 use super::*;
340
341 #[test]
342 fn default_values() {
343 let csd = ContenderWithSerializedDocumentV0::default();
344 assert_eq!(csd.identity_id, Identifier::default());
345 assert!(csd.serialized_document.is_none());
346 assert!(csd.vote_tally.is_none());
347 }
348
349 #[test]
350 fn construction_with_data() {
351 let id = Identifier::new([5u8; 32]);
352 let doc_bytes = vec![1, 2, 3, 4, 5];
353 let csd = ContenderWithSerializedDocumentV0 {
354 identity_id: id,
355 serialized_document: Some(doc_bytes.clone()),
356 vote_tally: Some(50),
357 };
358 let wrapped = ContenderWithSerializedDocument::V0(csd);
359 assert_eq!(wrapped.identity_id(), id);
360 assert_eq!(*wrapped.identity_id_ref(), id);
361 assert_eq!(wrapped.serialized_document(), &Some(doc_bytes));
362 assert_eq!(wrapped.vote_tally(), Some(50));
363 }
364
365 #[test]
366 fn take_serialized_document() {
367 let doc_bytes = vec![10, 20, 30];
368 let csd = ContenderWithSerializedDocumentV0 {
369 identity_id: Identifier::default(),
370 serialized_document: Some(doc_bytes.clone()),
371 vote_tally: None,
372 };
373 let mut wrapped = ContenderWithSerializedDocument::V0(csd);
374 let taken = wrapped.take_serialized_document();
375 assert_eq!(taken, Some(doc_bytes));
376 assert!(wrapped.serialized_document().is_none());
377 }
378
379 #[test]
380 fn serialization_round_trip() {
381 let id = Identifier::new([6u8; 32]);
382 let csd = ContenderWithSerializedDocumentV0 {
383 identity_id: id,
384 serialized_document: Some(vec![0xAA, 0xBB, 0xCC]),
385 vote_tally: Some(77),
386 };
387 let wrapped = ContenderWithSerializedDocument::V0(csd);
388
389 let bytes = wrapped
391 .serialize_to_bytes()
392 .expect("should serialize to bytes");
393 assert!(!bytes.is_empty());
394
395 let restored =
397 ContenderWithSerializedDocument::deserialize_from_bytes_untrusted(&bytes)
398 .expect("should deserialize from bytes");
399
400 assert_eq!(wrapped, restored);
401 }
402
403 #[test]
404 fn serialization_round_trip_with_no_document() {
405 let id = Identifier::new([7u8; 32]);
406 let csd = ContenderWithSerializedDocumentV0 {
407 identity_id: id,
408 serialized_document: None,
409 vote_tally: None,
410 };
411 let wrapped = ContenderWithSerializedDocument::V0(csd);
412
413 let bytes = wrapped
414 .serialize_to_bytes()
415 .expect("should serialize to bytes");
416 let restored =
417 ContenderWithSerializedDocument::deserialize_from_bytes_untrusted(&bytes)
418 .expect("should deserialize from bytes");
419
420 assert_eq!(wrapped, restored);
421 }
422 }
423
424 mod equality {
425 use super::*;
426
427 #[test]
428 fn equal_contenders() {
429 let id = Identifier::new([8u8; 32]);
430 let a = Contender::V0(ContenderV0 {
431 identity_id: id,
432 document: None,
433 vote_tally: Some(10),
434 });
435 let b = Contender::V0(ContenderV0 {
436 identity_id: id,
437 document: None,
438 vote_tally: Some(10),
439 });
440 assert_eq!(a, b);
441 }
442
443 #[test]
444 fn different_vote_tallies_not_equal() {
445 let id = Identifier::new([9u8; 32]);
446 let a = Contender::V0(ContenderV0 {
447 identity_id: id,
448 document: None,
449 vote_tally: Some(10),
450 });
451 let b = Contender::V0(ContenderV0 {
452 identity_id: id,
453 document: None,
454 vote_tally: Some(20),
455 });
456 assert_ne!(a, b);
457 }
458
459 #[test]
460 fn different_identity_ids_not_equal() {
461 let a = Contender::V0(ContenderV0 {
462 identity_id: Identifier::new([1u8; 32]),
463 document: None,
464 vote_tally: None,
465 });
466 let b = Contender::V0(ContenderV0 {
467 identity_id: Identifier::new([2u8; 32]),
468 document: None,
469 vote_tally: None,
470 });
471 assert_ne!(a, b);
472 }
473 }
474}
475
476#[cfg(all(
477 test,
478 feature = "json-conversion",
479 feature = "value-conversion",
480 feature = "serde-conversion"
481))]
482mod json_convertible_tests_contender_with_serialized_document {
483 use super::*;
484 use platform_value::{platform_value, Identifier, Value};
485 use serde_json::json;
486
487 fn fixture() -> ContenderWithSerializedDocument {
491 ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
492 identity_id: Identifier::new([0xa1; 32]),
493 serialized_document: Some(vec![0xde, 0xad, 0xbe, 0xef]),
494 vote_tally: Some(42),
495 })
496 }
497
498 #[test]
499 fn json_round_trip_with_full_wire_shape() {
500 use crate::serialization::JsonConvertible;
501 let original = fixture();
502 let json = original.to_json().expect("to_json");
503 assert_eq!(
509 json,
510 json!({
511 "$formatVersion": "0",
512 "identityId": "Bswb3UyeD1pUTaGiE6WvqwFpJZsQSEY1xhJePCDTHdvp",
513 "serializedDocument": [222, 173, 190, 239],
514 "voteTally": 42,
515 })
516 );
517 let recovered = ContenderWithSerializedDocument::from_json(json).expect("from_json");
518 assert_eq!(original, recovered);
519 }
520
521 #[test]
522 fn value_round_trip_with_full_wire_shape() {
523 use crate::serialization::ValueConvertible;
524 let original = fixture();
525 let value = original.to_object().expect("to_object");
526 let id = Identifier::new([0xa1; 32]);
531 let bytes_array = Value::Array(vec![
532 Value::U8(0xde),
533 Value::U8(0xad),
534 Value::U8(0xbe),
535 Value::U8(0xef),
536 ]);
537 assert_eq!(
538 value,
539 platform_value!({
540 "$formatVersion": "0",
541 "identityId": id,
542 "serializedDocument": bytes_array,
543 "voteTally": 42u32,
544 })
545 );
546 let recovered = ContenderWithSerializedDocument::from_object(value).expect("from_object");
547 assert_eq!(original, recovered);
548 }
549}