grid_sdk/protocol/location/
state.rs1use protobuf::Message;
18use protobuf::RepeatedField;
19
20use std::error::Error as StdError;
21
22use crate::protos;
23use crate::protos::schema_state;
24use crate::protos::{
25 FromBytes, FromNative, FromProto, IntoBytes, IntoNative, IntoProto, ProtoConversionError,
26};
27
28use crate::protocol::schema::state::PropertyValue;
29
30#[derive(Copy, Clone, Debug, PartialEq)]
34pub enum LocationNamespace {
35 Gs1,
36}
37
38impl Default for LocationNamespace {
39 fn default() -> Self {
40 LocationNamespace::Gs1
41 }
42}
43
44impl FromProto<protos::location_state::Location_LocationNamespace> for LocationNamespace {
45 fn from_proto(
46 namespace: protos::location_state::Location_LocationNamespace,
47 ) -> Result<Self, ProtoConversionError> {
48 match namespace {
49 protos::location_state::Location_LocationNamespace::GS1 => Ok(LocationNamespace::Gs1),
50 protos::location_state::Location_LocationNamespace::UNSET_TYPE => {
51 Err(ProtoConversionError::InvalidTypeError(
52 "Cannot convert Location_LocationType with type UNSET_TYPE".to_string(),
53 ))
54 }
55 }
56 }
57}
58
59impl FromNative<LocationNamespace> for protos::location_state::Location_LocationNamespace {
60 fn from_native(namespace: LocationNamespace) -> Result<Self, ProtoConversionError> {
61 match namespace {
62 LocationNamespace::Gs1 => Ok(protos::location_state::Location_LocationNamespace::GS1),
63 }
64 }
65}
66
67impl IntoProto<protos::location_state::Location_LocationNamespace> for LocationNamespace {}
68impl IntoNative<LocationNamespace> for protos::location_state::Location_LocationNamespace {}
69
70#[derive(Debug, Clone, PartialEq)]
75pub struct Location {
76 location_id: String,
77 namespace: LocationNamespace,
78 owner: String,
79 properties: Vec<PropertyValue>,
80}
81
82impl Location {
83 pub fn location_id(&self) -> &str {
84 &self.location_id
85 }
86
87 pub fn namespace(&self) -> &LocationNamespace {
88 &self.namespace
89 }
90
91 pub fn owner(&self) -> &str {
92 &self.owner
93 }
94
95 pub fn properties(&self) -> &[PropertyValue] {
96 &self.properties
97 }
98
99 pub fn into_builder(self) -> LocationBuilder {
100 LocationBuilder::new()
101 .with_location_id(self.location_id)
102 .with_namespace(self.namespace)
103 .with_owner(self.owner)
104 .with_properties(self.properties)
105 }
106}
107
108impl FromProto<protos::location_state::Location> for Location {
109 fn from_proto(
110 location: protos::location_state::Location,
111 ) -> Result<Self, ProtoConversionError> {
112 Ok(Location {
113 location_id: location.get_location_id().to_string(),
114 namespace: LocationNamespace::from_proto(location.get_namespace())?,
115 owner: location.get_owner().to_string(),
116 properties: location
117 .get_properties()
118 .iter()
119 .cloned()
120 .map(PropertyValue::from_proto)
121 .collect::<Result<Vec<PropertyValue>, ProtoConversionError>>()?,
122 })
123 }
124}
125
126impl FromNative<Location> for protos::location_state::Location {
127 fn from_native(location: Location) -> Result<Self, ProtoConversionError> {
128 let mut proto = protos::location_state::Location::new();
129 proto.set_location_id(location.location_id().to_string());
130 proto.set_namespace(location.namespace().into_proto()?);
131 proto.set_owner(location.owner().to_string());
132 proto.set_properties(RepeatedField::from_vec(
133 location
134 .properties()
135 .iter()
136 .cloned()
137 .map(PropertyValue::into_proto)
138 .collect::<Result<Vec<schema_state::PropertyValue>, ProtoConversionError>>()?,
139 ));
140 Ok(proto)
141 }
142}
143
144impl IntoBytes for Location {
145 fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
146 let proto = self.into_proto()?;
147 let bytes = proto.write_to_bytes().map_err(|_| {
148 ProtoConversionError::SerializationError(
149 "Unable to get bytes from Location".to_string(),
150 )
151 })?;
152
153 Ok(bytes)
154 }
155}
156
157impl IntoProto<protos::location_state::Location> for Location {}
158impl IntoNative<Location> for protos::location_state::Location {}
159
160#[derive(Debug)]
163pub enum LocationBuildError {
164 MissingField(String),
165 EmptyVec(String),
166}
167
168impl StdError for LocationBuildError {
169 fn description(&self) -> &str {
170 match *self {
171 LocationBuildError::MissingField(ref msg) => msg,
172 LocationBuildError::EmptyVec(ref msg) => msg,
173 }
174 }
175
176 fn source(&self) -> Option<&(dyn StdError + 'static)> {
177 match *self {
178 LocationBuildError::MissingField(_) => None,
179 LocationBuildError::EmptyVec(_) => None,
180 }
181 }
182}
183
184impl std::fmt::Display for LocationBuildError {
185 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
186 match *self {
187 LocationBuildError::MissingField(ref s) => write!(f, "missing field \"{}\"", s),
188 LocationBuildError::EmptyVec(ref s) => write!(f, "\"{}\" must not be empty", s),
189 }
190 }
191}
192
193#[derive(Default, Clone, PartialEq)]
195pub struct LocationBuilder {
196 pub location_id: Option<String>,
197 pub namespace: Option<LocationNamespace>,
198 pub owner: Option<String>,
199 pub properties: Option<Vec<PropertyValue>>,
200}
201
202impl LocationBuilder {
203 pub fn new() -> Self {
204 LocationBuilder::default()
205 }
206
207 pub fn with_location_id(mut self, location_id: String) -> Self {
208 self.location_id = Some(location_id);
209 self
210 }
211
212 pub fn with_namespace(mut self, namespace: LocationNamespace) -> Self {
213 self.namespace = Some(namespace);
214 self
215 }
216
217 pub fn with_owner(mut self, owner: String) -> Self {
218 self.owner = Some(owner);
219 self
220 }
221
222 pub fn with_properties(mut self, properties: Vec<PropertyValue>) -> Self {
223 self.properties = Some(properties);
224 self
225 }
226
227 pub fn build(self) -> Result<Location, LocationBuildError> {
228 let location_id = self.location_id.ok_or_else(|| {
229 LocationBuildError::MissingField("'location_id' field is required".to_string())
230 })?;
231
232 let namespace = self.namespace.ok_or_else(|| {
233 LocationBuildError::MissingField("'namespace' field is required".to_string())
234 })?;
235
236 let owner = self.owner.ok_or_else(|| {
237 LocationBuildError::MissingField("'owner' field is required".to_string())
238 })?;
239
240 let properties = self.properties.ok_or_else(|| {
241 LocationBuildError::MissingField("'properties' field is required".to_string())
242 })?;
243
244 Ok(Location {
245 location_id,
246 namespace,
247 owner,
248 properties,
249 })
250 }
251}
252
253#[derive(Debug, Clone, PartialEq)]
255pub struct LocationList {
256 locations: Vec<Location>,
257}
258
259impl LocationList {
260 pub fn locations(&self) -> &[Location] {
261 &self.locations
262 }
263
264 pub fn into_builder(self) -> LocationListBuilder {
265 LocationListBuilder::new().with_locations(self.locations)
266 }
267}
268
269impl FromProto<protos::location_state::LocationList> for LocationList {
270 fn from_proto(
271 location_list: protos::location_state::LocationList,
272 ) -> Result<Self, ProtoConversionError> {
273 Ok(LocationList {
274 locations: location_list
275 .get_entries()
276 .iter()
277 .cloned()
278 .map(Location::from_proto)
279 .collect::<Result<Vec<Location>, ProtoConversionError>>()?,
280 })
281 }
282}
283
284impl FromNative<LocationList> for protos::location_state::LocationList {
285 fn from_native(location_list: LocationList) -> Result<Self, ProtoConversionError> {
286 let mut location_list_proto = protos::location_state::LocationList::new();
287
288 location_list_proto.set_entries(RepeatedField::from_vec(
289 location_list
290 .locations()
291 .iter()
292 .cloned()
293 .map(Location::into_proto)
294 .collect::<Result<Vec<protos::location_state::Location>, ProtoConversionError>>()?,
295 ));
296
297 Ok(location_list_proto)
298 }
299}
300
301impl FromBytes<LocationList> for LocationList {
302 fn from_bytes(bytes: &[u8]) -> Result<LocationList, ProtoConversionError> {
303 let proto: protos::location_state::LocationList = Message::parse_from_bytes(bytes)
304 .map_err(|_| {
305 ProtoConversionError::SerializationError(
306 "Unable to get LocationList from bytes".to_string(),
307 )
308 })?;
309
310 proto.into_native()
311 }
312}
313
314impl IntoBytes for LocationList {
315 fn into_bytes(self) -> Result<Vec<u8>, ProtoConversionError> {
316 let proto = self.into_proto()?;
317 let bytes = proto.write_to_bytes().map_err(|_| {
318 ProtoConversionError::SerializationError(
319 "Unable to get bytes from LocationList".to_string(),
320 )
321 })?;
322
323 Ok(bytes)
324 }
325}
326
327impl IntoProto<protos::location_state::LocationList> for LocationList {}
328impl IntoNative<LocationList> for protos::location_state::LocationList {}
329
330#[derive(Default, Clone)]
332pub struct LocationListBuilder {
333 pub locations: Option<Vec<Location>>,
334}
335
336impl LocationListBuilder {
337 pub fn new() -> Self {
338 LocationListBuilder::default()
339 }
340
341 pub fn with_locations(mut self, locations: Vec<Location>) -> LocationListBuilder {
342 self.locations = Some(locations);
343 self
344 }
345
346 pub fn build(self) -> Result<LocationList, LocationBuildError> {
347 let locations = self
349 .locations
350 .ok_or_else(|| LocationBuildError::MissingField("locations".to_string()))?;
351
352 let locations = {
353 if locations.is_empty() {
354 return Err(LocationBuildError::EmptyVec("locations".to_string()));
355 } else {
356 locations
357 }
358 };
359
360 Ok(LocationList { locations })
361 }
362}