grid_sdk/protocol/schema/
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 Schema state
16
17use protobuf::Message;
18use protobuf::RepeatedField;
19
20use std::error::Error as StdError;
21
22use crate::protos;
23use crate::protos::{
24    FromBytes, FromNative, FromProto, IntoBytes, IntoNative, IntoProto, ProtoConversionError,
25};
26
27/// Native representation of a `DataType`
28///
29/// `DataType`s are used in a schema to define a data field's type
30#[derive(Debug, Clone, PartialEq)]
31pub enum DataType {
32    Bytes,
33    Boolean,
34    Number,
35    String,
36    Enum,
37    Struct,
38    LatLong,
39}
40
41impl FromProto<protos::schema_state::PropertyDefinition_DataType> for DataType {
42    fn from_proto(
43        data_type: protos::schema_state::PropertyDefinition_DataType,
44    ) -> Result<Self, ProtoConversionError> {
45        match data_type {
46            protos::schema_state::PropertyDefinition_DataType::BYTES => Ok(DataType::Bytes),
47            protos::schema_state::PropertyDefinition_DataType::BOOLEAN => Ok(DataType::Boolean),
48            protos::schema_state::PropertyDefinition_DataType::NUMBER => Ok(DataType::Number),
49            protos::schema_state::PropertyDefinition_DataType::STRING => Ok(DataType::String),
50            protos::schema_state::PropertyDefinition_DataType::ENUM => Ok(DataType::Enum),
51            protos::schema_state::PropertyDefinition_DataType::STRUCT => Ok(DataType::Struct),
52            protos::schema_state::PropertyDefinition_DataType::LAT_LONG => Ok(DataType::LatLong),
53            protos::schema_state::PropertyDefinition_DataType::UNSET_DATA_TYPE => {
54                Err(ProtoConversionError::InvalidTypeError(
55                    "Cannot convert PropertyDefinition_DataType with type unset.".to_string(),
56                ))
57            }
58        }
59    }
60}
61
62impl FromNative<DataType> for protos::schema_state::PropertyDefinition_DataType {
63    fn from_native(data_type: DataType) -> Result<Self, ProtoConversionError> {
64        match data_type {
65            DataType::Bytes => Ok(protos::schema_state::PropertyDefinition_DataType::BYTES),
66            DataType::Boolean => Ok(protos::schema_state::PropertyDefinition_DataType::BOOLEAN),
67            DataType::Number => Ok(protos::schema_state::PropertyDefinition_DataType::NUMBER),
68            DataType::String => Ok(protos::schema_state::PropertyDefinition_DataType::STRING),
69            DataType::Enum => Ok(protos::schema_state::PropertyDefinition_DataType::ENUM),
70            DataType::Struct => Ok(protos::schema_state::PropertyDefinition_DataType::STRUCT),
71            DataType::LatLong => Ok(protos::schema_state::PropertyDefinition_DataType::LAT_LONG),
72        }
73    }
74}
75
76impl IntoProto<protos::schema_state::PropertyDefinition_DataType> for DataType {}
77impl IntoNative<DataType> for protos::schema_state::PropertyDefinition_DataType {}
78
79/// Native representation of the `LatLong` schema data type
80///
81/// A `LatLong` object is comprised of a latitude, longitude pair represented as signed integers
82#[derive(Debug, Clone, PartialEq)]
83pub struct LatLong {
84    latitude: i64,
85    longitude: i64,
86}
87
88impl LatLong {
89    pub fn latitude(&self) -> &i64 {
90        &self.latitude
91    }
92
93    pub fn longitude(&self) -> &i64 {
94        &self.longitude
95    }
96}
97
98impl FromProto<protos::schema_state::LatLong> for LatLong {
99    fn from_proto(lat_long: protos::schema_state::LatLong) -> Result<Self, ProtoConversionError> {
100        Ok(LatLong {
101            latitude: lat_long.get_latitude(),
102            longitude: lat_long.get_longitude(),
103        })
104    }
105}
106
107impl FromNative<LatLong> for protos::schema_state::LatLong {
108    fn from_native(lat_long: LatLong) -> Result<Self, ProtoConversionError> {
109        let mut proto_lat_long = protos::schema_state::LatLong::new();
110        proto_lat_long.set_latitude(*lat_long.latitude());
111        proto_lat_long.set_longitude(*lat_long.longitude());
112        Ok(proto_lat_long)
113    }
114}
115
116impl IntoProto<protos::schema_state::LatLong> for LatLong {}
117impl IntoNative<LatLong> for protos::schema_state::LatLong {}
118
119/// Returned if any required fields in a `LatLong` struct are invalid when being converted from the
120/// corresponding builder
121#[derive(Debug)]
122pub enum LatLongBuildError {
123    InvalidLatitude(i64),
124    InvalidLongitude(i64),
125}
126
127impl StdError for LatLongBuildError {}
128
129impl std::fmt::Display for LatLongBuildError {
130    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
131        match *self {
132            LatLongBuildError::InvalidLatitude(ref s) => write!(
133                f,
134                "Invalid latitude - must in the range of \
135                 -90000000 < lat < 90000000, but received: {}",
136                s
137            ),
138            LatLongBuildError::InvalidLongitude(ref s) => write!(
139                f,
140                "Invalid longitude - must in the range of \
141                 -180000000 < lat < 180000000, but received: {}",
142                s
143            ),
144        }
145    }
146}
147
148/// Builder used to create a `LatLong`
149#[derive(Default, Clone, PartialEq)]
150pub struct LatLongBuilder {
151    pub latitude: i64,
152    pub longitude: i64,
153}
154
155impl LatLongBuilder {
156    pub fn new() -> Self {
157        LatLongBuilder::default()
158    }
159
160    pub fn with_lat_long(mut self, latitude: i64, longitude: i64) -> LatLongBuilder {
161        self.latitude = latitude;
162        self.longitude = longitude;
163        self
164    }
165
166    pub fn build(self) -> Result<LatLong, LatLongBuildError> {
167        let latitude = self.latitude;
168        let longitude = self.longitude;
169
170        if latitude < -90_000_000 || latitude > 90_000_000 {
171            Err(LatLongBuildError::InvalidLatitude(latitude))
172        } else if longitude < -180_000_000 || longitude > 180_000_000 {
173            Err(LatLongBuildError::InvalidLongitude(longitude))
174        } else {
175            Ok(LatLong {
176                latitude,
177                longitude,
178            })
179        }
180    }
181}
182
183/// Native implementation of `PropertyDefinition`
184///
185/// This defines a field in a schema
186#[derive(Debug, Clone, PartialEq)]
187pub struct PropertyDefinition {
188    name: String,
189    data_type: DataType,
190    required: bool,
191    description: String,
192    number_exponent: i32,
193    enum_options: Vec<String>,
194    struct_properties: Vec<PropertyDefinition>,
195}
196
197impl PropertyDefinition {
198    pub fn name(&self) -> &str {
199        &self.name
200    }
201
202    pub fn data_type(&self) -> &DataType {
203        &self.data_type
204    }
205
206    pub fn required(&self) -> &bool {
207        &self.required
208    }
209
210    pub fn description(&self) -> &str {
211        &self.description
212    }
213
214    pub fn number_exponent(&self) -> &i32 {
215        &self.number_exponent
216    }
217
218    pub fn enum_options(&self) -> &[String] {
219        &self.enum_options
220    }
221
222    pub fn struct_properties(&self) -> &[PropertyDefinition] {
223        &self.struct_properties
224    }
225}
226
227impl FromProto<protos::schema_state::PropertyDefinition> for PropertyDefinition {
228    fn from_proto(
229        property_definition: protos::schema_state::PropertyDefinition,
230    ) -> Result<Self, ProtoConversionError> {
231        Ok(PropertyDefinition {
232            name: property_definition.get_name().to_string(),
233            data_type: DataType::from_proto(property_definition.get_data_type())?,
234            required: property_definition.get_required(),
235            description: property_definition.get_description().to_string(),
236            number_exponent: property_definition.get_number_exponent(),
237            enum_options: property_definition.get_enum_options().to_vec(),
238            struct_properties: property_definition
239                .get_struct_properties()
240                .iter()
241                .cloned()
242                .map(PropertyDefinition::from_proto)
243                .collect::<Result<Vec<PropertyDefinition>, ProtoConversionError>>()?,
244        })
245    }
246}
247
248impl FromNative<PropertyDefinition> for protos::schema_state::PropertyDefinition {
249    fn from_native(property_definition: PropertyDefinition) -> Result<Self, ProtoConversionError> {
250        let mut proto_property_definition = protos::schema_state::PropertyDefinition::new();
251        proto_property_definition.set_name(property_definition.name().to_string());
252        proto_property_definition
253            .set_data_type(property_definition.data_type().clone().into_proto()?);
254        proto_property_definition.set_required(*property_definition.required());
255        proto_property_definition.set_description(property_definition.description().to_string());
256        proto_property_definition.set_number_exponent(*property_definition.number_exponent());
257        proto_property_definition.set_enum_options(RepeatedField::from_vec(
258            property_definition.enum_options().to_vec(),
259        ));
260        proto_property_definition.set_struct_properties(
261            RepeatedField::from_vec(
262            property_definition.struct_properties().iter().cloned()
263            .map(PropertyDefinition::into_proto)
264            .collect::<Result<Vec<protos::schema_state::PropertyDefinition>, ProtoConversionError>>()?,));
265        Ok(proto_property_definition)
266    }
267}
268
269impl FromBytes<PropertyDefinition> for PropertyDefinition {
270    fn from_bytes(bytes: &[u8]) -> Result<PropertyDefinition, ProtoConversionError> {
271        let proto: protos::schema_state::PropertyDefinition = Message::parse_from_bytes(bytes)
272            .map_err(|_| {
273                ProtoConversionError::SerializationError(
274                    "Unable to get PropertyDefinition from bytes".to_string(),
275                )
276            })?;
277        proto.into_native()
278    }
279}
280
281impl IntoBytes for PropertyDefinition {
282    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
283        let proto = self.into_proto()?;
284        let bytes = proto.write_to_bytes().map_err(|_| {
285            ProtoConversionError::SerializationError(
286                "Unable to get bytes from PropertyDefinition".to_string(),
287            )
288        })?;
289        Ok(bytes)
290    }
291}
292
293impl IntoProto<protos::schema_state::PropertyDefinition> for PropertyDefinition {}
294impl IntoNative<PropertyDefinition> for protos::schema_state::PropertyDefinition {}
295
296/// Returned if any required fields in a `PropertyDefinition` are not present when being
297/// converted from the corresponding builder
298#[derive(Debug)]
299pub enum PropertyDefinitionBuildError {
300    MissingField(String),
301    EmptyVec(String),
302}
303
304impl StdError for PropertyDefinitionBuildError {
305    fn description(&self) -> &str {
306        match *self {
307            PropertyDefinitionBuildError::MissingField(ref msg) => msg,
308            PropertyDefinitionBuildError::EmptyVec(ref msg) => msg,
309        }
310    }
311
312    fn cause(&self) -> Option<&dyn StdError> {
313        match *self {
314            PropertyDefinitionBuildError::MissingField(_) => None,
315            PropertyDefinitionBuildError::EmptyVec(_) => None,
316        }
317    }
318}
319
320impl std::fmt::Display for PropertyDefinitionBuildError {
321    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
322        match *self {
323            PropertyDefinitionBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
324            PropertyDefinitionBuildError::EmptyVec(ref s) => write!(f, "EmptyVec: {}", s),
325        }
326    }
327}
328
329/// Builder used to create a `PropertyDefinition`
330#[derive(Default, Clone, PartialEq)]
331pub struct PropertyDefinitionBuilder {
332    pub name: Option<String>,
333    pub data_type: Option<DataType>,
334    pub required: Option<bool>,
335    pub description: Option<String>,
336    pub number_exponent: Option<i32>,
337    pub enum_options: Vec<String>,
338    pub struct_properties: Vec<PropertyDefinition>,
339}
340
341impl PropertyDefinitionBuilder {
342    pub fn new() -> Self {
343        PropertyDefinitionBuilder::default()
344    }
345
346    pub fn with_name(mut self, name: String) -> PropertyDefinitionBuilder {
347        self.name = Some(name);
348        self
349    }
350
351    pub fn with_data_type(mut self, data_type: DataType) -> PropertyDefinitionBuilder {
352        self.data_type = Some(data_type);
353        self
354    }
355
356    pub fn with_required(mut self, required: bool) -> PropertyDefinitionBuilder {
357        self.required = Some(required);
358        self
359    }
360
361    pub fn with_description(mut self, description: String) -> PropertyDefinitionBuilder {
362        self.description = Some(description);
363        self
364    }
365
366    pub fn with_number_exponent(mut self, number_exponent: i32) -> PropertyDefinitionBuilder {
367        self.number_exponent = Some(number_exponent);
368        self
369    }
370
371    pub fn with_enum_options(mut self, enum_options: Vec<String>) -> PropertyDefinitionBuilder {
372        self.enum_options = enum_options;
373        self
374    }
375
376    pub fn with_struct_properties(
377        mut self,
378        struct_properties: Vec<PropertyDefinition>,
379    ) -> PropertyDefinitionBuilder {
380        self.struct_properties = struct_properties;
381        self
382    }
383
384    pub fn build(self) -> Result<PropertyDefinition, PropertyDefinitionBuildError> {
385        let name = self.name.ok_or_else(|| {
386            PropertyDefinitionBuildError::MissingField("'name' field is required".to_string())
387        })?;
388
389        let data_type = self.data_type.ok_or_else(|| {
390            PropertyDefinitionBuildError::MissingField("'data_type' field is required".to_string())
391        })?;
392
393        let required = self.required.unwrap_or(false);
394        let description = self.description.unwrap_or_default();
395
396        let number_exponent = {
397            if data_type == DataType::Number {
398                self.number_exponent.ok_or_else(|| {
399                    PropertyDefinitionBuildError::MissingField(
400                        "'number_exponent' field is required".to_string(),
401                    )
402                })?
403            } else {
404                0
405            }
406        };
407
408        let enum_options = {
409            if data_type == DataType::Enum {
410                if !self.enum_options.is_empty() {
411                    self.enum_options
412                } else {
413                    return Err(PropertyDefinitionBuildError::EmptyVec(
414                        "'enum_options' cannot be empty".to_string(),
415                    ));
416                }
417            } else {
418                self.enum_options
419            }
420        };
421
422        let struct_properties = {
423            if data_type == DataType::Struct {
424                if !self.struct_properties.is_empty() {
425                    self.struct_properties
426                } else {
427                    return Err(PropertyDefinitionBuildError::EmptyVec(
428                        "'struct_properties' cannot be empty".to_string(),
429                    ));
430                }
431            } else {
432                self.struct_properties
433            }
434        };
435
436        Ok(PropertyDefinition {
437            name,
438            data_type,
439            required,
440            description,
441            number_exponent,
442            enum_options,
443            struct_properties,
444        })
445    }
446}
447
448/// Native representation of a `Schema`
449///
450/// A schema provides the definition for a property across smart contracts
451#[derive(Debug, Clone, PartialEq)]
452pub struct Schema {
453    name: String,
454    description: String,
455    owner: String,
456    properties: Vec<PropertyDefinition>,
457}
458
459impl Schema {
460    pub fn name(&self) -> &str {
461        &self.name
462    }
463
464    pub fn description(&self) -> &str {
465        &self.description
466    }
467
468    pub fn owner(&self) -> &str {
469        &self.owner
470    }
471
472    pub fn properties(&self) -> &[PropertyDefinition] {
473        &self.properties
474    }
475}
476
477impl FromProto<protos::schema_state::Schema> for Schema {
478    fn from_proto(schema: protos::schema_state::Schema) -> Result<Self, ProtoConversionError> {
479        Ok(Schema {
480            name: schema.get_name().to_string(),
481            description: schema.get_description().to_string(),
482            owner: schema.get_owner().to_string(),
483            properties: schema
484                .get_properties()
485                .iter()
486                .cloned()
487                .map(PropertyDefinition::from_proto)
488                .collect::<Result<Vec<PropertyDefinition>, ProtoConversionError>>()?,
489        })
490    }
491}
492
493impl FromNative<Schema> for protos::schema_state::Schema {
494    fn from_native(schema: Schema) -> Result<Self, ProtoConversionError> {
495        let mut proto_schema = protos::schema_state::Schema::new();
496        proto_schema.set_name(schema.name().to_string());
497        proto_schema.set_description(schema.description().to_string());
498        proto_schema.set_owner(schema.owner().to_string());
499        proto_schema.set_properties(RepeatedField::from_vec(
500            schema
501                .properties()
502                .iter()
503                .cloned()
504                .map(PropertyDefinition::into_proto)
505                .collect::<Result<Vec<protos::schema_state::PropertyDefinition>, ProtoConversionError>>()?,
506        ));
507        Ok(proto_schema)
508    }
509}
510
511impl FromBytes<Schema> for Schema {
512    fn from_bytes(bytes: &[u8]) -> Result<Schema, ProtoConversionError> {
513        let proto: protos::schema_state::Schema =
514            Message::parse_from_bytes(bytes).map_err(|_| {
515                ProtoConversionError::SerializationError(
516                    "Unable to get Schema from bytes".to_string(),
517                )
518            })?;
519        proto.into_native()
520    }
521}
522
523impl IntoBytes for Schema {
524    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
525        let proto = self.into_proto()?;
526        let bytes = proto.write_to_bytes().map_err(|_| {
527            ProtoConversionError::SerializationError("Unable to get bytes from Schema".to_string())
528        })?;
529        Ok(bytes)
530    }
531}
532
533impl IntoProto<protos::schema_state::Schema> for Schema {}
534impl IntoNative<Schema> for protos::schema_state::Schema {}
535
536/// Returned if any required fields in a `Schema` are not present when being
537/// converted from the corresponding builder
538#[derive(Debug)]
539pub enum SchemaBuildError {
540    MissingField(String),
541}
542
543impl StdError for SchemaBuildError {
544    fn description(&self) -> &str {
545        match *self {
546            SchemaBuildError::MissingField(ref msg) => msg,
547        }
548    }
549
550    fn cause(&self) -> Option<&dyn StdError> {
551        match *self {
552            SchemaBuildError::MissingField(_) => None,
553        }
554    }
555}
556
557impl std::fmt::Display for SchemaBuildError {
558    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
559        match *self {
560            SchemaBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
561        }
562    }
563}
564
565/// Builder used to create a `Schema`
566#[derive(Default, Clone)]
567pub struct SchemaBuilder {
568    pub name: Option<String>,
569    pub description: Option<String>,
570    pub owner: Option<String>,
571    pub properties: Vec<PropertyDefinition>,
572}
573
574impl SchemaBuilder {
575    pub fn new() -> Self {
576        SchemaBuilder::default()
577    }
578
579    pub fn with_name(mut self, name: String) -> SchemaBuilder {
580        self.name = Some(name);
581        self
582    }
583
584    pub fn with_description(mut self, description: String) -> SchemaBuilder {
585        self.description = Some(description);
586        self
587    }
588
589    pub fn with_owner(mut self, owner: String) -> SchemaBuilder {
590        self.owner = Some(owner);
591        self
592    }
593
594    pub fn with_properties(mut self, properties: Vec<PropertyDefinition>) -> SchemaBuilder {
595        self.properties = properties;
596        self
597    }
598
599    pub fn build(self) -> Result<Schema, SchemaBuildError> {
600        let name = self.name.ok_or_else(|| {
601            SchemaBuildError::MissingField("'name' field is required".to_string())
602        })?;
603
604        let owner = self.owner.ok_or_else(|| {
605            SchemaBuildError::MissingField("'owner' field is required".to_string())
606        })?;
607
608        let description = self.description.unwrap_or_else(|| "".to_string());
609        let properties = {
610            if !self.properties.is_empty() {
611                self.properties
612            } else {
613                return Err(SchemaBuildError::MissingField(
614                    "'properties' field is required".to_string(),
615                ));
616            }
617        };
618
619        Ok(Schema {
620            name,
621            description,
622            owner,
623            properties,
624        })
625    }
626}
627
628/// Native representation of a list of `Schema`s
629#[derive(Debug, Clone, PartialEq)]
630pub struct SchemaList {
631    schemas: Vec<Schema>,
632}
633
634impl SchemaList {
635    pub fn schemas(&self) -> &[Schema] {
636        &self.schemas
637    }
638}
639
640impl FromProto<protos::schema_state::SchemaList> for SchemaList {
641    fn from_proto(
642        schema_list: protos::schema_state::SchemaList,
643    ) -> Result<Self, ProtoConversionError> {
644        Ok(SchemaList {
645            schemas: schema_list
646                .get_schemas()
647                .iter()
648                .cloned()
649                .map(Schema::from_proto)
650                .collect::<Result<Vec<Schema>, ProtoConversionError>>()?,
651        })
652    }
653}
654
655impl FromNative<SchemaList> for protos::schema_state::SchemaList {
656    fn from_native(schema_list: SchemaList) -> Result<Self, ProtoConversionError> {
657        let mut schema_list_proto = protos::schema_state::SchemaList::new();
658
659        schema_list_proto.set_schemas(RepeatedField::from_vec(
660            schema_list
661                .schemas()
662                .iter()
663                .cloned()
664                .map(Schema::into_proto)
665                .collect::<Result<Vec<protos::schema_state::Schema>, ProtoConversionError>>()?,
666        ));
667
668        Ok(schema_list_proto)
669    }
670}
671
672impl FromBytes<SchemaList> for SchemaList {
673    fn from_bytes(bytes: &[u8]) -> Result<SchemaList, ProtoConversionError> {
674        let proto: protos::schema_state::SchemaList =
675            Message::parse_from_bytes(bytes).map_err(|_| {
676                ProtoConversionError::SerializationError(
677                    "Unable to get SchemaList from bytes".to_string(),
678                )
679            })?;
680        proto.into_native()
681    }
682}
683
684impl IntoBytes for SchemaList {
685    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
686        let proto = self.into_proto()?;
687        let bytes = proto.write_to_bytes().map_err(|_| {
688            ProtoConversionError::SerializationError(
689                "Unable to get bytes from SchemaList".to_string(),
690            )
691        })?;
692        Ok(bytes)
693    }
694}
695
696impl IntoProto<protos::schema_state::SchemaList> for SchemaList {}
697impl IntoNative<SchemaList> for protos::schema_state::SchemaList {}
698
699/// Returned if any required fields in a `SchemaList` are not present when being
700/// converted from the corresponding builder
701#[derive(Debug)]
702pub enum SchemaListBuildError {
703    MissingField(String),
704}
705
706impl StdError for SchemaListBuildError {
707    fn description(&self) -> &str {
708        match *self {
709            SchemaListBuildError::MissingField(ref msg) => msg,
710        }
711    }
712
713    fn cause(&self) -> Option<&dyn StdError> {
714        match *self {
715            SchemaListBuildError::MissingField(_) => None,
716        }
717    }
718}
719
720impl std::fmt::Display for SchemaListBuildError {
721    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
722        match *self {
723            SchemaListBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
724        }
725    }
726}
727
728/// Builder used to create a list of `Schema`s
729#[derive(Default, Clone)]
730pub struct SchemaListBuilder {
731    pub schemas: Vec<Schema>,
732}
733
734impl SchemaListBuilder {
735    pub fn new() -> Self {
736        SchemaListBuilder::default()
737    }
738
739    pub fn with_schemas(mut self, schemas: Vec<Schema>) -> SchemaListBuilder {
740        self.schemas = schemas;
741        self
742    }
743
744    pub fn build(self) -> Result<SchemaList, SchemaListBuildError> {
745        let schemas = {
746            if self.schemas.is_empty() {
747                return Err(SchemaListBuildError::MissingField(
748                    "'schemas' cannot be empty".to_string(),
749                ));
750            } else {
751                self.schemas
752            }
753        };
754
755        Ok(SchemaList { schemas })
756    }
757}
758
759/// Native implementation of `PropertyValue`
760///
761/// This provides the value as defined by the corresponding `PropertyDefinition`
762#[derive(Debug, Clone, PartialEq)]
763pub struct PropertyValue {
764    name: String,
765    data_type: DataType,
766    bytes_value: Vec<u8>,
767    boolean_value: bool,
768    number_value: i64,
769    string_value: String,
770    enum_value: u32,
771    struct_values: Vec<PropertyValue>,
772    lat_long_value: LatLong,
773}
774
775impl PropertyValue {
776    pub fn name(&self) -> &str {
777        &self.name
778    }
779
780    pub fn data_type(&self) -> &DataType {
781        &self.data_type
782    }
783
784    pub fn bytes_value(&self) -> &[u8] {
785        &self.bytes_value
786    }
787
788    pub fn boolean_value(&self) -> &bool {
789        &self.boolean_value
790    }
791
792    pub fn number_value(&self) -> &i64 {
793        &self.number_value
794    }
795
796    pub fn string_value(&self) -> &str {
797        &self.string_value
798    }
799
800    pub fn enum_value(&self) -> &u32 {
801        &self.enum_value
802    }
803
804    pub fn struct_values(&self) -> &[PropertyValue] {
805        &self.struct_values
806    }
807
808    pub fn lat_long_value(&self) -> &LatLong {
809        &self.lat_long_value
810    }
811}
812
813impl FromProto<protos::schema_state::PropertyValue> for PropertyValue {
814    fn from_proto(
815        property_value: protos::schema_state::PropertyValue,
816    ) -> Result<Self, ProtoConversionError> {
817        Ok(PropertyValue {
818            name: property_value.get_name().to_string(),
819            data_type: DataType::from_proto(property_value.get_data_type())?,
820            bytes_value: property_value.get_bytes_value().to_vec(),
821            boolean_value: property_value.get_boolean_value(),
822            number_value: property_value.get_number_value(),
823            string_value: property_value.get_string_value().to_string(),
824            enum_value: property_value.get_enum_value(),
825            struct_values: property_value
826                .get_struct_values()
827                .iter()
828                .cloned()
829                .map(PropertyValue::from_proto)
830                .collect::<Result<Vec<PropertyValue>, ProtoConversionError>>()?,
831            lat_long_value: property_value.get_lat_long_value().clone().into_native()?,
832        })
833    }
834}
835
836impl FromNative<PropertyValue> for protos::schema_state::PropertyValue {
837    fn from_native(property_value: PropertyValue) -> Result<Self, ProtoConversionError> {
838        let mut proto_property_value = protos::schema_state::PropertyValue::new();
839        proto_property_value.set_name(property_value.name().to_string());
840        proto_property_value.set_data_type(property_value.data_type().clone().into_proto()?);
841        proto_property_value.set_bytes_value(property_value.bytes_value().to_vec());
842        proto_property_value.set_boolean_value(*property_value.boolean_value());
843        proto_property_value.set_number_value(*property_value.number_value());
844        proto_property_value.set_string_value(property_value.string_value().to_string());
845        proto_property_value.set_enum_value(*property_value.enum_value());
846        proto_property_value.set_struct_values(RepeatedField::from_vec(
847            property_value
848                .struct_values()
849                .iter()
850                .cloned()
851                .map(PropertyValue::into_proto)
852                .collect::<Result<Vec<protos::schema_state::PropertyValue>, ProtoConversionError>>(
853                )?,
854        ));
855        proto_property_value
856            .set_lat_long_value(property_value.lat_long_value().clone().into_proto()?);
857        Ok(proto_property_value)
858    }
859}
860
861impl FromBytes<PropertyValue> for PropertyValue {
862    fn from_bytes(bytes: &[u8]) -> Result<PropertyValue, ProtoConversionError> {
863        let proto: protos::schema_state::PropertyValue =
864            Message::parse_from_bytes(bytes).map_err(|_| {
865                ProtoConversionError::SerializationError(
866                    "Unable to get PropertyValue from bytes".to_string(),
867                )
868            })?;
869        proto.into_native()
870    }
871}
872
873impl IntoBytes for PropertyValue {
874    fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
875        let proto = self.into_proto()?;
876        let bytes = proto.write_to_bytes().map_err(|_| {
877            ProtoConversionError::SerializationError(
878                "Unable to get bytes from PropertyValue".to_string(),
879            )
880        })?;
881        Ok(bytes)
882    }
883}
884
885impl IntoProto<protos::schema_state::PropertyValue> for PropertyValue {}
886impl IntoNative<PropertyValue> for protos::schema_state::PropertyValue {}
887
888/// Returned if any required fields in a `PropertyValue` are not present when being
889/// converted from the corresponding builder
890#[derive(Debug)]
891pub enum PropertyValueBuildError {
892    MissingField(String),
893}
894
895impl StdError for PropertyValueBuildError {
896    fn description(&self) -> &str {
897        match *self {
898            PropertyValueBuildError::MissingField(ref msg) => msg,
899        }
900    }
901
902    fn cause(&self) -> Option<&dyn StdError> {
903        match *self {
904            PropertyValueBuildError::MissingField(_) => None,
905        }
906    }
907}
908
909impl std::fmt::Display for PropertyValueBuildError {
910    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
911        match *self {
912            PropertyValueBuildError::MissingField(ref s) => write!(f, "MissingField: {}", s),
913        }
914    }
915}
916
917/// Builder used to create a `PropertyValue`
918#[derive(Default, Clone)]
919pub struct PropertyValueBuilder {
920    pub name: Option<String>,
921    pub data_type: Option<DataType>,
922    pub bytes_value: Option<Vec<u8>>,
923    pub boolean_value: Option<bool>,
924    pub number_value: Option<i64>,
925    pub string_value: Option<String>,
926    pub enum_value: Option<u32>,
927    pub struct_values: Vec<PropertyValue>,
928    pub lat_long_value: Option<LatLong>,
929}
930
931impl PropertyValueBuilder {
932    pub fn new() -> Self {
933        PropertyValueBuilder::default()
934    }
935
936    pub fn with_name(mut self, name: String) -> PropertyValueBuilder {
937        self.name = Some(name);
938        self
939    }
940
941    pub fn with_data_type(mut self, data_type: DataType) -> PropertyValueBuilder {
942        self.data_type = Some(data_type);
943        self
944    }
945
946    pub fn with_bytes_value(mut self, bytes: Vec<u8>) -> PropertyValueBuilder {
947        self.bytes_value = Some(bytes);
948        self
949    }
950
951    pub fn with_boolean_value(mut self, boolean: bool) -> PropertyValueBuilder {
952        self.boolean_value = Some(boolean);
953        self
954    }
955
956    pub fn with_number_value(mut self, number: i64) -> PropertyValueBuilder {
957        self.number_value = Some(number);
958        self
959    }
960
961    pub fn with_enum_value(mut self, enum_value: u32) -> PropertyValueBuilder {
962        self.enum_value = Some(enum_value);
963        self
964    }
965
966    pub fn with_string_value(mut self, string: String) -> PropertyValueBuilder {
967        self.string_value = Some(string);
968        self
969    }
970
971    pub fn with_struct_values(mut self, struct_values: Vec<PropertyValue>) -> PropertyValueBuilder {
972        self.struct_values = struct_values;
973        self
974    }
975
976    pub fn with_lat_long_value(mut self, lat_long_value: LatLong) -> PropertyValueBuilder {
977        self.lat_long_value = Some(lat_long_value);
978        self
979    }
980
981    pub fn build(self) -> Result<PropertyValue, PropertyValueBuildError> {
982        let name = self.name.ok_or_else(|| {
983            PropertyValueBuildError::MissingField("'name' field is required".to_string())
984        })?;
985
986        let data_type = self.data_type.ok_or_else(|| {
987            PropertyValueBuildError::MissingField("'data_type' field is required".to_string())
988        })?;
989
990        let bytes_value = {
991            if data_type == DataType::Bytes {
992                self.bytes_value.ok_or_else(|| {
993                    PropertyValueBuildError::MissingField(
994                        "'bytes_value' field is required".to_string(),
995                    )
996                })?
997            } else {
998                vec![]
999            }
1000        };
1001
1002        let boolean_value = {
1003            if data_type == DataType::Boolean {
1004                self.boolean_value.ok_or_else(|| {
1005                    PropertyValueBuildError::MissingField(
1006                        "'boolean_value' field is required".to_string(),
1007                    )
1008                })?
1009            } else {
1010                false
1011            }
1012        };
1013
1014        let number_value = {
1015            if data_type == DataType::Number {
1016                self.number_value.ok_or_else(|| {
1017                    PropertyValueBuildError::MissingField(
1018                        "'number_value' field is required".to_string(),
1019                    )
1020                })?
1021            } else {
1022                0
1023            }
1024        };
1025
1026        let string_value = {
1027            if data_type == DataType::String {
1028                self.string_value.ok_or_else(|| {
1029                    PropertyValueBuildError::MissingField(
1030                        "'string_value' field is required".to_string(),
1031                    )
1032                })?
1033            } else {
1034                "".to_string()
1035            }
1036        };
1037
1038        let enum_value = {
1039            if data_type == DataType::Enum {
1040                self.enum_value.ok_or_else(|| {
1041                    PropertyValueBuildError::MissingField(
1042                        "'enum_value' field is required".to_string(),
1043                    )
1044                })?
1045            } else {
1046                0
1047            }
1048        };
1049
1050        let struct_values = {
1051            if data_type == DataType::Struct {
1052                if !self.struct_values.is_empty() {
1053                    self.struct_values
1054                } else {
1055                    return Err(PropertyValueBuildError::MissingField(
1056                        "'struct_values' cannot be empty".to_string(),
1057                    ));
1058                }
1059            } else {
1060                self.struct_values
1061            }
1062        };
1063
1064        let lat_long_value = {
1065            if data_type == DataType::LatLong {
1066                self.lat_long_value.ok_or_else(|| {
1067                    PropertyValueBuildError::MissingField(
1068                        "'lat_long_value' field is required".to_string(),
1069                    )
1070                })?
1071            } else {
1072                LatLong {
1073                    latitude: 0,
1074                    longitude: 0,
1075                }
1076            }
1077        };
1078
1079        Ok(PropertyValue {
1080            name,
1081            data_type,
1082            bytes_value,
1083            boolean_value,
1084            number_value,
1085            string_value,
1086            enum_value,
1087            struct_values,
1088            lat_long_value,
1089        })
1090    }
1091}
1092
1093#[cfg(test)]
1094mod tests {
1095    use super::*;
1096
1097    #[test]
1098    /// Validate that a `PropertyDefinition` with a `String` data type is built correctly
1099    fn check_property_definition_builder_string() {
1100        let builder = PropertyDefinitionBuilder::new();
1101        let property_definition = builder
1102            .with_name("TEST".to_string())
1103            .with_data_type(DataType::String)
1104            .with_description("Optional".to_string())
1105            .build()
1106            .unwrap();
1107
1108        assert_eq!(property_definition.name, "TEST");
1109        assert_eq!(property_definition.data_type, DataType::String);
1110        assert_eq!(property_definition.description, "Optional");
1111    }
1112
1113    #[test]
1114    /// Validate that a `PropertyDefinition` with an `Enum` data type is built correctly
1115    fn check_property_definition_builder_enum() {
1116        let builder = PropertyDefinitionBuilder::new();
1117        let property_definition = builder
1118            .with_name("TEST".to_string())
1119            .with_data_type(DataType::Enum)
1120            .with_description("Optional".to_string())
1121            .with_enum_options(vec![
1122                "One".to_string(),
1123                "Two".to_string(),
1124                "Three".to_string(),
1125            ])
1126            .build()
1127            .unwrap();
1128
1129        assert_eq!(property_definition.name, "TEST");
1130        assert_eq!(property_definition.data_type, DataType::Enum);
1131        assert_eq!(property_definition.description, "Optional");
1132        assert_eq!(
1133            property_definition.enum_options,
1134            vec!["One".to_string(), "Two".to_string(), "Three".to_string()]
1135        );
1136    }
1137
1138    #[test]
1139    /// Validate that a `PropertyDefinition` with a `Struct` data type is built correctly
1140    fn check_property_definition_builder_struct() {
1141        let builder = PropertyDefinitionBuilder::new();
1142        let struct_string = builder
1143            .with_name("TEST".to_string())
1144            .with_data_type(DataType::Enum)
1145            .with_description("Optional".to_string())
1146            .with_enum_options(vec![
1147                "One".to_string(),
1148                "Two".to_string(),
1149                "Three".to_string(),
1150            ])
1151            .build()
1152            .unwrap();
1153
1154        let builder = PropertyDefinitionBuilder::new();
1155        let property_definition = builder
1156            .with_name("TEST_STRUCT".to_string())
1157            .with_data_type(DataType::Struct)
1158            .with_description("Optional".to_string())
1159            .with_struct_properties(vec![struct_string.clone()])
1160            .build()
1161            .unwrap();
1162
1163        assert_eq!(property_definition.name, "TEST_STRUCT");
1164        assert_eq!(property_definition.data_type, DataType::Struct);
1165        assert_eq!(property_definition.description, "Optional");
1166        assert_eq!(property_definition.struct_properties, vec![struct_string]);
1167    }
1168
1169    #[test]
1170    /// Validate that a `PropertyDefinition` with a `String` data type may be converted to bytes
1171    /// and back to its native representation successfully
1172    fn check_property_definition_bytes() {
1173        let builder = PropertyDefinitionBuilder::new();
1174        let original = builder
1175            .with_name("TEST".to_string())
1176            .with_data_type(DataType::String)
1177            .with_description("Optional".to_string())
1178            .build()
1179            .unwrap();
1180
1181        let bytes = original.clone().into_bytes().unwrap();
1182
1183        let property_definition = PropertyDefinition::from_bytes(&bytes).unwrap();
1184        assert_eq!(property_definition, original);
1185    }
1186
1187    #[test]
1188    /// Validate that a `Schema`, containing a `PropertyDefinition` with an `Enum` data type is
1189    /// built correctly
1190    fn check_schema_builder() {
1191        let builder = PropertyDefinitionBuilder::new();
1192        let property_definition = builder
1193            .with_name("TEST".to_string())
1194            .with_data_type(DataType::Enum)
1195            .with_description("Optional".to_string())
1196            .with_enum_options(vec![
1197                "One".to_string(),
1198                "Two".to_string(),
1199                "Three".to_string(),
1200            ])
1201            .build()
1202            .unwrap();
1203
1204        let builder = SchemaBuilder::new();
1205        let schema = builder
1206            .with_name("TestSchema".to_string())
1207            .with_description("Test Schema".to_string())
1208            .with_owner("owner".to_string())
1209            .with_properties(vec![property_definition.clone()])
1210            .build()
1211            .unwrap();
1212
1213        assert_eq!(schema.name, "TestSchema");
1214        assert_eq!(schema.description, "Test Schema");
1215        assert_eq!(schema.owner, "owner");
1216        assert_eq!(schema.properties, vec![property_definition]);
1217    }
1218
1219    #[test]
1220    /// Validate that a `Schema`, containing a `PropertyDefinition` with an `Enum` data type may
1221    /// be converted to bytes and back to its native representation successfully
1222    fn check_schema_bytes() {
1223        let builder = PropertyDefinitionBuilder::new();
1224        let property_definition = builder
1225            .with_name("TEST".to_string())
1226            .with_data_type(DataType::Enum)
1227            .with_description("Optional".to_string())
1228            .with_enum_options(vec![
1229                "One".to_string(),
1230                "Two".to_string(),
1231                "Three".to_string(),
1232            ])
1233            .build()
1234            .unwrap();
1235
1236        let builder = SchemaBuilder::new();
1237        let original = builder
1238            .with_name("TestSchema".to_string())
1239            .with_description("Test Schema".to_string())
1240            .with_owner("owner".to_string())
1241            .with_properties(vec![property_definition.clone()])
1242            .build()
1243            .unwrap();
1244
1245        let bytes = original.clone().into_bytes().unwrap();
1246
1247        let schema = Schema::from_bytes(&bytes).unwrap();
1248        assert_eq!(schema, original);
1249    }
1250
1251    #[test]
1252    /// Validate that a `PropertyValue` with a `String` data type is built correctly
1253    fn check_property_value_builder_string() {
1254        let builder = PropertyValueBuilder::new();
1255        let property_value = builder
1256            .with_name("TEST".to_string())
1257            .with_data_type(DataType::String)
1258            .with_string_value("String value".to_string())
1259            .build()
1260            .unwrap();
1261
1262        assert_eq!(property_value.name, "TEST");
1263        assert_eq!(property_value.data_type, DataType::String);
1264        assert_eq!(property_value.string_value, "String value");
1265    }
1266
1267    #[test]
1268    /// Validate that a `PropertyValue` with a `Struct` data type is built correctly
1269    fn check_property_value_builder_struct() {
1270        let builder = PropertyValueBuilder::new();
1271        let string_value = builder
1272            .with_name("TEST".to_string())
1273            .with_data_type(DataType::String)
1274            .with_string_value("String value".to_string())
1275            .build()
1276            .unwrap();
1277
1278        let builder = PropertyValueBuilder::new();
1279        let property_value = builder
1280            .with_name("TEST_STRUCT".to_string())
1281            .with_data_type(DataType::Struct)
1282            .with_struct_values(vec![string_value.clone()])
1283            .build()
1284            .unwrap();
1285
1286        assert_eq!(property_value.name, "TEST_STRUCT");
1287        assert_eq!(property_value.data_type, DataType::Struct);
1288        assert_eq!(property_value.struct_values, vec![string_value]);
1289    }
1290
1291    #[test]
1292    /// Validate that a `PropertyValue` with a `LatLong` data type is built correctly
1293    fn check_property_value_builder_lat_long() {
1294        let lat_long = LatLong {
1295            latitude: 44977753,
1296            longitude: -93265015,
1297        };
1298        let builder = PropertyValueBuilder::new();
1299        let property_value = builder
1300            .with_name("TEST".to_string())
1301            .with_data_type(DataType::LatLong)
1302            .with_lat_long_value(lat_long.clone())
1303            .build()
1304            .unwrap();
1305
1306        assert_eq!(property_value.name, "TEST");
1307        assert_eq!(property_value.data_type, DataType::LatLong);
1308        assert_eq!(property_value.lat_long_value, lat_long);
1309    }
1310
1311    #[test]
1312    /// Validate that a `PropertyValue` with a `String` data type may be converted into bytes and
1313    /// back to its native representation successfully
1314    fn check_property_value_bytes() {
1315        let builder = PropertyValueBuilder::new();
1316        let original = builder
1317            .with_name("TEST".to_string())
1318            .with_data_type(DataType::String)
1319            .with_string_value("String value".to_string())
1320            .build()
1321            .unwrap();
1322
1323        let bytes = original.clone().into_bytes().unwrap();
1324
1325        let property_value = PropertyValue::from_bytes(&bytes).unwrap();
1326        assert_eq!(property_value, original);
1327    }
1328}