1use std::fmt::Display;
4
5use borsh::{BorshDeserialize, BorshSerialize};
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7#[cfg(feature = "openapi")]
8use utoipa::ToSchema;
9
10#[cfg(feature = "typescript")]
11use ts_rs::TS;
12
13#[derive(
18 Default,
19 Debug,
20 Clone,
21 Hash,
22 PartialEq,
23 Eq,
24 Ord,
25 PartialOrd,
26 BorshSerialize,
27 BorshDeserialize,
28)]
29#[cfg_attr(feature = "openapi", derive(ToSchema))]
30#[cfg_attr(feature = "typescript", derive(TS))]
32#[cfg_attr(feature = "typescript", ts(export, type = "string"))]
33pub enum SchemaType {
34 #[default]
35 Governance,
36 Type(String),
37 TrackerSchemas,
38}
39
40#[cfg_attr(feature = "typescript", derive(TS))]
41#[cfg_attr(feature = "typescript", ts(export))]
42pub enum ReservedWords {
43 TrackerSchemas,
44 Governance,
45 Any,
46 Witnesses,
47 Owner,
48}
49
50impl Display for ReservedWords {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 match self {
53 Self::TrackerSchemas => write!(f, "tracker_schemas"),
54 Self::Governance => write!(f, "governance"),
55 Self::Any => write!(f, "Any"),
56 Self::Witnesses => write!(f, "Witnesses"),
57 Self::Owner => write!(f, "Owner"),
58 }
59 }
60}
61
62impl std::str::FromStr for SchemaType {
63 type Err = String;
64
65 fn from_str(s: &str) -> Result<Self, Self::Err> {
66 if s.is_empty() {
68 return Err("Schema_id can not be empty".to_string());
69 }
70
71 match s {
72 "governance" => Ok(Self::Governance),
73 "tracker_schemas" => Ok(Self::TrackerSchemas),
74 _ => Ok(Self::Type(s.to_string())),
75 }
76 }
77}
78
79impl SchemaType {
80 pub const fn len(&self) -> usize {
82 match self {
83 Self::Governance => "governance".len(),
84 Self::Type(schema_id) => schema_id.len(),
85 Self::TrackerSchemas => "tracker_schemas".len(),
86 }
87 }
88
89 pub const fn is_empty(&self) -> bool {
91 match self {
92 Self::Governance => false,
93 Self::Type(schschema_id) => schschema_id.is_empty(),
94 Self::TrackerSchemas => false,
95 }
96 }
97
98 pub fn is_valid(&self) -> bool {
100 match self {
101 Self::Governance => true,
102 Self::TrackerSchemas => true,
103 Self::Type(schema_id) => {
104 !schema_id.is_empty()
105 && schema_id != &ReservedWords::Governance.to_string()
106 && schema_id != &ReservedWords::TrackerSchemas.to_string()
107 && schema_id.trim().len() == schema_id.len()
108 }
109 }
110 }
111
112 pub fn is_valid_in_request(&self) -> bool {
114 match self {
115 Self::Governance => true,
116 Self::TrackerSchemas => false,
117 Self::Type(schema_id) => {
118 !schema_id.is_empty()
119 && schema_id != &ReservedWords::Governance.to_string()
120 && schema_id != &ReservedWords::TrackerSchemas.to_string()
121 && schema_id.trim().len() == schema_id.len()
122 }
123 }
124 }
125}
126
127impl Display for SchemaType {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 match self {
130 Self::TrackerSchemas => write!(f, "tracker_schemas"),
131 Self::Governance => write!(f, "governance"),
132 Self::Type(schema_id) => write!(f, "{}", schema_id),
133 }
134 }
135}
136
137impl SchemaType {
138 pub const fn is_gov(&self) -> bool {
140 matches!(self, Self::Governance)
141 }
142}
143
144impl<'de> Deserialize<'de> for SchemaType {
145 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
146 where
147 D: Deserializer<'de>,
148 {
149 let s = <String as serde::Deserialize>::deserialize(deserializer)?;
150 if s.is_empty() {
151 return Err(serde::de::Error::custom(
152 "Schema can not be empty".to_string(),
153 ));
154 }
155
156 Ok(match s.as_str() {
157 "governance" => Self::Governance,
158 "tracker_schemas" => Self::TrackerSchemas,
159 _ => Self::Type(s),
160 })
161 }
162}
163
164impl Serialize for SchemaType {
165 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
166 where
167 S: Serializer,
168 {
169 match self {
170 Self::TrackerSchemas => serializer.serialize_str("tracker_schemas"),
171 Self::Governance => serializer.serialize_str("governance"),
172 Self::Type(schema) => serializer.serialize_str(schema),
173 }
174 }
175}