use crate::{
Activity, ActivityId, Agent, AgentId, DataError, Fingerprint, Group, GroupId, StatementRef,
SubStatement, SubStatementId, Validate, ValidationError, emit_error,
};
use core::fmt;
use serde::{
Deserialize, Serialize,
de::{self},
};
use serde_json::Value;
use std::hash::Hasher;
use tracing::{debug, error};
#[derive(Debug, PartialEq, Serialize)]
#[serde(untagged)]
pub enum StatementObject {
Agent(Agent),
Group(Group),
StatementRef(StatementRef),
SubStatement(Box<SubStatement>),
Activity(Activity),
}
#[derive(Debug, Serialize)]
#[serde(untagged)]
pub(crate) enum StatementObjectId {
Activity(ActivityId),
Agent(AgentId),
Group(GroupId),
StatementRef(StatementRef),
SubStatement(Box<SubStatementId>),
}
impl From<StatementObject> for StatementObjectId {
fn from(value: StatementObject) -> Self {
match value {
StatementObject::Agent(agent) => StatementObjectId::Agent(agent.into()),
StatementObject::Group(group) => StatementObjectId::Group(group.into()),
StatementObject::StatementRef(stmt_ref) => StatementObjectId::StatementRef(stmt_ref),
StatementObject::SubStatement(sub_stmt) => {
StatementObjectId::SubStatement(Box::new(sub_stmt.into()))
}
StatementObject::Activity(activity) => StatementObjectId::Activity(activity.into()),
}
}
}
impl From<StatementObjectId> for StatementObject {
fn from(value: StatementObjectId) -> Self {
match value {
StatementObjectId::Activity(x) => StatementObject::Activity(Activity::from(x)),
StatementObjectId::Agent(x) => StatementObject::Agent(Agent::from(x)),
StatementObjectId::Group(x) => StatementObject::Group(Group::from(x)),
StatementObjectId::StatementRef(x) => StatementObject::StatementRef(x),
StatementObjectId::SubStatement(x) => {
StatementObject::SubStatement(Box::new(SubStatement::from(*x)))
}
}
}
}
impl<'de> Deserialize<'de> for StatementObject {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v: Value = Deserialize::deserialize(deserializer)?;
match v {
Value::Object(ref map) => {
let ot = map.get("objectType").map_or(
{
debug!("Missing 'objectType'. Assume 'Activity' + continue");
Some("Activity")
},
|x| x.as_str(),
);
match ot {
Some("Agent") => match Agent::deserialize(v) {
Ok(x) => Ok(StatementObject::Agent(x)),
Err(x) => {
let msg = format!("input is not Agent: {x}");
error!("objectType is 'Agent', but {}", msg);
Err(de::Error::custom(msg))
}
},
Some("Group") => match Group::deserialize(v) {
Ok(x) => Ok(StatementObject::Group(x)),
Err(x) => {
let msg = format!("input is not Group: {x}");
error!("objectType is 'Group', but {}", msg);
Err(de::Error::custom(msg))
}
},
Some("StatementRef") => match StatementRef::deserialize(v) {
Ok(x) => Ok(StatementObject::StatementRef(x)),
Err(x) => {
let msg = format!("input is not StatementRef: {x}");
error!("objectType is 'StatementRef', but {}", msg);
Err(de::Error::custom(msg))
}
},
Some("SubStatement") => match SubStatement::deserialize(v) {
Ok(x) => Ok(StatementObject::SubStatement(Box::new(x))),
Err(x) => {
let msg = format!("input is not SubStatement: {x}");
error!("objectType is 'SubStatement', but {}", msg);
Err(de::Error::custom(msg))
}
},
Some("Activity") => match Activity::deserialize(v) {
Ok(x) => Ok(StatementObject::Activity(x)),
Err(x) => {
let msg = format!("input is not Activity: {x}");
error!("objectType is 'Activity', but {}", msg);
Err(de::Error::custom(msg))
}
},
_ => Err(de::Error::custom(
"Unknown 'objectType'. Expected Agent | Group | StatementRef | SubStatement | Activity",
)),
}
}
_ => Err(de::Error::custom("Expected JSON object")),
}
}
}
#[derive(Debug)]
#[doc(hidden)]
pub enum ObjectKind {
ActivityObject = 0,
AgentObject = 1,
GroupObject = 2,
StatementRefObject = 3,
SubStatementObject = 4,
}
impl fmt::Display for ObjectKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ObjectKind::ActivityObject => write!(f, "[Activity]"),
ObjectKind::AgentObject => write!(f, "[Agent]"),
ObjectKind::GroupObject => write!(f, "[Group]"),
ObjectKind::StatementRefObject => write!(f, "[StatementRef]"),
ObjectKind::SubStatementObject => write!(f, "[SubStatement]"),
}
}
}
impl From<i16> for ObjectKind {
fn from(value: i16) -> Self {
match value {
0 => ObjectKind::ActivityObject,
1 => ObjectKind::AgentObject,
2 => ObjectKind::GroupObject,
3 => ObjectKind::StatementRefObject,
_ => ObjectKind::SubStatementObject,
}
}
}
impl StatementObject {
pub fn from_activity(obj: Activity) -> Self {
StatementObject::Activity(obj)
}
pub fn from_agent(obj: Agent) -> Self {
StatementObject::Agent(obj)
}
pub fn from_group(obj: Group) -> Self {
StatementObject::Group(obj)
}
pub fn from_statement_ref(obj: StatementRef) -> Self {
StatementObject::StatementRef(obj)
}
pub fn from_sub_statement(obj: SubStatement) -> Self {
StatementObject::SubStatement(Box::new(obj))
}
pub fn is_activity(&self) -> bool {
matches!(self, StatementObject::Activity(_))
}
pub fn is_agent(&self) -> bool {
matches!(self, StatementObject::Agent(_))
}
pub fn is_group(&self) -> bool {
matches!(self, StatementObject::Group(_))
}
pub fn is_statement_ref(&self) -> bool {
matches!(self, StatementObject::StatementRef(_))
}
pub fn is_sub_statement(&self) -> bool {
matches!(self, StatementObject::SubStatement(_))
}
pub fn as_activity(&self) -> Result<Activity, DataError> {
match self {
StatementObject::Activity(x) => Ok(x.to_owned()),
_ => emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
format!("This ({self}) is NOT an Activity").into()
))),
}
}
pub fn as_agent(&self) -> Result<Agent, DataError> {
match self {
StatementObject::Agent(x) => Ok(x.to_owned()),
_ => emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
format!("This ({self}) is NOT an Agent").into()
))),
}
}
pub fn as_group(&self) -> Result<Group, DataError> {
match self {
StatementObject::Group(x) => Ok(x.to_owned()),
_ => emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
format!("This ({self}) is NOT a Group").into()
))),
}
}
pub fn as_statement_ref(&self) -> Result<StatementRef, DataError> {
match self {
StatementObject::StatementRef(x) => Ok(x.to_owned()),
_ => emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
format!("This ({self}) is NOT a Statement-Ref").into()
))),
}
}
pub fn as_sub_statement(&self) -> Result<SubStatement, DataError> {
match self {
StatementObject::SubStatement(x) => Ok(*x.to_owned()),
_ => emit_error!(DataError::Validation(ValidationError::ConstraintViolation(
format!("This ({self}) is NOT a Sub-Statement").into()
))),
}
}
pub fn kind(&self) -> ObjectKind {
match self {
StatementObject::Activity(_) => ObjectKind::ActivityObject,
StatementObject::Agent(_) => ObjectKind::AgentObject,
StatementObject::Group(_) => ObjectKind::GroupObject,
StatementObject::StatementRef(_) => ObjectKind::StatementRefObject,
StatementObject::SubStatement(_) => ObjectKind::SubStatementObject,
}
}
}
impl fmt::Display for StatementObject {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
StatementObject::Agent(x) => write!(f, "{x}"),
StatementObject::Group(x) => write!(f, "{x}"),
StatementObject::StatementRef(x) => write!(f, "{x}"),
StatementObject::SubStatement(x) => write!(f, "{x}"),
StatementObject::Activity(x) => write!(f, "{x}"),
}
}
}
impl Fingerprint for StatementObject {
fn fingerprint<H: Hasher>(&self, state: &mut H) {
match self {
StatementObject::Agent(x) => x.fingerprint(state),
StatementObject::Group(x) => x.fingerprint(state),
StatementObject::StatementRef(x) => x.fingerprint(state),
StatementObject::SubStatement(x) => x.fingerprint(state),
StatementObject::Activity(x) => x.fingerprint(state),
}
}
}
impl Validate for StatementObject {
fn validate(&self) -> Vec<ValidationError> {
match self {
StatementObject::Agent(x) => x.validate(),
StatementObject::Group(x) => x.validate(),
StatementObject::StatementRef(x) => x.validate(),
StatementObject::SubStatement(x) => x.validate(),
StatementObject::Activity(x) => x.validate(),
}
}
}