grid_sdk/protocol/track_and_trace/
state.rs

1// Copyright 2019 Cargill Incorporated
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Protocol structs for Track and Trace state
16
17use super::errors::BuilderError;
18use crate::protocol::schema::state::{PropertyDefinition, PropertyValue};
19use crate::protos::track_and_trace_state;
20use crate::protos::{
21    FromBytes, FromNative, FromProto, IntoBytes, IntoNative, IntoProto, ProtoConversionError,
22};
23use protobuf::Message;
24use protobuf::RepeatedField;
25
26/// Native representation of a `Reporter`
27///
28/// Contains a cryptographic public key, associated with an agent, of the agent authorized to
29/// report updates to a `Property`. A flag indicator, `authorized`, determines whether the reporter
30/// is still authorized to report updates.
31#[derive(Debug, Clone, PartialEq)]
32pub struct Reporter {
33    public_key: String,
34    authorized: bool,
35    index: u32,
36}
37
38impl Reporter {
39    pub fn public_key(&self) -> &str {
40        &self.public_key
41    }
42    pub fn authorized(&self) -> &bool {
43        &self.authorized
44    }
45    pub fn index(&self) -> &u32 {
46        &self.index
47    }
48    pub fn into_builder(self) -> ReporterBuilder {
49        ReporterBuilder::new()
50            .with_public_key(self.public_key)
51            .with_authorized(self.authorized)
52            .with_index(self.index)
53    }
54}
55
56/// Builder used to create a `Reporter`
57#[derive(Default, Clone)]
58pub struct ReporterBuilder {
59    public_key: Option<String>,
60    authorized: Option<bool>,
61    index: Option<u32>,
62}
63
64impl ReporterBuilder {
65    pub fn new() -> Self {
66        ReporterBuilder::default()
67    }
68    pub fn with_public_key(mut self, value: String) -> Self {
69        self.public_key = Some(value);
70        self
71    }
72    pub fn with_authorized(mut self, value: bool) -> Self {
73        self.authorized = Some(value);
74        self
75    }
76    pub fn with_index(mut self, value: u32) -> Self {
77        self.index = Some(value);
78        self
79    }
80    pub fn build(self) -> Result<Reporter, BuilderError> {
81        let public_key = self
82            .public_key
83            .ok_or_else(|| BuilderError::MissingField("public_key".into()))?;
84        let authorized = self
85            .authorized
86            .ok_or_else(|| BuilderError::MissingField("authorized".into()))?;
87        let index = self
88            .index
89            .ok_or_else(|| BuilderError::MissingField("index".into()))?;
90        Ok(Reporter {
91            public_key,
92            authorized,
93            index,
94        })
95    }
96}
97
98impl FromProto<track_and_trace_state::Property_Reporter> for Reporter {
99    fn from_proto(
100        proto: track_and_trace_state::Property_Reporter,
101    ) -> Result<Self, ProtoConversionError> {
102        Ok(Reporter {
103            public_key: proto.get_public_key().to_string(),
104            authorized: proto.get_authorized(),
105            index: proto.get_index(),
106        })
107    }
108}
109
110impl FromNative<Reporter> for track_and_trace_state::Property_Reporter {
111    fn from_native(native: Reporter) -> Result<Self, ProtoConversionError> {
112        let mut proto = track_and_trace_state::Property_Reporter::new();
113        proto.set_public_key(native.public_key().to_string());
114        proto.set_authorized(*native.authorized());
115        proto.set_index(*native.index());
116
117        Ok(proto)
118    }
119}
120
121impl FromBytes<Reporter> for Reporter {
122    fn from_bytes(bytes: &[u8]) -> Result<Reporter, ProtoConversionError> {
123        let proto: track_and_trace_state::Property_Reporter = Message::parse_from_bytes(bytes)
124            .map_err(|_| {
125                ProtoConversionError::SerializationError("Unable to get Reporter from bytes".into())
126            })?;
127        proto.into_native()
128    }
129}
130impl IntoBytes for Reporter {
131    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
132        let proto = self.into_proto()?;
133        let bytes = proto.write_to_bytes().map_err(|_| {
134            ProtoConversionError::SerializationError("Unable to get Reporter from bytes".into())
135        })?;
136        Ok(bytes)
137    }
138}
139impl IntoProto<track_and_trace_state::Property_Reporter> for Reporter {}
140impl IntoNative<Reporter> for track_and_trace_state::Property_Reporter {}
141
142/// Native representation of a `Property`
143///
144/// Contains historical data pertaining to a particular data field of a tracked object.
145#[derive(Debug, Clone, PartialEq)]
146pub struct Property {
147    name: String,
148    record_id: String,
149    property_definition: PropertyDefinition,
150    reporters: Vec<Reporter>,
151    current_page: u32,
152    wrapped: bool,
153}
154
155impl Property {
156    pub fn name(&self) -> &str {
157        &self.name
158    }
159    pub fn record_id(&self) -> &str {
160        &self.record_id
161    }
162    pub fn property_definition(&self) -> &PropertyDefinition {
163        &self.property_definition
164    }
165    pub fn reporters(&self) -> &[Reporter] {
166        &self.reporters
167    }
168    pub fn current_page(&self) -> &u32 {
169        &self.current_page
170    }
171    pub fn wrapped(&self) -> &bool {
172        &self.wrapped
173    }
174
175    pub fn into_builder(self) -> PropertyBuilder {
176        PropertyBuilder::new()
177            .with_name(self.name)
178            .with_record_id(self.record_id)
179            .with_property_definition(self.property_definition)
180            .with_reporters(self.reporters)
181            .with_current_page(self.current_page)
182            .with_wrapped(self.wrapped)
183    }
184}
185
186/// Builder used to create a `Property`
187#[derive(Default, Debug)]
188pub struct PropertyBuilder {
189    name: Option<String>,
190    record_id: Option<String>,
191    property_definition: Option<PropertyDefinition>,
192    reporters: Option<Vec<Reporter>>,
193    current_page: Option<u32>,
194    wrapped: Option<bool>,
195}
196
197impl PropertyBuilder {
198    pub fn new() -> Self {
199        PropertyBuilder::default()
200    }
201    pub fn with_name(mut self, value: String) -> Self {
202        self.name = Some(value);
203        self
204    }
205    pub fn with_record_id(mut self, value: String) -> Self {
206        self.record_id = Some(value);
207        self
208    }
209    pub fn with_property_definition(mut self, value: PropertyDefinition) -> Self {
210        self.property_definition = Some(value);
211        self
212    }
213    pub fn with_reporters(mut self, value: Vec<Reporter>) -> Self {
214        self.reporters = Some(value);
215        self
216    }
217    pub fn with_current_page(mut self, value: u32) -> Self {
218        self.current_page = Some(value);
219        self
220    }
221    pub fn with_wrapped(mut self, value: bool) -> Self {
222        self.wrapped = Some(value);
223        self
224    }
225    pub fn build(self) -> Result<Property, BuilderError> {
226        let name = self
227            .name
228            .ok_or_else(|| BuilderError::MissingField("name".into()))?;
229        let record_id = self
230            .record_id
231            .ok_or_else(|| BuilderError::MissingField("record_id".into()))?;
232        let property_definition = self
233            .property_definition
234            .ok_or_else(|| BuilderError::MissingField("property_definition".into()))?;
235        let reporters = self
236            .reporters
237            .ok_or_else(|| BuilderError::MissingField("reporters".into()))?;
238        let current_page = self
239            .current_page
240            .ok_or_else(|| BuilderError::MissingField("current_page".into()))?;
241        let wrapped = self
242            .wrapped
243            .ok_or_else(|| BuilderError::MissingField("wrapped".into()))?;
244        Ok(Property {
245            name,
246            record_id,
247            property_definition,
248            reporters,
249            current_page,
250            wrapped,
251        })
252    }
253}
254
255impl FromProto<track_and_trace_state::Property> for Property {
256    fn from_proto(proto: track_and_trace_state::Property) -> Result<Self, ProtoConversionError> {
257        Ok(Property {
258            name: proto.get_name().to_string(),
259            record_id: proto.get_record_id().to_string(),
260            property_definition: PropertyDefinition::from_proto(
261                proto.get_property_definition().clone(),
262            )?,
263            reporters: proto
264                .get_reporters()
265                .iter()
266                .cloned()
267                .map(Reporter::from_proto)
268                .collect::<Result<Vec<Reporter>, ProtoConversionError>>()?,
269            current_page: proto.get_current_page(),
270            wrapped: proto.get_wrapped(),
271        })
272    }
273}
274
275impl FromNative<Property> for track_and_trace_state::Property {
276    fn from_native(native: Property) -> Result<Self, ProtoConversionError> {
277        let mut proto = track_and_trace_state::Property::new();
278        proto.set_name(native.name().to_string());
279        proto.set_record_id(native.record_id().to_string());
280        proto.set_property_definition(native.property_definition().clone().into_proto()?);
281        proto.set_reporters(RepeatedField::from_vec(
282            native.reporters()
283            .iter()
284            .cloned()
285            .map(Reporter::into_proto)
286            .collect::<Result<Vec<track_and_trace_state::Property_Reporter>, ProtoConversionError>>()?));
287        proto.set_current_page(*native.current_page());
288        proto.set_wrapped(*native.wrapped());
289
290        Ok(proto)
291    }
292}
293
294impl FromBytes<Property> for Property {
295    fn from_bytes(bytes: &[u8]) -> Result<Property, ProtoConversionError> {
296        let proto: track_and_trace_state::Property =
297            Message::parse_from_bytes(bytes).map_err(|_| {
298                ProtoConversionError::SerializationError("Unable to get Property from bytes".into())
299            })?;
300        proto.into_native()
301    }
302}
303impl IntoBytes for Property {
304    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
305        let proto = self.into_proto()?;
306        let bytes = proto.write_to_bytes().map_err(|_| {
307            ProtoConversionError::SerializationError("Unable to get Property from bytes".into())
308        })?;
309        Ok(bytes)
310    }
311}
312impl IntoProto<track_and_trace_state::Property> for Property {}
313impl IntoNative<Property> for track_and_trace_state::Property {}
314
315/// Native representation of a list of `Property` objects
316#[derive(Debug, Clone, PartialEq)]
317pub struct PropertyList {
318    properties: Vec<Property>,
319}
320
321impl PropertyList {
322    pub fn properties(&self) -> &[Property] {
323        &self.properties
324    }
325
326    pub fn into_builder(self) -> PropertyListBuilder {
327        PropertyListBuilder::new().with_properties(self.properties)
328    }
329}
330
331/// Builder used to create a list of `Property` objects
332#[derive(Default, Clone)]
333pub struct PropertyListBuilder {
334    properties: Option<Vec<Property>>,
335}
336
337impl PropertyListBuilder {
338    pub fn new() -> Self {
339        PropertyListBuilder::default()
340    }
341    pub fn with_properties(mut self, value: Vec<Property>) -> Self {
342        self.properties = Some(value);
343        self
344    }
345    pub fn build(self) -> Result<PropertyList, BuilderError> {
346        let properties = self
347            .properties
348            .ok_or_else(|| BuilderError::MissingField("properties".into()))?;
349        Ok(PropertyList { properties })
350    }
351}
352
353impl FromProto<track_and_trace_state::PropertyList> for PropertyList {
354    fn from_proto(
355        proto: track_and_trace_state::PropertyList,
356    ) -> Result<Self, ProtoConversionError> {
357        Ok(PropertyList {
358            properties: proto
359                .get_entries()
360                .iter()
361                .cloned()
362                .map(Property::from_proto)
363                .collect::<Result<Vec<Property>, ProtoConversionError>>()?,
364        })
365    }
366}
367
368impl FromNative<PropertyList> for track_and_trace_state::PropertyList {
369    fn from_native(native: PropertyList) -> Result<Self, ProtoConversionError> {
370        let mut proto = track_and_trace_state::PropertyList::new();
371        proto.set_entries(RepeatedField::from_vec(
372            native
373                .properties()
374                .iter()
375                .cloned()
376                .map(Property::into_proto)
377                .collect::<Result<Vec<track_and_trace_state::Property>, ProtoConversionError>>()?,
378        ));
379
380        Ok(proto)
381    }
382}
383
384impl FromBytes<PropertyList> for PropertyList {
385    fn from_bytes(bytes: &[u8]) -> Result<PropertyList, ProtoConversionError> {
386        let proto: track_and_trace_state::PropertyList =
387            Message::parse_from_bytes(bytes).map_err(|_| {
388                ProtoConversionError::SerializationError(
389                    "Unable to get PropertyList from Bytes".into(),
390                )
391            })?;
392        proto.into_native()
393    }
394}
395impl IntoBytes for PropertyList {
396    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
397        let proto = self.into_proto()?;
398        let bytes = proto.write_to_bytes().map_err(|_| {
399            ProtoConversionError::SerializationError("Unable to get PropertyList from Bytes".into())
400        })?;
401        Ok(bytes)
402    }
403}
404impl IntoProto<track_and_trace_state::PropertyList> for PropertyList {}
405impl IntoNative<PropertyList> for track_and_trace_state::PropertyList {}
406
407/// Native representation of a reported property value
408///
409/// Contains an updated `Property` value as reported by an authorized agent.
410#[derive(Debug, Clone, PartialEq)]
411pub struct ReportedValue {
412    reporter_index: u32,
413    timestamp: u64,
414    value: PropertyValue,
415}
416
417impl ReportedValue {
418    pub fn reporter_index(&self) -> &u32 {
419        &self.reporter_index
420    }
421    pub fn timestamp(&self) -> &u64 {
422        &self.timestamp
423    }
424    pub fn value(&self) -> &PropertyValue {
425        &self.value
426    }
427    pub fn into_builder(self) -> ReportedValueBuilder {
428        ReportedValueBuilder::new()
429            .with_reporter_index(self.reporter_index)
430            .with_timestamp(self.timestamp)
431            .with_value(self.value)
432    }
433}
434
435/// Builder used to create a `ReportedValue`
436#[derive(Default, Debug)]
437pub struct ReportedValueBuilder {
438    reporter_index: Option<u32>,
439    timestamp: Option<u64>,
440    value: Option<PropertyValue>,
441}
442
443impl ReportedValueBuilder {
444    pub fn new() -> Self {
445        ReportedValueBuilder::default()
446    }
447    pub fn with_reporter_index(mut self, value: u32) -> Self {
448        self.reporter_index = Some(value);
449        self
450    }
451    pub fn with_timestamp(mut self, value: u64) -> Self {
452        self.timestamp = Some(value);
453        self
454    }
455    pub fn with_value(mut self, value: PropertyValue) -> Self {
456        self.value = Some(value);
457        self
458    }
459    pub fn build(self) -> Result<ReportedValue, BuilderError> {
460        let reporter_index = self
461            .reporter_index
462            .ok_or_else(|| BuilderError::MissingField("reporter_index".into()))?;
463        let timestamp = self
464            .timestamp
465            .ok_or_else(|| BuilderError::MissingField("timestamp".into()))?;
466        let value = self
467            .value
468            .ok_or_else(|| BuilderError::MissingField("value".into()))?;
469        Ok(ReportedValue {
470            reporter_index,
471            timestamp,
472            value,
473        })
474    }
475}
476
477impl FromProto<track_and_trace_state::PropertyPage_ReportedValue> for ReportedValue {
478    fn from_proto(
479        proto: track_and_trace_state::PropertyPage_ReportedValue,
480    ) -> Result<Self, ProtoConversionError> {
481        Ok(ReportedValue {
482            reporter_index: proto.get_reporter_index(),
483            timestamp: proto.get_timestamp(),
484            value: PropertyValue::from_proto(proto.get_value().clone())?,
485        })
486    }
487}
488
489impl FromNative<ReportedValue> for track_and_trace_state::PropertyPage_ReportedValue {
490    fn from_native(native: ReportedValue) -> Result<Self, ProtoConversionError> {
491        let mut proto = track_and_trace_state::PropertyPage_ReportedValue::new();
492        proto.set_reporter_index(*native.reporter_index());
493        proto.set_timestamp(*native.timestamp());
494        proto.set_value(native.value().clone().into_proto()?);
495
496        Ok(proto)
497    }
498}
499
500impl FromBytes<ReportedValue> for ReportedValue {
501    fn from_bytes(bytes: &[u8]) -> Result<ReportedValue, ProtoConversionError> {
502        let proto: track_and_trace_state::PropertyPage_ReportedValue =
503            Message::parse_from_bytes(bytes).map_err(|_| {
504                ProtoConversionError::SerializationError(
505                    "Unable to get ReportedValue from bytes".into(),
506                )
507            })?;
508        proto.into_native()
509    }
510}
511impl IntoBytes for ReportedValue {
512    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
513        let proto = self.into_proto()?;
514        let bytes = proto.write_to_bytes().map_err(|_| {
515            ProtoConversionError::SerializationError(
516                "Unable to get ReportedValue from bytes".into(),
517            )
518        })?;
519        Ok(bytes)
520    }
521}
522impl IntoProto<track_and_trace_state::PropertyPage_ReportedValue> for ReportedValue {}
523impl IntoNative<ReportedValue> for track_and_trace_state::PropertyPage_ReportedValue {}
524
525/// Native representation of a `PropertyPage`
526///
527/// Treated by the Track and Trace transaction processer as a ring buffer to hold all historical
528/// reported values for the corresponding `Property`. Once the reserved namespaces for property
529/// pages are filled, the next update will overwrite the oldest page within the namespace.
530#[derive(Debug, Clone, PartialEq)]
531pub struct PropertyPage {
532    name: String,
533    record_id: String,
534    reported_values: Vec<ReportedValue>,
535}
536
537impl PropertyPage {
538    pub fn name(&self) -> &str {
539        &self.name
540    }
541    pub fn record_id(&self) -> &str {
542        &self.record_id
543    }
544    pub fn reported_values(&self) -> &[ReportedValue] {
545        &self.reported_values
546    }
547
548    pub fn into_builder(self) -> PropertyPageBuilder {
549        PropertyPageBuilder::new()
550            .with_name(self.name)
551            .with_record_id(self.record_id)
552            .with_reported_values(self.reported_values)
553    }
554}
555
556/// Builder used to create a `PropertyPage`
557#[derive(Default, Debug)]
558pub struct PropertyPageBuilder {
559    name: Option<String>,
560    record_id: Option<String>,
561    reported_values: Option<Vec<ReportedValue>>,
562}
563
564impl PropertyPageBuilder {
565    pub fn new() -> Self {
566        PropertyPageBuilder::default()
567    }
568    pub fn with_name(mut self, value: String) -> Self {
569        self.name = Some(value);
570        self
571    }
572    pub fn with_record_id(mut self, value: String) -> Self {
573        self.record_id = Some(value);
574        self
575    }
576    pub fn with_reported_values(mut self, value: Vec<ReportedValue>) -> Self {
577        self.reported_values = Some(value);
578        self
579    }
580    pub fn build(self) -> Result<PropertyPage, BuilderError> {
581        let name = self
582            .name
583            .ok_or_else(|| BuilderError::MissingField("name".into()))?;
584        let record_id = self
585            .record_id
586            .ok_or_else(|| BuilderError::MissingField("record_id".into()))?;
587        let reported_values = self
588            .reported_values
589            .ok_or_else(|| BuilderError::MissingField("reported_values".into()))?;
590        Ok(PropertyPage {
591            name,
592            record_id,
593            reported_values,
594        })
595    }
596}
597
598impl FromProto<track_and_trace_state::PropertyPage> for PropertyPage {
599    fn from_proto(
600        proto: track_and_trace_state::PropertyPage,
601    ) -> Result<Self, ProtoConversionError> {
602        Ok(PropertyPage {
603            name: proto.get_name().to_string(),
604            record_id: proto.get_record_id().to_string(),
605            reported_values: proto
606                .get_reported_values()
607                .iter()
608                .cloned()
609                .map(ReportedValue::from_proto)
610                .collect::<Result<Vec<ReportedValue>, ProtoConversionError>>()?,
611        })
612    }
613}
614
615impl FromNative<PropertyPage> for track_and_trace_state::PropertyPage {
616    fn from_native(native: PropertyPage) -> Result<Self, ProtoConversionError> {
617        let mut proto = track_and_trace_state::PropertyPage::new();
618        proto.set_name(native.name().to_string());
619        proto.set_record_id(native.record_id().to_string());
620        proto.set_reported_values(RepeatedField::from_vec(
621            native
622                .reported_values()
623                .iter()
624                .cloned()
625                .map(ReportedValue::into_proto)
626                .collect::<Result<
627                    Vec<track_and_trace_state::PropertyPage_ReportedValue>,
628                    ProtoConversionError,
629                >>()?,
630        ));
631
632        Ok(proto)
633    }
634}
635
636impl FromBytes<PropertyPage> for PropertyPage {
637    fn from_bytes(bytes: &[u8]) -> Result<PropertyPage, ProtoConversionError> {
638        let proto: track_and_trace_state::PropertyPage =
639            Message::parse_from_bytes(bytes).map_err(|_| {
640                ProtoConversionError::SerializationError(
641                    "Undable to get PropertyPage from bytes".into(),
642                )
643            })?;
644        proto.into_native()
645    }
646}
647impl IntoBytes for PropertyPage {
648    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
649        let proto = self.into_proto()?;
650        let bytes = proto.write_to_bytes().map_err(|_| {
651            ProtoConversionError::SerializationError(
652                "Undable to get PropertyPage from bytes".into(),
653            )
654        })?;
655        Ok(bytes)
656    }
657}
658impl IntoProto<track_and_trace_state::PropertyPage> for PropertyPage {}
659impl IntoNative<PropertyPage> for track_and_trace_state::PropertyPage {}
660
661/// Native representation of a list of `PropertyPage`s
662#[derive(Debug, Clone, PartialEq)]
663pub struct PropertyPageList {
664    property_pages: Vec<PropertyPage>,
665}
666
667impl PropertyPageList {
668    pub fn property_pages(&self) -> &[PropertyPage] {
669        &self.property_pages
670    }
671
672    pub fn into_builder(self) -> PropertyPageListBuilder {
673        PropertyPageListBuilder::new().with_property_pages(self.property_pages)
674    }
675}
676
677/// Builder used to create a list of `PropertyPage`s
678#[derive(Default, Debug)]
679pub struct PropertyPageListBuilder {
680    property_pages: Option<Vec<PropertyPage>>,
681}
682
683impl PropertyPageListBuilder {
684    pub fn new() -> Self {
685        PropertyPageListBuilder::default()
686    }
687    pub fn with_property_pages(mut self, value: Vec<PropertyPage>) -> Self {
688        self.property_pages = Some(value);
689        self
690    }
691    pub fn build(self) -> Result<PropertyPageList, BuilderError> {
692        let property_pages = self
693            .property_pages
694            .ok_or_else(|| BuilderError::MissingField("property_pages".into()))?;
695        Ok(PropertyPageList { property_pages })
696    }
697}
698
699impl FromProto<track_and_trace_state::PropertyPageList> for PropertyPageList {
700    fn from_proto(
701        proto: track_and_trace_state::PropertyPageList,
702    ) -> Result<Self, ProtoConversionError> {
703        Ok(PropertyPageList {
704            property_pages: proto
705                .get_entries()
706                .iter()
707                .cloned()
708                .map(PropertyPage::from_proto)
709                .collect::<Result<Vec<PropertyPage>, ProtoConversionError>>()?,
710        })
711    }
712}
713
714impl FromNative<PropertyPageList> for track_and_trace_state::PropertyPageList {
715    fn from_native(native: PropertyPageList) -> Result<Self, ProtoConversionError> {
716        let mut proto = track_and_trace_state::PropertyPageList::new();
717        proto.set_entries(RepeatedField::from_vec(
718            native
719                .property_pages()
720                .iter()
721                .cloned()
722                .map(PropertyPage::into_proto)
723                .collect::<Result<Vec<track_and_trace_state::PropertyPage>, ProtoConversionError>>(
724                )?,
725        ));
726
727        Ok(proto)
728    }
729}
730
731impl FromBytes<PropertyPageList> for PropertyPageList {
732    fn from_bytes(bytes: &[u8]) -> Result<PropertyPageList, ProtoConversionError> {
733        let proto: track_and_trace_state::PropertyPageList = Message::parse_from_bytes(bytes)
734            .map_err(|_| {
735                ProtoConversionError::SerializationError(
736                    "Unable to get PropertyPageList from Bytes".into(),
737                )
738            })?;
739        proto.into_native()
740    }
741}
742impl IntoBytes for PropertyPageList {
743    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
744        let proto = self.into_proto()?;
745        let bytes = proto.write_to_bytes().map_err(|_| {
746            ProtoConversionError::SerializationError(
747                "Unable to get PropertyPageList from Bytes".into(),
748            )
749        })?;
750        Ok(bytes)
751    }
752}
753impl IntoProto<track_and_trace_state::PropertyPageList> for PropertyPageList {}
754impl IntoNative<PropertyPageList> for track_and_trace_state::PropertyPageList {}
755
756/// Possible `Role` values
757#[derive(Debug, Clone, PartialEq)]
758pub enum Role {
759    Owner,
760    Custodian,
761    Reporter,
762}
763
764impl Default for Role {
765    fn default() -> Role {
766        Role::Owner
767    }
768}
769
770impl FromProto<track_and_trace_state::Proposal_Role> for Role {
771    fn from_proto(
772        roles: track_and_trace_state::Proposal_Role,
773    ) -> Result<Self, ProtoConversionError> {
774        match roles {
775            track_and_trace_state::Proposal_Role::OWNER => Ok(Role::Owner),
776            track_and_trace_state::Proposal_Role::CUSTODIAN => Ok(Role::Custodian),
777            track_and_trace_state::Proposal_Role::REPORTER => Ok(Role::Reporter),
778        }
779    }
780}
781
782impl FromNative<Role> for track_and_trace_state::Proposal_Role {
783    fn from_native(roles: Role) -> Result<Self, ProtoConversionError> {
784        match roles {
785            Role::Owner => Ok(track_and_trace_state::Proposal_Role::OWNER),
786            Role::Custodian => Ok(track_and_trace_state::Proposal_Role::CUSTODIAN),
787            Role::Reporter => Ok(track_and_trace_state::Proposal_Role::REPORTER),
788        }
789    }
790}
791
792impl IntoProto<track_and_trace_state::Proposal_Role> for Role {}
793impl IntoNative<Role> for track_and_trace_state::Proposal_Role {}
794
795/// Possible `Proposal` statuses
796#[derive(Debug, Clone, PartialEq)]
797pub enum Status {
798    Open,
799    Accepted,
800    Rejected,
801    Canceled,
802}
803
804impl Default for Status {
805    fn default() -> Status {
806        Status::Open
807    }
808}
809
810impl FromProto<track_and_trace_state::Proposal_Status> for Status {
811    fn from_proto(
812        statuses: track_and_trace_state::Proposal_Status,
813    ) -> Result<Self, ProtoConversionError> {
814        match statuses {
815            track_and_trace_state::Proposal_Status::OPEN => Ok(Status::Open),
816            track_and_trace_state::Proposal_Status::ACCEPTED => Ok(Status::Accepted),
817            track_and_trace_state::Proposal_Status::REJECTED => Ok(Status::Rejected),
818            track_and_trace_state::Proposal_Status::CANCELED => Ok(Status::Canceled),
819        }
820    }
821}
822
823impl FromNative<Status> for track_and_trace_state::Proposal_Status {
824    fn from_native(statuses: Status) -> Result<Self, ProtoConversionError> {
825        match statuses {
826            Status::Open => Ok(track_and_trace_state::Proposal_Status::OPEN),
827            Status::Accepted => Ok(track_and_trace_state::Proposal_Status::ACCEPTED),
828            Status::Rejected => Ok(track_and_trace_state::Proposal_Status::REJECTED),
829            Status::Canceled => Ok(track_and_trace_state::Proposal_Status::CANCELED),
830        }
831    }
832}
833
834impl IntoProto<track_and_trace_state::Proposal_Status> for Status {}
835impl IntoNative<Status> for track_and_trace_state::Proposal_Status {}
836
837/// Native representation of a `Proposal`
838///
839/// A `Proposal` contains an offer from the owner or custodian of a `Record` to authorize another
840/// agent a role, either owner, custodian, or reporter for the associated `Record`.
841#[derive(Debug, Clone, PartialEq)]
842pub struct Proposal {
843    record_id: String,
844    timestamp: u64,
845    issuing_agent: String,
846    receiving_agent: String,
847    role: Role,
848    properties: Vec<String>,
849    status: Status,
850    terms: String,
851}
852
853impl Proposal {
854    pub fn record_id(&self) -> &str {
855        &self.record_id
856    }
857    pub fn timestamp(&self) -> &u64 {
858        &self.timestamp
859    }
860    pub fn issuing_agent(&self) -> &str {
861        &self.issuing_agent
862    }
863    pub fn receiving_agent(&self) -> &str {
864        &self.receiving_agent
865    }
866    pub fn role(&self) -> &Role {
867        &self.role
868    }
869    pub fn properties(&self) -> &[String] {
870        &self.properties
871    }
872    pub fn status(&self) -> &Status {
873        &self.status
874    }
875    pub fn terms(&self) -> &str {
876        &self.terms
877    }
878    pub fn into_builder(self) -> ProposalBuilder {
879        ProposalBuilder::new()
880            .with_record_id(self.record_id)
881            .with_timestamp(self.timestamp)
882            .with_issuing_agent(self.issuing_agent)
883            .with_receiving_agent(self.receiving_agent)
884            .with_role(self.role)
885            .with_properties(self.properties)
886            .with_status(self.status)
887            .with_terms(self.terms)
888    }
889}
890
891/// Builder used to create a `Proposal`
892#[derive(Default, Debug)]
893pub struct ProposalBuilder {
894    record_id: Option<String>,
895    timestamp: Option<u64>,
896    issuing_agent: Option<String>,
897    receiving_agent: Option<String>,
898    role: Option<Role>,
899    properties: Option<Vec<String>>,
900    status: Option<Status>,
901    terms: Option<String>,
902}
903
904impl ProposalBuilder {
905    pub fn new() -> Self {
906        ProposalBuilder::default()
907    }
908    pub fn with_record_id(mut self, value: String) -> Self {
909        self.record_id = Some(value);
910        self
911    }
912    pub fn with_timestamp(mut self, value: u64) -> Self {
913        self.timestamp = Some(value);
914        self
915    }
916    pub fn with_issuing_agent(mut self, value: String) -> Self {
917        self.issuing_agent = Some(value);
918        self
919    }
920    pub fn with_receiving_agent(mut self, value: String) -> Self {
921        self.receiving_agent = Some(value);
922        self
923    }
924    pub fn with_role(mut self, value: Role) -> Self {
925        self.role = Some(value);
926        self
927    }
928    pub fn with_properties(mut self, value: Vec<String>) -> Self {
929        self.properties = Some(value);
930        self
931    }
932    pub fn with_status(mut self, value: Status) -> Self {
933        self.status = Some(value);
934        self
935    }
936    pub fn with_terms(mut self, value: String) -> Self {
937        self.terms = Some(value);
938        self
939    }
940    pub fn build(self) -> Result<Proposal, BuilderError> {
941        let record_id = self
942            .record_id
943            .ok_or_else(|| BuilderError::MissingField("record_id".into()))?;
944        let timestamp = self
945            .timestamp
946            .ok_or_else(|| BuilderError::MissingField("timestamp".into()))?;
947        let issuing_agent = self
948            .issuing_agent
949            .ok_or_else(|| BuilderError::MissingField("issuing_agent".into()))?;
950        let receiving_agent = self
951            .receiving_agent
952            .ok_or_else(|| BuilderError::MissingField("receiving_agent".into()))?;
953        let role = self
954            .role
955            .ok_or_else(|| BuilderError::MissingField("role".into()))?;
956        let properties = self
957            .properties
958            .ok_or_else(|| BuilderError::MissingField("properties".into()))?;
959        let status = self
960            .status
961            .ok_or_else(|| BuilderError::MissingField("status".into()))?;
962        let terms = self
963            .terms
964            .ok_or_else(|| BuilderError::MissingField("terms".into()))?;
965        Ok(Proposal {
966            record_id,
967            timestamp,
968            issuing_agent,
969            receiving_agent,
970            role,
971            properties,
972            status,
973            terms,
974        })
975    }
976}
977
978impl FromProto<track_and_trace_state::Proposal> for Proposal {
979    fn from_proto(proto: track_and_trace_state::Proposal) -> Result<Self, ProtoConversionError> {
980        Ok(Proposal {
981            record_id: proto.get_record_id().to_string(),
982            timestamp: proto.get_timestamp(),
983            issuing_agent: proto.get_issuing_agent().to_string(),
984            receiving_agent: proto.get_receiving_agent().to_string(),
985            role: Role::from_proto(proto.get_role())?,
986            properties: proto
987                .get_properties()
988                .iter()
989                .cloned()
990                .map(String::from)
991                .collect(),
992            status: Status::from_proto(proto.get_status())?,
993            terms: proto.get_terms().to_string(),
994        })
995    }
996}
997
998impl FromNative<Proposal> for track_and_trace_state::Proposal {
999    fn from_native(native: Proposal) -> Result<Self, ProtoConversionError> {
1000        let mut proto = track_and_trace_state::Proposal::new();
1001
1002        proto.set_record_id(native.record_id().to_string());
1003        proto.set_timestamp(*native.timestamp());
1004        proto.set_issuing_agent(native.issuing_agent().to_string());
1005        proto.set_receiving_agent(native.receiving_agent().to_string());
1006        proto.set_role(native.role().clone().into_proto()?);
1007        proto.set_properties(RepeatedField::from_vec(native.properties().to_vec()));
1008        proto.set_status(native.status().clone().into_proto()?);
1009        proto.set_terms(native.terms().to_string());
1010
1011        Ok(proto)
1012    }
1013}
1014
1015impl FromBytes<Proposal> for Proposal {
1016    fn from_bytes(bytes: &[u8]) -> Result<Proposal, ProtoConversionError> {
1017        let proto: track_and_trace_state::Proposal =
1018            Message::parse_from_bytes(bytes).map_err(|_| {
1019                ProtoConversionError::SerializationError("Unable to get Proposal from bytes".into())
1020            })?;
1021        proto.into_native()
1022    }
1023}
1024
1025impl IntoBytes for Proposal {
1026    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
1027        let proto = self.into_proto()?;
1028        let bytes = proto.write_to_bytes().map_err(|_| {
1029            ProtoConversionError::SerializationError("Unable to get Proposal from bytes".into())
1030        })?;
1031        Ok(bytes)
1032    }
1033}
1034impl IntoProto<track_and_trace_state::Proposal> for Proposal {}
1035impl IntoNative<Proposal> for track_and_trace_state::Proposal {}
1036
1037/// Native representation of a list of `Proposal`s
1038#[derive(Debug, Clone, PartialEq)]
1039pub struct ProposalList {
1040    proposals: Vec<Proposal>,
1041}
1042
1043impl ProposalList {
1044    pub fn proposals(&self) -> &[Proposal] {
1045        &self.proposals
1046    }
1047
1048    pub fn into_builder(self) -> ProposalListBuilder {
1049        ProposalListBuilder::new().with_proposals(self.proposals)
1050    }
1051}
1052
1053/// Builder used to create a list of `Proposal`s
1054#[derive(Default, Debug)]
1055pub struct ProposalListBuilder {
1056    proposals: Option<Vec<Proposal>>,
1057}
1058
1059impl ProposalListBuilder {
1060    pub fn new() -> Self {
1061        ProposalListBuilder::default()
1062    }
1063    pub fn with_proposals(mut self, value: Vec<Proposal>) -> Self {
1064        self.proposals = Some(value);
1065        self
1066    }
1067    pub fn build(self) -> Result<ProposalList, BuilderError> {
1068        let proposals = self
1069            .proposals
1070            .ok_or_else(|| BuilderError::MissingField("proposals".into()))?;
1071        Ok(ProposalList { proposals })
1072    }
1073}
1074
1075impl FromProto<track_and_trace_state::ProposalList> for ProposalList {
1076    fn from_proto(
1077        proto: track_and_trace_state::ProposalList,
1078    ) -> Result<Self, ProtoConversionError> {
1079        Ok(ProposalList {
1080            proposals: proto
1081                .get_entries()
1082                .iter()
1083                .cloned()
1084                .map(Proposal::from_proto)
1085                .collect::<Result<Vec<Proposal>, ProtoConversionError>>()?,
1086        })
1087    }
1088}
1089
1090impl FromNative<ProposalList> for track_and_trace_state::ProposalList {
1091    fn from_native(native: ProposalList) -> Result<Self, ProtoConversionError> {
1092        let mut proto = track_and_trace_state::ProposalList::new();
1093        proto.set_entries(RepeatedField::from_vec(
1094            native
1095                .proposals()
1096                .iter()
1097                .cloned()
1098                .map(Proposal::into_proto)
1099                .collect::<Result<Vec<track_and_trace_state::Proposal>, ProtoConversionError>>()?,
1100        ));
1101
1102        Ok(proto)
1103    }
1104}
1105
1106impl FromBytes<ProposalList> for ProposalList {
1107    fn from_bytes(bytes: &[u8]) -> Result<ProposalList, ProtoConversionError> {
1108        let proto: track_and_trace_state::ProposalList =
1109            Message::parse_from_bytes(bytes).map_err(|_| {
1110                ProtoConversionError::SerializationError(
1111                    "Unable to get ProposalList from bytes".into(),
1112                )
1113            })?;
1114        proto.into_native()
1115    }
1116}
1117
1118impl IntoBytes for ProposalList {
1119    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
1120        let proto = self.into_proto()?;
1121        let bytes = proto.write_to_bytes().map_err(|_| {
1122            ProtoConversionError::SerializationError("Unable to get ProposalList from bytes".into())
1123        })?;
1124        Ok(bytes)
1125    }
1126}
1127
1128impl IntoProto<track_and_trace_state::ProposalList> for ProposalList {}
1129impl IntoNative<ProposalList> for track_and_trace_state::ProposalList {}
1130
1131/// Native representation of an `AssociatedAgent`
1132///
1133/// This struct represents a cryptographic public key that identifies an agent associated with
1134/// a `Record`
1135#[derive(Debug, Clone, PartialEq)]
1136pub struct AssociatedAgent {
1137    agent_id: String,
1138    timestamp: u64,
1139}
1140
1141impl AssociatedAgent {
1142    pub fn agent_id(&self) -> &str {
1143        &self.agent_id
1144    }
1145    pub fn timestamp(&self) -> &u64 {
1146        &self.timestamp
1147    }
1148
1149    pub fn into_builder(self) -> AssociatedAgentBuilder {
1150        AssociatedAgentBuilder::new()
1151            .with_agent_id(self.agent_id)
1152            .with_timestamp(self.timestamp)
1153    }
1154}
1155
1156/// Builder used to create an `AssociatedAgent`
1157#[derive(Default, Debug)]
1158pub struct AssociatedAgentBuilder {
1159    agent_id: Option<String>,
1160    timestamp: Option<u64>,
1161}
1162
1163impl AssociatedAgentBuilder {
1164    pub fn new() -> Self {
1165        AssociatedAgentBuilder::default()
1166    }
1167    pub fn with_agent_id(mut self, value: String) -> Self {
1168        self.agent_id = Some(value);
1169        self
1170    }
1171    pub fn with_timestamp(mut self, value: u64) -> Self {
1172        self.timestamp = Some(value);
1173        self
1174    }
1175    pub fn build(self) -> Result<AssociatedAgent, BuilderError> {
1176        let agent_id = self
1177            .agent_id
1178            .ok_or_else(|| BuilderError::MissingField("agent_id".into()))?;
1179        let timestamp = self
1180            .timestamp
1181            .ok_or_else(|| BuilderError::MissingField("timestamp".into()))?;
1182        Ok(AssociatedAgent {
1183            agent_id,
1184            timestamp,
1185        })
1186    }
1187}
1188
1189impl FromProto<track_and_trace_state::Record_AssociatedAgent> for AssociatedAgent {
1190    fn from_proto(
1191        proto: track_and_trace_state::Record_AssociatedAgent,
1192    ) -> Result<Self, ProtoConversionError> {
1193        Ok(AssociatedAgent {
1194            agent_id: proto.get_agent_id().to_string(),
1195            timestamp: proto.get_timestamp(),
1196        })
1197    }
1198}
1199
1200impl FromNative<AssociatedAgent> for track_and_trace_state::Record_AssociatedAgent {
1201    fn from_native(native: AssociatedAgent) -> Result<Self, ProtoConversionError> {
1202        let mut proto = track_and_trace_state::Record_AssociatedAgent::new();
1203
1204        proto.set_agent_id(native.agent_id().to_string());
1205        proto.set_timestamp(*native.timestamp());
1206
1207        Ok(proto)
1208    }
1209}
1210
1211impl FromBytes<AssociatedAgent> for AssociatedAgent {
1212    fn from_bytes(bytes: &[u8]) -> Result<AssociatedAgent, ProtoConversionError> {
1213        let proto: track_and_trace_state::Record_AssociatedAgent = Message::parse_from_bytes(bytes)
1214            .map_err(|_| {
1215                ProtoConversionError::SerializationError(
1216                    "Unable to get AssociatedAgent from bytes".into(),
1217                )
1218            })?;
1219        proto.into_native()
1220    }
1221}
1222impl IntoBytes for AssociatedAgent {
1223    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
1224        let proto = self.into_proto()?;
1225        let bytes = proto.write_to_bytes().map_err(|_| {
1226            ProtoConversionError::SerializationError(
1227                "Unable to get AssociatedAgent from bytes".into(),
1228            )
1229        })?;
1230        Ok(bytes)
1231    }
1232}
1233impl IntoProto<track_and_trace_state::Record_AssociatedAgent> for AssociatedAgent {}
1234impl IntoNative<AssociatedAgent> for track_and_trace_state::Record_AssociatedAgent {}
1235
1236/// Native representation of a `Record`
1237///
1238/// A record represents the goods being tracked
1239#[derive(Debug, Clone, PartialEq)]
1240pub struct Record {
1241    record_id: String,
1242    schema: String,
1243    owners: Vec<AssociatedAgent>,
1244    custodians: Vec<AssociatedAgent>,
1245    field_final: bool,
1246}
1247
1248impl Record {
1249    pub fn record_id(&self) -> &str {
1250        &self.record_id
1251    }
1252    pub fn schema(&self) -> &str {
1253        &self.schema
1254    }
1255    pub fn owners(&self) -> &[AssociatedAgent] {
1256        &self.owners
1257    }
1258    pub fn custodians(&self) -> &[AssociatedAgent] {
1259        &self.custodians
1260    }
1261    pub fn field_final(&self) -> &bool {
1262        &self.field_final
1263    }
1264    pub fn into_builder(self) -> RecordBuilder {
1265        RecordBuilder::new()
1266            .with_record_id(self.record_id)
1267            .with_schema(self.schema)
1268            .with_owners(self.owners)
1269            .with_custodians(self.custodians)
1270            .with_field_final(self.field_final)
1271    }
1272}
1273
1274/// Builder used to create a `Record`
1275#[derive(Default, Debug)]
1276pub struct RecordBuilder {
1277    record_id: Option<String>,
1278    schema: Option<String>,
1279    owners: Option<Vec<AssociatedAgent>>,
1280    custodians: Option<Vec<AssociatedAgent>>,
1281    field_final: Option<bool>,
1282}
1283
1284impl RecordBuilder {
1285    pub fn new() -> Self {
1286        RecordBuilder::default()
1287    }
1288    pub fn with_record_id(mut self, value: String) -> Self {
1289        self.record_id = Some(value);
1290        self
1291    }
1292    pub fn with_schema(mut self, value: String) -> Self {
1293        self.schema = Some(value);
1294        self
1295    }
1296    pub fn with_owners(mut self, value: Vec<AssociatedAgent>) -> Self {
1297        self.owners = Some(value);
1298        self
1299    }
1300    pub fn with_custodians(mut self, value: Vec<AssociatedAgent>) -> Self {
1301        self.custodians = Some(value);
1302        self
1303    }
1304    pub fn with_field_final(mut self, value: bool) -> Self {
1305        self.field_final = Some(value);
1306        self
1307    }
1308    pub fn build(self) -> Result<Record, BuilderError> {
1309        let record_id = self
1310            .record_id
1311            .ok_or_else(|| BuilderError::MissingField("record_id".into()))?;
1312        let schema = self
1313            .schema
1314            .ok_or_else(|| BuilderError::MissingField("schema".into()))?;
1315        let owners = self
1316            .owners
1317            .ok_or_else(|| BuilderError::MissingField("owners".into()))?;
1318        let custodians = self
1319            .custodians
1320            .ok_or_else(|| BuilderError::MissingField("custodians".into()))?;
1321        let field_final = self
1322            .field_final
1323            .ok_or_else(|| BuilderError::MissingField("field_final".into()))?;
1324        Ok(Record {
1325            record_id,
1326            schema,
1327            owners,
1328            custodians,
1329            field_final,
1330        })
1331    }
1332}
1333
1334impl FromProto<track_and_trace_state::Record> for Record {
1335    fn from_proto(proto: track_and_trace_state::Record) -> Result<Self, ProtoConversionError> {
1336        Ok(Record {
1337            record_id: proto.get_record_id().to_string(),
1338            schema: proto.get_schema().to_string(),
1339            owners: proto
1340                .get_owners()
1341                .iter()
1342                .cloned()
1343                .map(AssociatedAgent::from_proto)
1344                .collect::<Result<Vec<AssociatedAgent>, ProtoConversionError>>()?,
1345            custodians: proto
1346                .get_custodians()
1347                .iter()
1348                .cloned()
1349                .map(AssociatedAgent::from_proto)
1350                .collect::<Result<Vec<AssociatedAgent>, ProtoConversionError>>()?,
1351            field_final: proto.get_field_final(),
1352        })
1353    }
1354}
1355
1356impl FromNative<Record> for track_and_trace_state::Record {
1357    fn from_native(native: Record) -> Result<Self, ProtoConversionError> {
1358        let mut proto = track_and_trace_state::Record::new();
1359        proto.set_record_id(native.record_id().to_string());
1360        proto.set_schema(native.schema().to_string());
1361        proto.set_owners(
1362            RepeatedField::from_vec(
1363                native
1364                    .owners()
1365                    .iter()
1366                    .cloned()
1367                    .map(AssociatedAgent::into_proto)
1368                    .collect::<Result<
1369                        Vec<track_and_trace_state::Record_AssociatedAgent>,
1370                        ProtoConversionError,
1371                    >>()?,
1372            ),
1373        );
1374        proto.set_custodians(
1375            RepeatedField::from_vec(
1376                native
1377                    .custodians()
1378                    .iter()
1379                    .cloned()
1380                    .map(AssociatedAgent::into_proto)
1381                    .collect::<Result<
1382                        Vec<track_and_trace_state::Record_AssociatedAgent>,
1383                        ProtoConversionError,
1384                    >>()?,
1385            ),
1386        );
1387        proto.set_field_final(*native.field_final());
1388
1389        Ok(proto)
1390    }
1391}
1392
1393impl FromBytes<Record> for Record {
1394    fn from_bytes(bytes: &[u8]) -> Result<Record, ProtoConversionError> {
1395        let proto: track_and_trace_state::Record =
1396            Message::parse_from_bytes(bytes).map_err(|_| {
1397                ProtoConversionError::SerializationError("Unable to get Record from bytes".into())
1398            })?;
1399        proto.into_native()
1400    }
1401}
1402impl IntoBytes for Record {
1403    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
1404        let proto = self.into_proto()?;
1405        let bytes = proto.write_to_bytes().map_err(|_| {
1406            ProtoConversionError::SerializationError("Unable to get Record from bytes".into())
1407        })?;
1408        Ok(bytes)
1409    }
1410}
1411impl IntoProto<track_and_trace_state::Record> for Record {}
1412impl IntoNative<Record> for track_and_trace_state::Record {}
1413
1414/// Native representation of a list of `Record`s
1415#[derive(Debug, Clone, PartialEq)]
1416pub struct RecordList {
1417    records: Vec<Record>,
1418}
1419
1420impl RecordList {
1421    pub fn records(&self) -> &[Record] {
1422        &self.records
1423    }
1424
1425    pub fn into_builder(self) -> RecordListBuilder {
1426        RecordListBuilder::new().with_records(self.records)
1427    }
1428}
1429
1430/// Builder used to create a list of `Record`s
1431#[derive(Default, Debug)]
1432pub struct RecordListBuilder {
1433    records: Option<Vec<Record>>,
1434}
1435
1436impl RecordListBuilder {
1437    pub fn new() -> Self {
1438        RecordListBuilder::default()
1439    }
1440    pub fn with_records(mut self, value: Vec<Record>) -> Self {
1441        self.records = Some(value);
1442        self
1443    }
1444    pub fn build(self) -> Result<RecordList, BuilderError> {
1445        let records = self
1446            .records
1447            .ok_or_else(|| BuilderError::MissingField("records".into()))?;
1448        Ok(RecordList { records })
1449    }
1450}
1451
1452impl FromProto<track_and_trace_state::RecordList> for RecordList {
1453    fn from_proto(proto: track_and_trace_state::RecordList) -> Result<Self, ProtoConversionError> {
1454        Ok(RecordList {
1455            records: proto
1456                .get_entries()
1457                .iter()
1458                .cloned()
1459                .map(Record::from_proto)
1460                .collect::<Result<Vec<Record>, ProtoConversionError>>()?,
1461        })
1462    }
1463}
1464
1465impl FromNative<RecordList> for track_and_trace_state::RecordList {
1466    fn from_native(native: RecordList) -> Result<Self, ProtoConversionError> {
1467        let mut proto = track_and_trace_state::RecordList::new();
1468        proto.set_entries(RepeatedField::from_vec(
1469            native
1470                .records()
1471                .iter()
1472                .cloned()
1473                .map(Record::into_proto)
1474                .collect::<Result<Vec<track_and_trace_state::Record>, ProtoConversionError>>()?,
1475        ));
1476
1477        Ok(proto)
1478    }
1479}
1480
1481impl FromBytes<RecordList> for RecordList {
1482    fn from_bytes(bytes: &[u8]) -> Result<RecordList, ProtoConversionError> {
1483        let proto: track_and_trace_state::RecordList =
1484            Message::parse_from_bytes(bytes).map_err(|_| {
1485                ProtoConversionError::SerializationError("Unable to get Record from bytes".into())
1486            })?;
1487        proto.into_native()
1488    }
1489}
1490
1491impl IntoBytes for RecordList {
1492    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
1493        let proto = self.into_proto()?;
1494        let bytes = proto.write_to_bytes().map_err(|_| {
1495            ProtoConversionError::SerializationError("Unable to get Record from bytes".into())
1496        })?;
1497        Ok(bytes)
1498    }
1499}
1500impl IntoProto<track_and_trace_state::RecordList> for RecordList {}
1501impl IntoNative<RecordList> for track_and_trace_state::RecordList {}
1502
1503#[cfg(test)]
1504mod tests {
1505    use super::*;
1506    use crate::protocol::schema::state::{
1507        DataType, PropertyDefinitionBuilder, PropertyValueBuilder,
1508    };
1509    use std::fmt::Debug;
1510
1511    fn test_from_bytes<T: FromBytes<T> + Clone + PartialEq + IntoBytes + Debug, F>(
1512        under_test: T,
1513        from_bytes: F,
1514    ) where
1515        F: Fn(&[u8]) -> Result<T, ProtoConversionError>,
1516    {
1517        let bytes = under_test.clone().into_bytes().unwrap();
1518        let created_from_bytes = from_bytes(&bytes).unwrap();
1519        assert_eq!(under_test, created_from_bytes);
1520    }
1521
1522    #[test]
1523    /// Validate a `Reporter` is built correctly
1524    fn test_reporter_builder() {
1525        let builder = ReporterBuilder::new();
1526        let reporter = builder
1527            .with_public_key("1234".to_string())
1528            .with_authorized(true)
1529            .with_index(0)
1530            .build()
1531            .unwrap();
1532
1533        assert_eq!(reporter.public_key(), "1234");
1534        assert_eq!(*reporter.authorized(), true);
1535        assert_eq!(*reporter.index(), 0);
1536    }
1537
1538    #[test]
1539    /// Validate a `Reporter` is built correctly and may be correctly converted back into a builder
1540    fn test_reporter_into_builder() {
1541        let reporter = ReporterBuilder::new()
1542            .with_public_key("1234".to_string())
1543            .with_authorized(true)
1544            .with_index(0)
1545            .build()
1546            .unwrap();
1547
1548        let builder = reporter.into_builder();
1549
1550        assert_eq!(builder.public_key, Some("1234".to_string()));
1551        assert_eq!(builder.authorized, Some(true));
1552        assert_eq!(builder.index, Some(0));
1553    }
1554
1555    #[test]
1556    /// Validate a `Reporter` may be converted into bytes and back to its native representation
1557    /// successfully
1558    fn test_reporter_bytes() {
1559        let builder = ReporterBuilder::new();
1560        let original = builder
1561            .with_public_key("1234".to_string())
1562            .with_authorized(true)
1563            .with_index(0)
1564            .build()
1565            .unwrap();
1566
1567        test_from_bytes(original, Reporter::from_bytes);
1568    }
1569
1570    #[test]
1571    /// Validate a `Property` is built correctly
1572    fn test_property_builder() {
1573        let property_definition = PropertyDefinitionBuilder::new()
1574            .with_name("i dunno".into())
1575            .with_data_type(DataType::String)
1576            .with_required(true)
1577            .with_description("test".into())
1578            .build()
1579            .unwrap();
1580
1581        let reporter = ReporterBuilder::new()
1582            .with_public_key("1234".to_string())
1583            .with_authorized(true)
1584            .with_index(0)
1585            .build()
1586            .unwrap();
1587
1588        let property = PropertyBuilder::new()
1589            .with_name("taco".into())
1590            .with_record_id("taco1234".into())
1591            .with_property_definition(property_definition.clone())
1592            .with_reporters(vec![reporter.clone()])
1593            .with_current_page(0)
1594            .with_wrapped(true)
1595            .build()
1596            .unwrap();
1597
1598        assert_eq!(property.name(), "taco");
1599        assert_eq!(property.record_id(), "taco1234");
1600        assert_eq!(*property.property_definition(), property_definition);
1601        assert!(property.reporters().iter().any(|x| *x == reporter));
1602        assert_eq!(*property.current_page(), 0);
1603        assert_eq!(*property.wrapped(), true);
1604    }
1605
1606    #[test]
1607    /// Validate a `Property` is built and may be converted back into a builder
1608    fn test_property_into_builder() {
1609        let property_definition = PropertyDefinitionBuilder::new()
1610            .with_name("i dunno".into())
1611            .with_data_type(DataType::String)
1612            .with_required(true)
1613            .with_description("test".into())
1614            .build()
1615            .unwrap();
1616
1617        let reporter = ReporterBuilder::new()
1618            .with_public_key("1234".to_string())
1619            .with_authorized(true)
1620            .with_index(0)
1621            .build()
1622            .unwrap();
1623
1624        let property = PropertyBuilder::new()
1625            .with_name("taco".into())
1626            .with_record_id("taco1234".into())
1627            .with_property_definition(property_definition.clone())
1628            .with_reporters(vec![reporter.clone()])
1629            .with_current_page(0)
1630            .with_wrapped(true)
1631            .build()
1632            .unwrap();
1633
1634        let builder = property.into_builder();
1635
1636        assert_eq!(builder.name, Some("taco".to_string()));
1637        assert_eq!(builder.record_id, Some("taco1234".to_string()));
1638        assert_eq!(builder.property_definition, Some(property_definition));
1639        assert_eq!(builder.reporters, Some(vec![reporter]));
1640        assert_eq!(builder.current_page, Some(0));
1641        assert_eq!(builder.wrapped, Some(true));
1642    }
1643
1644    #[test]
1645    /// Validate a `Property` may be converted into bytes and back to its native representation
1646    /// successfully
1647    fn test_property_bytes() {
1648        let property_definition = PropertyDefinitionBuilder::new()
1649            .with_name("i dunno".into())
1650            .with_data_type(DataType::String)
1651            .with_required(true)
1652            .with_description("test".into())
1653            .build()
1654            .unwrap();
1655
1656        let reporter = ReporterBuilder::new()
1657            .with_public_key("1234".to_string())
1658            .with_authorized(true)
1659            .with_index(0)
1660            .build()
1661            .unwrap();
1662
1663        let property = PropertyBuilder::new()
1664            .with_name("taco".into())
1665            .with_record_id("taco1234".into())
1666            .with_property_definition(property_definition.clone())
1667            .with_reporters(vec![reporter.clone()])
1668            .with_current_page(0)
1669            .with_wrapped(true)
1670            .build()
1671            .unwrap();
1672
1673        test_from_bytes(property, Property::from_bytes);
1674    }
1675
1676    #[test]
1677    /// Validate a `PropertList` is built correctly
1678    fn test_property_list_builder() {
1679        let property_definition = PropertyDefinitionBuilder::new()
1680            .with_name("i dunno".into())
1681            .with_data_type(DataType::String)
1682            .with_required(true)
1683            .with_description("test".into())
1684            .build()
1685            .unwrap();
1686
1687        let reporter = ReporterBuilder::new()
1688            .with_public_key("1234".to_string())
1689            .with_authorized(true)
1690            .with_index(0)
1691            .build()
1692            .unwrap();
1693
1694        let property = PropertyBuilder::new()
1695            .with_name("taco".into())
1696            .with_record_id("taco1234".into())
1697            .with_property_definition(property_definition.clone())
1698            .with_reporters(vec![reporter.clone()])
1699            .with_current_page(0)
1700            .with_wrapped(true)
1701            .build()
1702            .unwrap();
1703
1704        let property_list = PropertyListBuilder::new()
1705            .with_properties(vec![property.clone()])
1706            .build()
1707            .unwrap();
1708
1709        assert!(property_list.properties().iter().any(|x| *x == property));
1710    }
1711
1712    #[test]
1713    /// Validate a `PropertyList` is built and may be converted back into a builder
1714    fn test_property_list_into_builder() {
1715        let property_definition = PropertyDefinitionBuilder::new()
1716            .with_name("i dunno".into())
1717            .with_data_type(DataType::String)
1718            .with_required(true)
1719            .with_description("test".into())
1720            .build()
1721            .unwrap();
1722
1723        let reporter = ReporterBuilder::new()
1724            .with_public_key("1234".to_string())
1725            .with_authorized(true)
1726            .with_index(0)
1727            .build()
1728            .unwrap();
1729
1730        let property = PropertyBuilder::new()
1731            .with_name("taco".into())
1732            .with_record_id("taco1234".into())
1733            .with_property_definition(property_definition.clone())
1734            .with_reporters(vec![reporter.clone()])
1735            .with_current_page(0)
1736            .with_wrapped(true)
1737            .build()
1738            .unwrap();
1739
1740        let property_list = PropertyListBuilder::new()
1741            .with_properties(vec![property.clone()])
1742            .build()
1743            .unwrap();
1744
1745        let builder = property_list.into_builder();
1746
1747        assert_eq!(builder.properties, Some(vec![property]));
1748    }
1749
1750    #[test]
1751    /// Validate a `PropertyList` may be converted into bytes and back to its native represenation
1752    /// successfully
1753    fn test_property_list_bytes() {
1754        let property_definition = PropertyDefinitionBuilder::new()
1755            .with_name("i dunno".into())
1756            .with_data_type(DataType::String)
1757            .with_required(true)
1758            .with_description("test".into())
1759            .build()
1760            .unwrap();
1761
1762        let reporter = ReporterBuilder::new()
1763            .with_public_key("1234".to_string())
1764            .with_authorized(true)
1765            .with_index(0)
1766            .build()
1767            .unwrap();
1768
1769        let property = PropertyBuilder::new()
1770            .with_name("taco".into())
1771            .with_record_id("taco1234".into())
1772            .with_property_definition(property_definition.clone())
1773            .with_reporters(vec![reporter.clone()])
1774            .with_current_page(0)
1775            .with_wrapped(true)
1776            .build()
1777            .unwrap();
1778
1779        let property_list = PropertyListBuilder::new()
1780            .with_properties(vec![property])
1781            .build()
1782            .unwrap();
1783
1784        test_from_bytes(property_list, PropertyList::from_bytes);
1785    }
1786
1787    #[test]
1788    /// Validate a `PropertyPage` is built correctly
1789    fn test_property_page() {
1790        let property_value = PropertyValueBuilder::new()
1791            .with_name("egg".into())
1792            .with_data_type(DataType::Number)
1793            .with_number_value(42)
1794            .build()
1795            .unwrap();
1796
1797        let reported_value = ReportedValueBuilder::new()
1798            .with_reporter_index(0)
1799            .with_timestamp(214)
1800            .with_value(property_value)
1801            .build()
1802            .unwrap();
1803
1804        let property_page = PropertyPageBuilder::new()
1805            .with_name("egg".into())
1806            .with_record_id("egg1234".into())
1807            .with_reported_values(vec![reported_value.clone()])
1808            .build()
1809            .unwrap();
1810
1811        assert_eq!(property_page.name(), "egg");
1812        assert_eq!(property_page.record_id(), "egg1234");
1813        assert!(property_page
1814            .reported_values()
1815            .iter()
1816            .any(|x| *x == reported_value));
1817    }
1818
1819    #[test]
1820    /// Validate a `PropertyPage` is built and may be converted back to a builder
1821    fn test_property_page_into_builder() {
1822        let property_value = PropertyValueBuilder::new()
1823            .with_name("egg".into())
1824            .with_data_type(DataType::Number)
1825            .with_number_value(42)
1826            .build()
1827            .unwrap();
1828
1829        let reported_value = ReportedValueBuilder::new()
1830            .with_reporter_index(0)
1831            .with_timestamp(214)
1832            .with_value(property_value)
1833            .build()
1834            .unwrap();
1835
1836        let property_page = PropertyPageBuilder::new()
1837            .with_name("egg".into())
1838            .with_record_id("egg1234".into())
1839            .with_reported_values(vec![reported_value.clone()])
1840            .build()
1841            .unwrap();
1842
1843        let builder = property_page.into_builder();
1844
1845        assert_eq!(builder.name, Some("egg".to_string()));
1846        assert_eq!(builder.record_id, Some("egg1234".to_string()));
1847        assert_eq!(builder.reported_values, Some(vec![reported_value]));
1848    }
1849
1850    #[test]
1851    /// Validate a `PropertyPage` may be converted into bytes and back to its native representation
1852    /// successfully
1853    fn test_property_page_bytes() {
1854        let property_value = PropertyValueBuilder::new()
1855            .with_name("egg".into())
1856            .with_data_type(DataType::Number)
1857            .with_number_value(42)
1858            .build()
1859            .unwrap();
1860
1861        let reported_value = ReportedValueBuilder::new()
1862            .with_reporter_index(0)
1863            .with_timestamp(214)
1864            .with_value(property_value)
1865            .build()
1866            .unwrap();
1867
1868        let property_page = PropertyPageBuilder::new()
1869            .with_name("egg".into())
1870            .with_record_id("egg1234".into())
1871            .with_reported_values(vec![reported_value.clone()])
1872            .build()
1873            .unwrap();
1874
1875        test_from_bytes(property_page, PropertyPage::from_bytes);
1876    }
1877
1878    #[test]
1879    /// Validate a `PropertyPageList` is built correctly
1880    fn test_property_page_list() {
1881        let property_value = PropertyValueBuilder::new()
1882            .with_name("egg".into())
1883            .with_data_type(DataType::Number)
1884            .with_number_value(42)
1885            .build()
1886            .unwrap();
1887
1888        let reported_value = ReportedValueBuilder::new()
1889            .with_reporter_index(0)
1890            .with_timestamp(214)
1891            .with_value(property_value)
1892            .build()
1893            .unwrap();
1894
1895        let property_page = PropertyPageBuilder::new()
1896            .with_name("egg".into())
1897            .with_record_id("egg1234".into())
1898            .with_reported_values(vec![reported_value.clone()])
1899            .build()
1900            .unwrap();
1901
1902        let property_page_list = PropertyPageListBuilder::new()
1903            .with_property_pages(vec![property_page.clone()])
1904            .build()
1905            .unwrap();
1906
1907        assert!(property_page_list
1908            .property_pages()
1909            .iter()
1910            .any(|x| *x == property_page))
1911    }
1912
1913    #[test]
1914    /// Validate a `PropertyPageList` is built and may be converted back into a builder
1915    fn test_property_page_list_into_builder() {
1916        let property_value = PropertyValueBuilder::new()
1917            .with_name("egg".into())
1918            .with_data_type(DataType::Number)
1919            .with_number_value(42)
1920            .build()
1921            .unwrap();
1922
1923        let reported_value = ReportedValueBuilder::new()
1924            .with_reporter_index(0)
1925            .with_timestamp(214)
1926            .with_value(property_value)
1927            .build()
1928            .unwrap();
1929
1930        let property_page = PropertyPageBuilder::new()
1931            .with_name("egg".into())
1932            .with_record_id("egg1234".into())
1933            .with_reported_values(vec![reported_value.clone()])
1934            .build()
1935            .unwrap();
1936
1937        let property_page_list = PropertyPageListBuilder::new()
1938            .with_property_pages(vec![property_page.clone()])
1939            .build()
1940            .unwrap();
1941
1942        let builder = property_page_list.into_builder();
1943
1944        assert_eq!(builder.property_pages, Some(vec![property_page]))
1945    }
1946
1947    #[test]
1948    /// Validate a `PropertyPageList` may be converted into bytes and back to its native
1949    /// representation successfully
1950    fn test_property_page_list_bytes() {
1951        let property_value = PropertyValueBuilder::new()
1952            .with_name("egg".into())
1953            .with_data_type(DataType::Number)
1954            .with_number_value(42)
1955            .build()
1956            .unwrap();
1957
1958        let reported_value = ReportedValueBuilder::new()
1959            .with_reporter_index(0)
1960            .with_timestamp(214)
1961            .with_value(property_value)
1962            .build()
1963            .unwrap();
1964
1965        let property_page = PropertyPageBuilder::new()
1966            .with_name("egg".into())
1967            .with_record_id("egg1234".into())
1968            .with_reported_values(vec![reported_value.clone()])
1969            .build()
1970            .unwrap();
1971
1972        let property_page_list = PropertyPageListBuilder::new()
1973            .with_property_pages(vec![property_page.clone()])
1974            .build()
1975            .unwrap();
1976
1977        test_from_bytes(property_page_list, PropertyPageList::from_bytes);
1978    }
1979
1980    #[test]
1981    /// Validate a `Proposal` is built correctly
1982    fn test_proposal_builder() {
1983        let proposal = ProposalBuilder::new()
1984            .with_record_id("egg1234".into())
1985            .with_timestamp(214)
1986            .with_issuing_agent("james".into())
1987            .with_receiving_agent("joe".into())
1988            .with_role(Role::Owner)
1989            .with_properties(vec!["wet".into()])
1990            .with_status(Status::Open)
1991            .with_terms("a term".into())
1992            .build()
1993            .unwrap();
1994
1995        assert_eq!(proposal.record_id(), "egg1234");
1996        assert_eq!(*proposal.timestamp(), 214);
1997        assert_eq!(proposal.issuing_agent(), "james");
1998        assert_eq!(proposal.receiving_agent(), "joe");
1999        assert_eq!(*proposal.role(), Role::Owner);
2000        assert!(proposal.properties().iter().any(|x| x == "wet"));
2001        assert_eq!(*proposal.status(), Status::Open);
2002        assert_eq!(proposal.terms(), "a term");
2003    }
2004
2005    #[test]
2006    /// Validate a `Proposal` is built and may be converted back to its builder
2007    fn test_proposal_into_builder() {
2008        let proposal = ProposalBuilder::new()
2009            .with_record_id("egg1234".into())
2010            .with_timestamp(214)
2011            .with_issuing_agent("james".into())
2012            .with_receiving_agent("joe".into())
2013            .with_role(Role::Owner)
2014            .with_properties(vec!["wet".into()])
2015            .with_status(Status::Open)
2016            .with_terms("a term".into())
2017            .build()
2018            .unwrap();
2019
2020        let builder = proposal.into_builder();
2021
2022        assert_eq!(builder.record_id, Some("egg1234".to_string()));
2023        assert_eq!(builder.timestamp, Some(214));
2024        assert_eq!(builder.issuing_agent, Some("james".to_string()));
2025        assert_eq!(builder.receiving_agent, Some("joe".to_string()));
2026        assert_eq!(builder.role, Some(Role::Owner));
2027        assert_eq!(builder.properties, Some(vec!["wet".to_string()]));
2028        assert_eq!(builder.status, Some(Status::Open));
2029        assert_eq!(builder.terms, Some("a term".to_string()));
2030    }
2031
2032    #[test]
2033    /// Validate a `Proposal` may be converted into bytes and back to its native representation
2034    /// successfully
2035    fn test_proposal_bytes() {
2036        let proposal = ProposalBuilder::new()
2037            .with_record_id("egg1234".into())
2038            .with_timestamp(214)
2039            .with_issuing_agent("james".into())
2040            .with_receiving_agent("joe".into())
2041            .with_role(Role::Owner)
2042            .with_properties(vec!["wet".into(), "gets everywhere".into()])
2043            .with_status(Status::Open)
2044            .with_terms("a term".into())
2045            .build()
2046            .unwrap();
2047
2048        test_from_bytes(proposal, Proposal::from_bytes);
2049    }
2050
2051    #[test]
2052    /// Validate a `ProposalList` is built correctly
2053    fn test_proposal_list() {
2054        let proposal = ProposalBuilder::new()
2055            .with_record_id("egg1234".into())
2056            .with_timestamp(214)
2057            .with_issuing_agent("james".into())
2058            .with_receiving_agent("joe".into())
2059            .with_role(Role::Owner)
2060            .with_properties(vec!["wet".into(), "gets everywhere".into()])
2061            .with_status(Status::Open)
2062            .with_terms("a term".into())
2063            .build()
2064            .unwrap();
2065
2066        let proposal_list = ProposalListBuilder::new()
2067            .with_proposals(vec![proposal.clone()])
2068            .build()
2069            .unwrap();
2070
2071        assert!(proposal_list.proposals().iter().any(|x| *x == proposal));
2072    }
2073
2074    #[test]
2075    /// Validate a `ProposalList` is built and may be converted back to its builder
2076    fn test_proposal_list_into_builder() {
2077        let proposal = ProposalBuilder::new()
2078            .with_record_id("egg1234".into())
2079            .with_timestamp(214)
2080            .with_issuing_agent("james".into())
2081            .with_receiving_agent("joe".into())
2082            .with_role(Role::Owner)
2083            .with_properties(vec!["wet".into(), "gets everywhere".into()])
2084            .with_status(Status::Open)
2085            .with_terms("a term".into())
2086            .build()
2087            .unwrap();
2088
2089        let proposal_list = ProposalListBuilder::new()
2090            .with_proposals(vec![proposal.clone()])
2091            .build()
2092            .unwrap();
2093
2094        let builder = proposal_list.into_builder();
2095
2096        assert_eq!(builder.proposals, Some(vec![proposal]));
2097    }
2098
2099    #[test]
2100    /// Validate a `ProposalList` may be converted into bytes and back to its native representation
2101    /// successfully
2102    fn test_proposal_list_bytes() {
2103        let proposal = ProposalBuilder::new()
2104            .with_record_id("egg1234".into())
2105            .with_timestamp(214)
2106            .with_issuing_agent("james".into())
2107            .with_receiving_agent("joe".into())
2108            .with_role(Role::Owner)
2109            .with_properties(vec!["wet".into(), "gets everywhere".into()])
2110            .with_status(Status::Open)
2111            .with_terms("a term".into())
2112            .build()
2113            .unwrap();
2114
2115        let proposal_list = ProposalListBuilder::new()
2116            .with_proposals(vec![proposal.clone()])
2117            .build()
2118            .unwrap();
2119
2120        test_from_bytes(proposal_list, ProposalList::from_bytes);
2121    }
2122
2123    #[test]
2124    /// Validate a `Record` is built successfully
2125    fn test_record_builder() {
2126        let associated_agent = AssociatedAgentBuilder::new()
2127            .with_agent_id("agent1234".into())
2128            .with_timestamp(2132)
2129            .build()
2130            .unwrap();
2131
2132        let record = RecordBuilder::new()
2133            .with_record_id("egg1234".into())
2134            .with_schema("egg".into())
2135            .with_owners(vec![associated_agent.clone()])
2136            .with_custodians(vec![associated_agent.clone()])
2137            .with_field_final(false)
2138            .build()
2139            .unwrap();
2140
2141        assert_eq!(record.record_id(), "egg1234");
2142        assert_eq!(record.schema(), "egg");
2143        assert!(record.owners().iter().any(|x| *x == associated_agent));
2144        assert!(record.custodians().iter().any(|x| *x == associated_agent));
2145        assert_eq!(*record.field_final(), false);
2146    }
2147
2148    #[test]
2149    /// Validate a `Record` is built and may be converted back to a builder
2150    fn test_record_into_builder() {
2151        let associated_agent = AssociatedAgentBuilder::new()
2152            .with_agent_id("agent1234".into())
2153            .with_timestamp(2132)
2154            .build()
2155            .unwrap();
2156
2157        let record = RecordBuilder::new()
2158            .with_record_id("egg1234".into())
2159            .with_schema("egg".into())
2160            .with_owners(vec![associated_agent.clone()])
2161            .with_custodians(vec![associated_agent.clone()])
2162            .with_field_final(false)
2163            .build()
2164            .unwrap();
2165
2166        let builder = record.into_builder();
2167
2168        assert_eq!(builder.record_id, Some("egg1234".to_string()));
2169        assert_eq!(builder.schema, Some("egg".to_string()));
2170        assert_eq!(builder.owners, Some(vec![associated_agent.clone()]));
2171        assert_eq!(builder.custodians, Some(vec![associated_agent.clone()]));
2172        assert_eq!(builder.field_final, Some(false));
2173    }
2174
2175    #[test]
2176    /// Validate a `Record` may be converted into bytes and back to its native representation
2177    /// successfully
2178    fn test_record_bytes() {
2179        let associated_agent = AssociatedAgentBuilder::new()
2180            .with_agent_id("agent1234".into())
2181            .with_timestamp(2132)
2182            .build()
2183            .unwrap();
2184
2185        let record = RecordBuilder::new()
2186            .with_record_id("egg1234".into())
2187            .with_schema("egg".into())
2188            .with_owners(vec![associated_agent.clone()])
2189            .with_custodians(vec![associated_agent.clone()])
2190            .with_field_final(false)
2191            .build()
2192            .unwrap();
2193
2194        test_from_bytes(record, Record::from_bytes);
2195    }
2196
2197    #[test]
2198    /// Validate a `RecordList` is built correctly
2199    fn test_record_list() {
2200        let associated_agent = AssociatedAgentBuilder::new()
2201            .with_agent_id("agent1234".into())
2202            .with_timestamp(2132)
2203            .build()
2204            .unwrap();
2205
2206        let record = RecordBuilder::new()
2207            .with_record_id("egg1234".into())
2208            .with_schema("egg".into())
2209            .with_owners(vec![associated_agent.clone()])
2210            .with_custodians(vec![associated_agent.clone()])
2211            .with_field_final(false)
2212            .build()
2213            .unwrap();
2214
2215        let record_list = RecordListBuilder::new()
2216            .with_records(vec![record.clone()])
2217            .build()
2218            .unwrap();
2219
2220        assert!(record_list.records().iter().any(|x| *x == record));
2221    }
2222
2223    #[test]
2224    /// Validate a `RecordList` is built and may be converted back to its builder
2225    fn test_record_list_into_builder() {
2226        let associated_agent = AssociatedAgentBuilder::new()
2227            .with_agent_id("agent1234".into())
2228            .with_timestamp(2132)
2229            .build()
2230            .unwrap();
2231
2232        let record = RecordBuilder::new()
2233            .with_record_id("egg1234".into())
2234            .with_schema("egg".into())
2235            .with_owners(vec![associated_agent.clone()])
2236            .with_custodians(vec![associated_agent.clone()])
2237            .with_field_final(false)
2238            .build()
2239            .unwrap();
2240
2241        let record_list = RecordListBuilder::new()
2242            .with_records(vec![record.clone()])
2243            .build()
2244            .unwrap();
2245
2246        let builder = record_list.into_builder();
2247
2248        assert_eq!(builder.records, Some(vec![record]));
2249    }
2250
2251    #[test]
2252    /// Validate a `RecordList` may be converted into bytes and back to its native representation
2253    /// successfully
2254    fn test_record_list_bytes() {
2255        let associated_agent = AssociatedAgentBuilder::new()
2256            .with_agent_id("agent1234".into())
2257            .with_timestamp(2132)
2258            .build()
2259            .unwrap();
2260
2261        let record = RecordBuilder::new()
2262            .with_record_id("egg1234".into())
2263            .with_schema("egg".into())
2264            .with_owners(vec![associated_agent.clone()])
2265            .with_custodians(vec![associated_agent.clone()])
2266            .with_field_final(false)
2267            .build()
2268            .unwrap();
2269
2270        let record_list = RecordListBuilder::new()
2271            .with_records(vec![record.clone()])
2272            .build()
2273            .unwrap();
2274
2275        test_from_bytes(record_list, RecordList::from_bytes);
2276    }
2277
2278    #[test]
2279    /// Validate an `AssociatedAgent` is built and may be converted back to a builder
2280    fn test_associated_agent_into_builder() {
2281        let associated_agent = AssociatedAgentBuilder::new()
2282            .with_agent_id("agent1234".into())
2283            .with_timestamp(2132)
2284            .build()
2285            .unwrap();
2286
2287        let builder = associated_agent.into_builder();
2288
2289        assert_eq!(builder.agent_id, Some("agent1234".to_string()));
2290        assert_eq!(builder.timestamp, Some(2132));
2291    }
2292}