1use crate::{
4 data::{
5 Actor, ActorId, Attachment, Context, ContextId, DataError, Fingerprint, MyTimestamp,
6 ObjectType, SubStatementObject, SubStatementObjectId, Validate, ValidationError, Verb,
7 VerbId, XResult, fingerprint_it,
8 },
9 emit_error,
10};
11use chrono::{DateTime, Utc};
12use core::fmt;
13use serde::{Deserialize, Serialize};
14use serde_with::skip_serializing_none;
15use std::{hash::Hasher, str::FromStr};
16
17#[skip_serializing_none]
22#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
23#[serde(deny_unknown_fields)]
24pub struct SubStatement {
25 #[serde(rename = "objectType")]
26 object_type: ObjectType,
27 actor: Actor,
28 verb: Verb,
29 object: SubStatementObject,
30 result: Option<XResult>,
31 context: Option<Context>,
32 timestamp: Option<MyTimestamp>,
33 attachments: Option<Vec<Attachment>>,
34}
35
36#[skip_serializing_none]
37#[derive(Debug, Serialize)]
38#[serde(deny_unknown_fields)]
39pub(crate) struct SubStatementId {
40 #[serde(rename = "objectType")]
41 object_type: ObjectType,
42 actor: ActorId,
43 verb: VerbId,
44 object: SubStatementObjectId,
45 result: Option<XResult>,
46 context: Option<ContextId>,
47 timestamp: Option<MyTimestamp>,
48 attachments: Option<Vec<Attachment>>,
49}
50
51impl From<SubStatement> for SubStatementId {
52 fn from(value: SubStatement) -> Self {
53 SubStatementId {
54 object_type: ObjectType::SubStatement,
55 actor: ActorId::from(value.actor),
56 verb: VerbId::from(value.verb),
57 object: SubStatementObjectId::from(value.object),
58 result: value.result,
59 context: value.context.map(ContextId::from),
60 timestamp: value.timestamp,
61 attachments: value.attachments,
62 }
63 }
64}
65
66impl From<Box<SubStatement>> for SubStatementId {
67 fn from(value: Box<SubStatement>) -> Self {
68 SubStatementId {
69 object_type: ObjectType::SubStatement,
70 actor: ActorId::from(value.actor),
71 verb: VerbId::from(value.verb),
72 object: SubStatementObjectId::from(value.object),
73 result: value.result,
74 context: value.context.map(ContextId::from),
75 timestamp: value.timestamp,
76 attachments: value.attachments,
77 }
78 }
79}
80
81impl From<SubStatementId> for SubStatement {
82 fn from(value: SubStatementId) -> Self {
83 SubStatement {
84 object_type: ObjectType::SubStatement,
85 actor: Actor::from(value.actor),
86 verb: Verb::from(value.verb),
87 object: SubStatementObject::from(value.object),
88 result: value.result,
89 context: value.context.map(Context::from),
90 timestamp: value.timestamp,
91 attachments: value.attachments,
92 }
93 }
94}
95
96impl SubStatement {
97 pub fn builder() -> SubStatementBuilder {
99 SubStatementBuilder::default()
100 }
101
102 pub fn check_object_type(&self) -> bool {
107 self.object_type == ObjectType::SubStatement
108 }
109
110 pub fn actor(&self) -> &Actor {
116 &self.actor
117 }
118
119 pub fn verb(&self) -> &Verb {
121 &self.verb
122 }
123
124 pub fn object(&self) -> &SubStatementObject {
131 &self.object
132 }
133
134 pub fn result(&self) -> Option<&XResult> {
136 self.result.as_ref()
137 }
138
139 pub fn context(&self) -> Option<&Context> {
141 self.context.as_ref()
142 }
143
144 pub fn timestamp(&self) -> Option<&DateTime<Utc>> {
149 if let Some(z_timestamp) = self.timestamp.as_ref() {
150 Some(z_timestamp.inner())
151 } else {
152 None
153 }
154 }
155
156 pub fn attachments(&self) -> Option<&[Attachment]> {
158 self.attachments.as_deref()
159 }
160
161 pub fn uid(&self) -> u64 {
163 fingerprint_it(self)
164 }
165
166 pub fn equivalent(&self, that: &SubStatement) -> bool {
168 self.uid() == that.uid()
169 }
170}
171
172impl fmt::Display for SubStatement {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 let mut vec = vec![];
175
176 vec.push(format!("actor: {}", self.actor));
177 vec.push(format!("verb: {}", self.verb));
178 vec.push(format!("object: {}", self.object));
179 if let Some(z_result) = self.result.as_ref() {
180 vec.push(format!("result: {}", z_result));
181 }
182 if let Some(z_context) = self.context.as_ref() {
183 vec.push(format!("context: {}", z_context));
184 }
185 if let Some(z_timestamp) = self.timestamp.as_ref() {
186 vec.push(format!("timestamp: \"{}\"", z_timestamp));
187 }
188 if self.attachments.is_some() {
189 let items = self.attachments.as_deref().unwrap();
190 vec.push(format!(
191 "attachments: [{}]",
192 items
193 .iter()
194 .map(|x| x.to_string())
195 .collect::<Vec<_>>()
196 .join(", ")
197 ))
198 }
199
200 let res = vec
201 .iter()
202 .map(|x| x.to_string())
203 .collect::<Vec<_>>()
204 .join(", ");
205 write!(f, "SubStatement{{ {res} }}")
206 }
207}
208
209impl Fingerprint for SubStatement {
210 fn fingerprint<H: Hasher>(&self, state: &mut H) {
211 self.actor.fingerprint(state);
213 self.verb.fingerprint(state);
214 self.object.fingerprint(state);
215 }
219}
220
221impl Validate for SubStatement {
222 fn validate(&self) -> Vec<ValidationError> {
223 let mut vec = vec![];
224
225 if !self.check_object_type() {
226 vec.push(ValidationError::WrongObjectType {
227 expected: ObjectType::SubStatement,
228 found: self.object_type.to_string().into(),
229 })
230 }
231 vec.extend(self.actor.validate());
232 vec.extend(self.verb.validate());
233 vec.extend(self.object.validate());
234 if let Some(z_result) = self.result.as_ref() {
235 vec.extend(z_result.validate())
236 }
237 if let Some(z_context) = self.context.as_ref() {
238 vec.extend(z_context.validate());
239 if !self.object().is_activity()
241 && (z_context.revision().is_some() || z_context.platform().is_some())
242 {
243 vec.push(ValidationError::ConstraintViolation(
244 "SubStatement context w/ revision | platform but object != Activity".into(),
245 ))
246 }
247 }
248 if let Some(z_attachments) = self.attachments.as_ref() {
249 for att in z_attachments.iter() {
250 vec.extend(att.validate())
251 }
252 }
253
254 vec
255 }
256}
257
258#[derive(Debug, Default)]
260pub struct SubStatementBuilder {
261 _actor: Option<Actor>,
262 _verb: Option<Verb>,
263 _object: Option<SubStatementObject>,
264 _result: Option<XResult>,
265 _context: Option<Context>,
266 _timestamp: Option<MyTimestamp>,
267 _attachments: Option<Vec<Attachment>>,
268}
269
270impl SubStatementBuilder {
271 pub fn actor(mut self, val: Actor) -> Result<Self, DataError> {
275 val.check_validity()?;
276 self._actor = Some(val);
277 Ok(self)
278 }
279
280 pub fn verb(mut self, val: Verb) -> Result<Self, DataError> {
284 val.check_validity()?;
285 self._verb = Some(val);
286 Ok(self)
287 }
288
289 pub fn object(mut self, val: SubStatementObject) -> Result<Self, DataError> {
293 val.check_validity()?;
294 self._object = Some(val);
295 Ok(self)
296 }
297
298 pub fn result(mut self, val: XResult) -> Result<Self, DataError> {
302 val.check_validity()?;
303 self._result = Some(val);
304 Ok(self)
305 }
306
307 pub fn context(mut self, val: Context) -> Result<Self, DataError> {
311 val.check_validity()?;
312 self._context = Some(val);
313 Ok(self)
314 }
315
316 pub fn timestamp(mut self, val: &str) -> Result<Self, DataError> {
320 let val = val.trim();
321 if val.is_empty() {
322 emit_error!(DataError::Validation(ValidationError::Empty(
323 "timestamp".into()
324 )))
325 }
326 let ts = MyTimestamp::from_str(val)?;
327 self._timestamp = Some(ts);
328 Ok(self)
329 }
330
331 pub fn with_timestamp(mut self, val: DateTime<Utc>) -> Self {
333 self._timestamp = Some(MyTimestamp::from(val));
334 self
335 }
336
337 pub fn attachment(mut self, att: Attachment) -> Result<Self, DataError> {
340 att.check_validity()?;
341 if self._attachments.is_none() {
342 self._attachments = Some(vec![])
343 }
344 self._attachments.as_mut().unwrap().push(att);
345 Ok(self)
346 }
347
348 pub fn build(self) -> Result<SubStatement, DataError> {
352 if self._actor.is_none() || self._verb.is_none() || self._object.is_none() {
353 emit_error!(DataError::Validation(ValidationError::MissingField(
354 "actor | verb | object".into()
355 )))
356 }
357 Ok(SubStatement {
358 object_type: ObjectType::SubStatement,
359 actor: self._actor.unwrap(),
360 verb: self._verb.unwrap(),
361 object: self._object.unwrap(),
362 result: self._result,
363 context: self._context,
364 timestamp: self._timestamp,
365 attachments: self._attachments,
366 })
367 }
368}