1use crate::{
4 Actor, ActorId, Attachment, Context, ContextId, DataError, Fingerprint, MyTimestamp,
5 ObjectType, SubStatementObject, SubStatementObjectId, Validate, ValidationError, Verb, VerbId,
6 XResult, emit_error, fingerprint_it,
7};
8use chrono::{DateTime, Utc};
9use core::fmt;
10use serde::{Deserialize, Serialize};
11use serde_with::skip_serializing_none;
12use std::{hash::Hasher, str::FromStr};
13
14#[skip_serializing_none]
19#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
20#[serde(deny_unknown_fields)]
21pub struct SubStatement {
22 #[serde(rename = "objectType")]
23 object_type: ObjectType,
24 actor: Actor,
25 verb: Verb,
26 object: SubStatementObject,
27 result: Option<XResult>,
28 context: Option<Context>,
29 timestamp: Option<MyTimestamp>,
30 attachments: Option<Vec<Attachment>>,
31}
32
33#[skip_serializing_none]
34#[derive(Debug, Serialize)]
35#[serde(deny_unknown_fields)]
36pub(crate) struct SubStatementId {
37 #[serde(rename = "objectType")]
38 object_type: ObjectType,
39 actor: ActorId,
40 verb: VerbId,
41 object: SubStatementObjectId,
42 result: Option<XResult>,
43 context: Option<ContextId>,
44 timestamp: Option<MyTimestamp>,
45 attachments: Option<Vec<Attachment>>,
46}
47
48impl From<SubStatement> for SubStatementId {
49 fn from(value: SubStatement) -> Self {
50 SubStatementId {
51 object_type: ObjectType::SubStatement,
52 actor: ActorId::from(value.actor),
53 verb: VerbId::from(value.verb),
54 object: SubStatementObjectId::from(value.object),
55 result: value.result,
56 context: value.context.map(ContextId::from),
57 timestamp: value.timestamp,
58 attachments: value.attachments,
59 }
60 }
61}
62
63impl From<Box<SubStatement>> for SubStatementId {
64 fn from(value: Box<SubStatement>) -> Self {
65 SubStatementId {
66 object_type: ObjectType::SubStatement,
67 actor: ActorId::from(value.actor),
68 verb: VerbId::from(value.verb),
69 object: SubStatementObjectId::from(value.object),
70 result: value.result,
71 context: value.context.map(ContextId::from),
72 timestamp: value.timestamp,
73 attachments: value.attachments,
74 }
75 }
76}
77
78impl From<SubStatementId> for SubStatement {
79 fn from(value: SubStatementId) -> Self {
80 SubStatement {
81 object_type: ObjectType::SubStatement,
82 actor: Actor::from(value.actor),
83 verb: Verb::from(value.verb),
84 object: SubStatementObject::from(value.object),
85 result: value.result,
86 context: value.context.map(Context::from),
87 timestamp: value.timestamp,
88 attachments: value.attachments,
89 }
90 }
91}
92
93impl SubStatement {
94 pub fn builder() -> SubStatementBuilder {
96 SubStatementBuilder::default()
97 }
98
99 pub fn check_object_type(&self) -> bool {
104 self.object_type == ObjectType::SubStatement
105 }
106
107 pub fn actor(&self) -> &Actor {
113 &self.actor
114 }
115
116 pub fn verb(&self) -> &Verb {
118 &self.verb
119 }
120
121 pub fn object(&self) -> &SubStatementObject {
128 &self.object
129 }
130
131 pub fn result(&self) -> Option<&XResult> {
133 self.result.as_ref()
134 }
135
136 pub fn context(&self) -> Option<&Context> {
138 self.context.as_ref()
139 }
140
141 pub fn timestamp(&self) -> Option<&DateTime<Utc>> {
146 if let Some(z_timestamp) = self.timestamp.as_ref() {
147 Some(z_timestamp.inner())
148 } else {
149 None
150 }
151 }
152
153 pub fn attachments(&self) -> Option<&[Attachment]> {
155 self.attachments.as_deref()
156 }
157
158 pub fn uid(&self) -> u64 {
160 fingerprint_it(self)
161 }
162
163 pub fn equivalent(&self, that: &SubStatement) -> bool {
165 self.uid() == that.uid()
166 }
167}
168
169impl fmt::Display for SubStatement {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 let mut vec = vec![];
172
173 vec.push(format!("actor: {}", self.actor));
174 vec.push(format!("verb: {}", self.verb));
175 vec.push(format!("object: {}", self.object));
176 if let Some(z_result) = self.result.as_ref() {
177 vec.push(format!("result: {}", z_result));
178 }
179 if let Some(z_context) = self.context.as_ref() {
180 vec.push(format!("context: {}", z_context));
181 }
182 if let Some(z_timestamp) = self.timestamp.as_ref() {
183 vec.push(format!("timestamp: \"{}\"", z_timestamp));
184 }
185 if self.attachments.is_some() {
186 let items = self.attachments.as_deref().unwrap();
187 vec.push(format!(
188 "attachments: [{}]",
189 items
190 .iter()
191 .map(|x| x.to_string())
192 .collect::<Vec<_>>()
193 .join(", ")
194 ))
195 }
196
197 let res = vec
198 .iter()
199 .map(|x| x.to_string())
200 .collect::<Vec<_>>()
201 .join(", ");
202 write!(f, "SubStatement{{ {res} }}")
203 }
204}
205
206impl Fingerprint for SubStatement {
207 fn fingerprint<H: Hasher>(&self, state: &mut H) {
208 self.actor.fingerprint(state);
210 self.verb.fingerprint(state);
211 self.object.fingerprint(state);
212 }
216}
217
218impl Validate for SubStatement {
219 fn validate(&self) -> Vec<ValidationError> {
220 let mut vec = vec![];
221
222 if !self.check_object_type() {
223 vec.push(ValidationError::WrongObjectType {
224 expected: ObjectType::SubStatement,
225 found: self.object_type.to_string().into(),
226 })
227 }
228 vec.extend(self.actor.validate());
229 vec.extend(self.verb.validate());
230 vec.extend(self.object.validate());
231 if let Some(z_result) = self.result.as_ref() {
232 vec.extend(z_result.validate())
233 }
234 if let Some(z_context) = self.context.as_ref() {
235 vec.extend(z_context.validate());
236 if !self.object().is_activity()
238 && (z_context.revision().is_some() || z_context.platform().is_some())
239 {
240 vec.push(ValidationError::ConstraintViolation(
241 "SubStatement context w/ revision | platform but object != Activity".into(),
242 ))
243 }
244 }
245 if let Some(z_attachments) = self.attachments.as_ref() {
246 for att in z_attachments.iter() {
247 vec.extend(att.validate())
248 }
249 }
250
251 vec
252 }
253}
254
255#[derive(Debug, Default)]
257pub struct SubStatementBuilder {
258 _actor: Option<Actor>,
259 _verb: Option<Verb>,
260 _object: Option<SubStatementObject>,
261 _result: Option<XResult>,
262 _context: Option<Context>,
263 _timestamp: Option<MyTimestamp>,
264 _attachments: Option<Vec<Attachment>>,
265}
266
267impl SubStatementBuilder {
268 pub fn actor(mut self, val: Actor) -> Result<Self, DataError> {
272 val.check_validity()?;
273 self._actor = Some(val);
274 Ok(self)
275 }
276
277 pub fn verb(mut self, val: Verb) -> Result<Self, DataError> {
281 val.check_validity()?;
282 self._verb = Some(val);
283 Ok(self)
284 }
285
286 pub fn object(mut self, val: SubStatementObject) -> Result<Self, DataError> {
290 val.check_validity()?;
291 self._object = Some(val);
292 Ok(self)
293 }
294
295 pub fn result(mut self, val: XResult) -> Result<Self, DataError> {
299 val.check_validity()?;
300 self._result = Some(val);
301 Ok(self)
302 }
303
304 pub fn context(mut self, val: Context) -> Result<Self, DataError> {
308 val.check_validity()?;
309 self._context = Some(val);
310 Ok(self)
311 }
312
313 pub fn timestamp(mut self, val: &str) -> Result<Self, DataError> {
317 let val = val.trim();
318 if val.is_empty() {
319 emit_error!(DataError::Validation(ValidationError::Empty(
320 "timestamp".into()
321 )))
322 }
323 let ts = MyTimestamp::from_str(val)?;
324 self._timestamp = Some(ts);
325 Ok(self)
326 }
327
328 pub fn with_timestamp(mut self, val: DateTime<Utc>) -> Self {
330 self._timestamp = Some(MyTimestamp::from(val));
331 self
332 }
333
334 pub fn attachment(mut self, att: Attachment) -> Result<Self, DataError> {
337 att.check_validity()?;
338 if self._attachments.is_none() {
339 self._attachments = Some(vec![])
340 }
341 self._attachments.as_mut().unwrap().push(att);
342 Ok(self)
343 }
344
345 pub fn build(self) -> Result<SubStatement, DataError> {
349 if self._actor.is_none() || self._verb.is_none() || self._object.is_none() {
350 emit_error!(DataError::Validation(ValidationError::MissingField(
351 "actor | verb | object".into()
352 )))
353 }
354 Ok(SubStatement {
355 object_type: ObjectType::SubStatement,
356 actor: self._actor.unwrap(),
357 verb: self._verb.unwrap(),
358 object: self._object.unwrap(),
359 result: self._result,
360 context: self._context,
361 timestamp: self._timestamp,
362 attachments: self._attachments,
363 })
364 }
365}