use std::fmt::Display;
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[cfg(feature = "typescript")]
use ts_rs::TS;
#[derive(
Default,
Debug,
Clone,
Hash,
PartialEq,
Eq,
Ord,
PartialOrd,
BorshSerialize,
BorshDeserialize,
)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "typescript", derive(TS))]
#[cfg_attr(feature = "typescript", ts(export, type = "string"))]
pub enum SchemaType {
#[default]
Governance,
Type(String),
TrackerSchemas,
}
#[cfg_attr(feature = "typescript", derive(TS))]
#[cfg_attr(feature = "typescript", ts(export))]
pub enum ReservedWords {
TrackerSchemas,
Governance,
Any,
Witnesses,
Owner,
}
impl Display for ReservedWords {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::TrackerSchemas => write!(f, "tracker_schemas"),
Self::Governance => write!(f, "governance"),
Self::Any => write!(f, "Any"),
Self::Witnesses => write!(f, "Witnesses"),
Self::Owner => write!(f, "Owner"),
}
}
}
impl std::str::FromStr for SchemaType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err("Schema_id can not be empty".to_string());
}
match s {
"governance" => Ok(Self::Governance),
"tracker_schemas" => Ok(Self::TrackerSchemas),
_ => Ok(Self::Type(s.to_string())),
}
}
}
impl SchemaType {
pub const fn len(&self) -> usize {
match self {
Self::Governance => "governance".len(),
Self::Type(schema_id) => schema_id.len(),
Self::TrackerSchemas => "tracker_schemas".len(),
}
}
pub const fn is_empty(&self) -> bool {
match self {
Self::Governance => false,
Self::Type(schschema_id) => schschema_id.is_empty(),
Self::TrackerSchemas => false,
}
}
pub fn is_valid(&self) -> bool {
match self {
Self::Governance => true,
Self::TrackerSchemas => true,
Self::Type(schema_id) => {
!schema_id.is_empty()
&& schema_id != &ReservedWords::Governance.to_string()
&& schema_id != &ReservedWords::TrackerSchemas.to_string()
&& schema_id.trim().len() == schema_id.len()
}
}
}
pub fn is_valid_in_request(&self) -> bool {
match self {
Self::Governance => true,
Self::TrackerSchemas => false,
Self::Type(schema_id) => {
!schema_id.is_empty()
&& schema_id != &ReservedWords::Governance.to_string()
&& schema_id != &ReservedWords::TrackerSchemas.to_string()
&& schema_id.trim().len() == schema_id.len()
}
}
}
}
impl Display for SchemaType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::TrackerSchemas => write!(f, "tracker_schemas"),
Self::Governance => write!(f, "governance"),
Self::Type(schema_id) => write!(f, "{}", schema_id),
}
}
}
impl SchemaType {
pub const fn is_gov(&self) -> bool {
matches!(self, Self::Governance)
}
}
impl<'de> Deserialize<'de> for SchemaType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = <String as serde::Deserialize>::deserialize(deserializer)?;
if s.is_empty() {
return Err(serde::de::Error::custom(
"Schema can not be empty".to_string(),
));
}
Ok(match s.as_str() {
"governance" => Self::Governance,
"tracker_schemas" => Self::TrackerSchemas,
_ => Self::Type(s),
})
}
}
impl Serialize for SchemaType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::TrackerSchemas => serializer.serialize_str("tracker_schemas"),
Self::Governance => serializer.serialize_str("governance"),
Self::Type(schema) => serializer.serialize_str(schema),
}
}
}