1#![deny(missing_docs)]
4#![deny(unsafe_code)]
5#![warn(clippy::pedantic)]
6#![allow(clippy::module_name_repetitions)]
7
8use serde::{Deserialize, Serialize};
9use chrono::{DateTime, Utc};
10use std::borrow::Cow;
11use crate::error::EpcisModelError;
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub struct Epc(pub Cow<'static, str>);
16
17impl From<String> for Epc {
18 fn from(s: String) -> Self {
19 Epc(Cow::Owned(s))
20 }
21}
22
23impl From<Cow<'static, str>> for Epc {
24 fn from(s: Cow<'static, str>) -> Self {
25 Epc(s)
26 }
27}
28
29impl TryFrom<&str> for Epc {
30 type Error = EpcisModelError;
31
32 fn try_from(s: &str) -> Result<Self, Self::Error> {
33 if s.is_empty() {
34 return Err(EpcisModelError::InvalidEpc("EPC URN cannot be empty".to_string()));
35 }
36 if !s.starts_with("urn:epc:") && !s.starts_with("http://") && !s.starts_with("https://") {
37 return Err(EpcisModelError::InvalidEpc(format!("EPC URN must start with URN or HTTP scheme: {s}")));
38 }
39 Ok(Epc(Cow::Owned(s.to_string())))
40 }
41}
42
43impl std::fmt::Display for Epc {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 write!(f, "{}", self.0)
46 }
47}
48
49#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
52#[serde(rename_all = "UPPERCASE")]
53pub enum Action {
54 Add,
56 Observe,
58 Delete,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
64pub struct ReadPointId(pub Cow<'static, str>);
65
66impl From<&'static str> for ReadPointId {
67 fn from(s: &'static str) -> Self {
68 ReadPointId(Cow::Borrowed(s))
69 }
70}
71
72impl From<String> for ReadPointId {
73 fn from(s: String) -> Self {
74 ReadPointId(Cow::Owned(s))
75 }
76}
77
78impl std::fmt::Display for ReadPointId {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "{}", self.0)
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
86pub struct ReadPoint {
87 pub id: ReadPointId,
89}
90
91impl From<&'static str> for ReadPoint {
92 fn from(id: &'static str) -> Self {
93 ReadPoint { id: ReadPointId::from(id) }
94 }
95}
96
97impl From<String> for ReadPoint {
98 fn from(id: String) -> Self {
99 ReadPoint { id: ReadPointId::from(id) }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
105pub struct BizLocationId(pub Cow<'static, str>);
106
107impl From<&'static str> for BizLocationId {
108 fn from(s: &'static str) -> Self {
109 BizLocationId(Cow::Borrowed(s))
110 }
111}
112
113impl From<String> for BizLocationId {
114 fn from(s: String) -> Self {
115 BizLocationId(Cow::Owned(s))
116 }
117}
118
119impl std::fmt::Display for BizLocationId {
120 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 write!(f, "{}", self.0)
122 }
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
127pub struct BizLocation {
128 pub id: BizLocationId,
130}
131
132impl From<&'static str> for BizLocation {
133 fn from(id: &'static str) -> Self {
134 BizLocation { id: BizLocationId::from(id) }
135 }
136}
137
138impl From<String> for BizLocation {
139 fn from(id: String) -> Self {
140 BizLocation { id: BizLocationId::from(id) }
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
146#[serde(rename_all = "camelCase")]
147pub struct BizTransaction {
148 #[serde(rename = "type")]
150 pub r#type: String,
151 pub biz_transaction: String,
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
157#[serde(rename_all = "camelCase")]
158pub struct Source {
159 #[serde(rename = "type")]
161 pub r#type: String,
162 pub source: String,
164}
165
166#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
168#[serde(rename_all = "camelCase")]
169pub struct Destination {
170 #[serde(rename = "type")]
172 pub r#type: String,
173 pub destination: String,
175}
176
177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
179#[serde(rename_all = "camelCase")]
180pub struct QuantityElement {
181 pub epc_class: String,
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub quantity: Option<f64>,
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub uom: Option<String>,
189}
190
191#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct SensorMetadata {
195 #[serde(skip_serializing_if = "Option::is_none")]
197 pub time: Option<DateTime<Utc>>,
198 #[serde(rename = "deviceID", skip_serializing_if = "Option::is_none")]
200 pub device_id: Option<String>,
201 #[serde(rename = "deviceMetadataURI", skip_serializing_if = "Option::is_none")]
203 pub device_metadata_uri: Option<String>,
204 #[serde(rename = "rawDataURI", skip_serializing_if = "Option::is_none")]
206 pub raw_data_uri: Option<String>,
207 #[serde(rename = "dataContentURI", skip_serializing_if = "Option::is_none")]
209 pub data_content_uri: Option<String>,
210 #[serde(rename = "bizRulesURI", skip_serializing_if = "Option::is_none")]
212 pub biz_rules_uri: Option<String>,
213}
214
215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
217#[serde(rename_all = "camelCase")]
218pub struct SensorReport {
219 #[serde(rename = "type")]
221 pub r#type: String,
222 #[serde(skip_serializing_if = "Option::is_none")]
224 pub value: Option<f64>,
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub uom: Option<String>,
228 #[serde(skip_serializing_if = "Option::is_none")]
230 pub sensor_processor: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub time: Option<DateTime<Utc>>,
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub microsecond_offset: Option<i32>,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub chemical_substance: Option<String>,
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub data_value: Option<String>,
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub string_value: Option<String>,
246 #[serde(skip_serializing_if = "Option::is_none")]
248 pub boolean_value: Option<bool>,
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub hex_binary_value: Option<String>,
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub uri_value: Option<String>,
255}
256
257#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
259#[serde(rename_all = "camelCase")]
260pub struct SensorElement {
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub sensor_metadata: Option<SensorMetadata>,
264 #[serde(skip_serializing_if = "Option::is_none")]
266 pub sensor_report: Option<Vec<SensorReport>>,
267}
268
269#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
271#[serde(rename_all = "camelCase")]
272pub struct ErrorDeclaration {
273 pub declaration_time: DateTime<Utc>,
275 #[serde(skip_serializing_if = "Option::is_none")]
277 pub reason: Option<String>,
278 #[serde(rename = "correctiveEventIDs", skip_serializing_if = "Option::is_none")]
280 pub corrective_event_ids: Option<Vec<String>>,
281}