use activitystreams_vocabulary::{
ActivityVocabulary, VocabularyTypes as ActivityStreamsVocabularyTypes,
impl_activity_vocabulary, impl_default, impl_display, impl_into_vocabulary,
};
use serde::{Deserialize, Serialize};
use crate::{Error, Result};
mod activity;
mod actor;
mod object;
pub use activity::ActivityType;
pub use actor::{ActorType, ActorTypes};
pub use object::ObjectType;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum VocabularyType {
Activity(ActivityType),
Actor(ActorType),
Object(ObjectType),
}
impl VocabularyType {
pub const fn new() -> Self {
Self::Activity(ActivityType::new())
}
pub const fn as_str(&self) -> &'static str {
match self {
Self::Activity(ty) => ty.as_str(),
Self::Actor(ty) => ty.as_str(),
Self::Object(ty) => ty.as_str(),
}
}
#[inline]
pub fn activity<I: Into<ActivityType>>(val: I) -> Self {
Self::Activity(val.into())
}
pub const fn is_activity(&self) -> bool {
matches!(self, Self::Activity(_))
}
pub fn as_activity(&self) -> Result<ActivityType> {
match self {
Self::Activity(ty) => Ok(*ty),
ty => Err(Error::vocabulary(format!(
"not a valid activity type: {ty}"
))),
}
}
#[inline]
pub fn actor<I: Into<ActorType>>(val: I) -> Self {
Self::Actor(val.into())
}
pub const fn is_actor(&self) -> bool {
matches!(self, Self::Actor(_))
}
pub fn as_actor(&self) -> Result<ActorType> {
match self {
Self::Actor(ty) => Ok(*ty),
ty => Err(Error::vocabulary(format!("not a valid actor type: {ty}"))),
}
}
#[inline]
pub fn object<I: Into<ObjectType>>(val: I) -> Self {
Self::Object(val.into())
}
pub const fn is_object(&self) -> bool {
matches!(self, Self::Object(_))
}
pub fn as_object(&self) -> Result<ObjectType> {
match self {
Self::Object(ty) => Ok(*ty),
ty => Err(Error::vocabulary(format!("not a valid object type: {ty}"))),
}
}
}
impl From<ActivityType> for VocabularyType {
fn from(val: ActivityType) -> Self {
Self::Activity(val)
}
}
impl From<ActorType> for VocabularyType {
fn from(val: ActorType) -> Self {
Self::Actor(val)
}
}
impl From<ObjectType> for VocabularyType {
fn from(val: ObjectType) -> Self {
Self::Object(val)
}
}
impl TryFrom<VocabularyType> for ActivityType {
type Error = Error;
fn try_from(val: VocabularyType) -> Result<Self> {
val.as_activity()
}
}
impl TryFrom<VocabularyType> for ActorType {
type Error = Error;
fn try_from(val: VocabularyType) -> Result<Self> {
val.as_actor()
}
}
impl TryFrom<VocabularyType> for ObjectType {
type Error = Error;
fn try_from(val: VocabularyType) -> Result<Self> {
val.as_object()
}
}
impl_default!(VocabularyType);
impl_display!(VocabularyType, str);
impl_activity_vocabulary!(VocabularyType);
impl_into_vocabulary!(VocabularyType);
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum VocabularyTypes {
Single(VocabularyType),
List(Vec<VocabularyType>),
}
impl VocabularyTypes {
pub const fn new() -> Self {
Self::Single(VocabularyType::new())
}
pub fn single<I: Into<VocabularyType>>(val: I) -> Self {
Self::Single(val.into())
}
pub const fn is_single(&self) -> bool {
matches!(self, Self::Single(_))
}
pub fn as_single(&self) -> Result<VocabularyType> {
match self {
Self::Single(ty) => Ok(*ty),
_ => Err(Error::vocabulary("invalid VocabularyTypes single variant")),
}
}
pub fn list<T, I>(list: I) -> Self
where
T: Into<VocabularyType>,
I: IntoIterator<Item = T>,
{
Self::List(list.into_iter().map(|i| i.into()).collect())
}
pub const fn is_list(&self) -> bool {
matches!(self, Self::List(_))
}
pub fn as_list(&self) -> Result<Vec<VocabularyType>> {
match self {
Self::List(tys) => Ok(tys.clone()),
_ => Err(Error::vocabulary("invalid VocabularyTypes list variant")),
}
}
pub fn contains<T: Into<VocabularyType>>(&self, t: T) -> bool {
let oth_ty = t.into();
match self {
Self::Single(ty) => ty == &oth_ty,
Self::List(tys) => tys.iter().any(|ty| ty == &oth_ty),
}
}
}
impl_default!(VocabularyTypes);
impl<I: Into<VocabularyType>> From<I> for VocabularyTypes {
fn from(val: I) -> Self {
Self::Single(val.into())
}
}
impl<I: Into<VocabularyType>> From<Vec<I>> for VocabularyTypes {
fn from(val: Vec<I>) -> Self {
Self::list(val)
}
}
impl<I: Into<VocabularyType>, const N: usize> From<[I; N]> for VocabularyTypes {
fn from(val: [I; N]) -> Self {
Self::list(val)
}
}
impl<I: Into<VocabularyType> + Clone, const N: usize> From<&[I; N]> for VocabularyTypes {
fn from(val: &[I; N]) -> Self {
Self::list(val.iter().cloned())
}
}
impl<I: Into<VocabularyType> + Clone> From<&[I]> for VocabularyTypes {
fn from(val: &[I]) -> Self {
Self::list(val.iter().cloned())
}
}
impl TryFrom<VocabularyTypes> for VocabularyType {
type Error = Error;
fn try_from(val: VocabularyTypes) -> Result<Self> {
val.as_single()
}
}
impl TryFrom<VocabularyTypes> for Vec<VocabularyType> {
type Error = Error;
fn try_from(val: VocabularyTypes) -> Result<Self> {
val.as_list()
}
}
impl From<VocabularyTypes> for ActivityStreamsVocabularyTypes {
fn from(val: VocabularyTypes) -> Self {
match val {
VocabularyTypes::Single(ty) => Self::Single(ty.into()),
VocabularyTypes::List(tys) => Self::List(tys.into_iter().map(|i| i.into()).collect()),
}
}
}
impl ActivityVocabulary for VocabularyTypes {
type Type = Self;
fn kind(&self) -> String {
self.to_string()
}
fn contains(&self, kind: &str) -> bool {
match self {
Self::Single(ty) => ty.as_str() == kind,
Self::List(tys) => tys.iter().any(|ty| ty.as_str() == kind),
}
}
}
impl core::fmt::Display for VocabularyTypes {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Single(ty) => write!(f, "{ty}"),
Self::List(tys) => serde_json::to_string(tys)
.map_err(|_| core::fmt::Error)
.and_then(|s| write!(f, "{s}")),
}
}
}