xapi_data/
context_agent.rs1use crate::{
4 Agent, AgentId, DataError, Fingerprint, ObjectType, Validate, ValidationError, emit_error,
5};
6use core::fmt;
7use iri_string::types::{IriStr, IriString};
8use serde::{Deserialize, Serialize};
9use serde_with::skip_serializing_none;
10use std::hash::{Hash, Hasher};
11
12#[skip_serializing_none]
20#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
21#[serde(deny_unknown_fields)]
22#[serde(rename_all = "camelCase")]
23pub struct ContextAgent {
24 #[serde(default = "default_object_type")]
25 object_type: ObjectType,
26 agent: Agent,
27 relevant_types: Vec<IriString>,
40}
41
42#[skip_serializing_none]
43#[derive(Debug, Serialize)]
44#[serde(rename_all = "camelCase")]
45pub(crate) struct ContextAgentId {
46 object_type: ObjectType,
47 agent: AgentId,
48 relevant_types: Vec<IriString>,
49}
50
51impl From<ContextAgent> for ContextAgentId {
52 fn from(value: ContextAgent) -> Self {
53 ContextAgentId {
54 object_type: ObjectType::ContextAgent,
55 agent: AgentId::from(value.agent),
56 relevant_types: value.relevant_types,
57 }
58 }
59}
60
61impl From<ContextAgentId> for ContextAgent {
62 fn from(value: ContextAgentId) -> Self {
63 ContextAgent {
64 object_type: ObjectType::ContextAgent,
65 agent: Agent::from(value.agent),
66 relevant_types: value.relevant_types,
67 }
68 }
69}
70
71impl ContextAgent {
72 pub fn builder() -> ContextAgentBuilder {
74 ContextAgentBuilder::default()
75 }
76
77 pub fn check_object_type(&self) -> bool {
82 self.object_type == ObjectType::ContextAgent
83 }
84
85 pub fn agent(&self) -> &Agent {
87 &self.agent
88 }
89
90 pub fn relevant_types(&self) -> &[IriString] {
92 self.relevant_types.as_ref()
93 }
94}
95
96impl Fingerprint for ContextAgent {
97 fn fingerprint<H: Hasher>(&self, state: &mut H) {
98 self.agent.fingerprint(state);
99 for s in &self.relevant_types {
100 s.hash(state)
101 }
102 }
103}
104
105impl fmt::Display for ContextAgent {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 let mut vec = vec![];
108
109 vec.push(format!("agent: {}", self.agent));
110 vec.push(format!(
111 "relevantTypes: [{}]",
112 self.relevant_types
113 .iter()
114 .map(|x| x.to_string())
115 .collect::<Vec<_>>()
116 .join(", ")
117 ));
118
119 let res = vec
120 .iter()
121 .map(|x| x.to_string())
122 .collect::<Vec<_>>()
123 .join(", ");
124 write!(f, "ContextAgent{{ {res} }}")
125 }
126}
127
128impl Validate for ContextAgent {
129 fn validate(&self) -> Vec<ValidationError> {
130 let mut vec = vec![];
131
132 if !self.check_object_type() {
133 vec.push(ValidationError::WrongObjectType {
134 expected: ObjectType::ContextAgent,
135 found: self.object_type.to_string().into(),
136 })
137 }
138 vec.extend(self.agent.validate());
139 if self.relevant_types.is_empty() {
140 vec.push(ValidationError::Empty("relevant_types".into()))
141 } else {
142 for iri in self.relevant_types.iter() {
143 if iri.is_empty() {
144 vec.push(ValidationError::InvalidIRI(iri.to_string().into()))
145 }
146 }
147 }
148
149 vec
150 }
151}
152
153#[derive(Debug, Default)]
155pub struct ContextAgentBuilder {
156 _agent: Option<Agent>,
157 _relevant_types: Vec<IriString>,
158}
159
160impl ContextAgentBuilder {
161 pub fn agent(mut self, val: Agent) -> Result<Self, DataError> {
165 val.check_validity()?;
166 self._agent = Some(val);
167 Ok(self)
168 }
169
170 pub fn relevant_type(mut self, val: &str) -> Result<Self, DataError> {
174 if val.is_empty() {
175 emit_error!(DataError::Validation(ValidationError::Empty(
176 "relevant-type IRI".into()
177 )))
178 } else {
179 let iri = IriStr::new(val)?;
180 if self._relevant_types.is_empty() {
181 self._relevant_types = vec![];
182 }
183 self._relevant_types.push(iri.to_owned());
184 Ok(self)
185 }
186 }
187
188 pub fn build(self) -> Result<ContextAgent, DataError> {
192 if let Some(z_agent) = self._agent {
193 if self._relevant_types.is_empty() {
194 emit_error!(DataError::Validation(ValidationError::Empty(
195 "relevant_types".into()
196 )))
197 } else {
198 let mut relevant_types = vec![];
199 for item in self._relevant_types.iter() {
200 let iri = IriString::try_from(item.as_str())?;
201 relevant_types.push(iri);
202 }
203
204 Ok(ContextAgent {
205 object_type: ObjectType::ContextAgent,
206 agent: z_agent,
207 relevant_types,
208 })
209 }
210 } else {
211 emit_error!(DataError::Validation(ValidationError::MissingField(
212 "agent".into()
213 )))
214 }
215 }
216}
217
218fn default_object_type() -> ObjectType {
219 ObjectType::ContextAgent
220}