1use crate::prelude::*;
2use candid::CandidType;
3use darling::FromMeta;
4use icydb_primitives::ScalarKind;
5use proc_macro2::TokenStream;
6use quote::{ToTokens, format_ident, quote};
7use std::str::FromStr;
8
9#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
19pub enum Cardinality {
20 #[default]
21 One,
22 Opt,
23 Many,
24}
25
26impl FromStr for Cardinality {
27 type Err = &'static str;
28
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 match s {
31 "One" => Ok(Self::One),
32 "Opt" => Ok(Self::Opt),
33 "Many" => Ok(Self::Many),
34 _ => Err("unknown Cardinality"),
35 }
36 }
37}
38
39impl FromMeta for Cardinality {
40 fn from_string(s: &str) -> Result<Self, darling::Error> {
41 s.parse::<Self>()
42 .map_err(|_| darling::Error::unknown_value(s))
43 }
44}
45
46impl ToTokens for Cardinality {
47 fn to_tokens(&self, tokens: &mut TokenStream) {
48 let ident = format_ident!("{self:?}");
49
50 tokens.extend(quote!(::icydb::schema::types::Cardinality::#ident));
51 }
52}
53
54#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
63#[remain::sorted]
64pub enum Primitive {
65 Account,
66 Blob,
67 Bool,
68 Date,
69 Decimal,
70 Duration,
71 Float32,
72 Float64,
73 Int8,
74 Int16,
75 Int32,
76 Int64,
77 Int128,
78 IntBig,
79 Nat8,
80 Nat16,
81 Nat32,
82 Nat64,
83 Nat128,
84 NatBig,
85 Principal,
86 Subaccount,
87 Text,
88 Timestamp,
89 Ulid,
90 Unit,
91}
92
93impl FromStr for Primitive {
94 type Err = &'static str;
95
96 fn from_str(s: &str) -> Result<Self, Self::Err> {
97 match s {
98 "Account" => Ok(Self::Account),
99 "Blob" => Ok(Self::Blob),
100 "Bool" => Ok(Self::Bool),
101 "Date" => Ok(Self::Date),
102 "Decimal" => Ok(Self::Decimal),
103 "Duration" => Ok(Self::Duration),
104 "Float32" => Ok(Self::Float32),
105 "Float64" => Ok(Self::Float64),
106 "Int8" => Ok(Self::Int8),
107 "Int16" => Ok(Self::Int16),
108 "Int32" => Ok(Self::Int32),
109 "Int64" => Ok(Self::Int64),
110 "Int128" => Ok(Self::Int128),
111 "IntBig" => Ok(Self::IntBig),
112 "Nat8" => Ok(Self::Nat8),
113 "Nat16" => Ok(Self::Nat16),
114 "Nat32" => Ok(Self::Nat32),
115 "Nat64" => Ok(Self::Nat64),
116 "Nat128" => Ok(Self::Nat128),
117 "NatBig" => Ok(Self::NatBig),
118 "Principal" => Ok(Self::Principal),
119 "Subaccount" => Ok(Self::Subaccount),
120 "Text" => Ok(Self::Text),
121 "Timestamp" => Ok(Self::Timestamp),
122 "Ulid" => Ok(Self::Ulid),
123 "Unit" => Ok(Self::Unit),
124 _ => Err("unknown Primitive"),
125 }
126 }
127}
128
129const fn primitive_scalar_kind(primitive: Primitive) -> ScalarKind {
130 match primitive {
131 Primitive::Account => ScalarKind::Account,
132 Primitive::Blob => ScalarKind::Blob,
133 Primitive::Bool => ScalarKind::Bool,
134 Primitive::Date => ScalarKind::Date,
135 Primitive::Decimal => ScalarKind::Decimal,
136 Primitive::Duration => ScalarKind::Duration,
137 Primitive::Float32 => ScalarKind::Float32,
138 Primitive::Float64 => ScalarKind::Float64,
139 Primitive::Int8 | Primitive::Int16 | Primitive::Int32 | Primitive::Int64 => ScalarKind::Int,
140 Primitive::Int128 => ScalarKind::Int128,
141 Primitive::IntBig => ScalarKind::IntBig,
142 Primitive::Nat8 | Primitive::Nat16 | Primitive::Nat32 | Primitive::Nat64 => ScalarKind::Nat,
143 Primitive::Nat128 => ScalarKind::Nat128,
144 Primitive::NatBig => ScalarKind::NatBig,
145 Primitive::Principal => ScalarKind::Principal,
146 Primitive::Subaccount => ScalarKind::Subaccount,
147 Primitive::Text => ScalarKind::Text,
148 Primitive::Timestamp => ScalarKind::Timestamp,
149 Primitive::Ulid => ScalarKind::Ulid,
150 Primitive::Unit => ScalarKind::Unit,
151 }
152}
153
154impl Primitive {
155 #[must_use]
156 pub const fn supports_arithmetic(self) -> bool {
157 primitive_scalar_kind(self).supports_arithmetic()
158 }
159
160 #[must_use]
161 pub const fn is_primary_key_component_encodable(self) -> bool {
162 primitive_scalar_kind(self).is_primary_key_component_encodable()
163 }
164
165 #[must_use]
166 pub const fn is_primary_key_encodable(self) -> bool {
167 primitive_scalar_kind(self).is_primary_key_component_encodable()
168 }
169
170 #[must_use]
171 pub const fn supports_remainder(self) -> bool {
172 matches!(
173 self,
174 Self::Decimal
175 | Self::Int8
176 | Self::Int16
177 | Self::Int32
178 | Self::Int64
179 | Self::Int128
180 | Self::Nat8
181 | Self::Nat16
182 | Self::Nat32
183 | Self::Nat64
184 | Self::Nat128
185 )
186 }
187
188 #[must_use]
189 pub const fn supports_copy(self) -> bool {
190 !matches!(self, Self::Blob | Self::IntBig | Self::NatBig | Self::Text)
191 }
192
193 #[must_use]
194 pub const fn supports_hash(self) -> bool {
195 !matches!(self, Self::Blob | Self::Unit)
196 }
197
198 #[must_use]
200 pub const fn supports_numeric_value(self) -> bool {
201 matches!(
202 self,
203 Self::Date
204 | Self::Decimal
205 | Self::Duration
206 | Self::Int8
207 | Self::Int16
208 | Self::Int32
209 | Self::Int64
210 | Self::Int128
211 | Self::IntBig
212 | Self::Float32
213 | Self::Float64
214 | Self::Nat8
215 | Self::Nat16
216 | Self::Nat32
217 | Self::Nat64
218 | Self::Nat128
219 | Self::NatBig
220 | Self::Timestamp
221 )
222 }
223
224 #[must_use]
226 pub const fn supports_ord(self) -> bool {
227 primitive_scalar_kind(self).supports_ordering()
228 }
229
230 #[must_use]
235 pub const fn is_decimal(self) -> bool {
236 matches!(self, Self::Decimal)
237 }
238
239 #[must_use]
242 pub const fn is_numeric(self) -> bool {
243 self.is_int() || self.is_float() || self.is_decimal()
244 }
245
246 #[must_use]
247 pub const fn is_float(self) -> bool {
248 matches!(self, Self::Float32 | Self::Float64)
249 }
250
251 #[must_use]
252 pub const fn is_signed_int(self) -> bool {
253 matches!(
254 self,
255 Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64 | Self::Int128 | Self::IntBig
256 )
257 }
258
259 #[must_use]
260 pub const fn is_unsigned_int(self) -> bool {
261 matches!(
262 self,
263 Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64 | Self::Nat128 | Self::NatBig
264 )
265 }
266
267 #[must_use]
268 pub const fn is_int(self) -> bool {
269 self.is_signed_int() || self.is_unsigned_int()
270 }
271}
272
273impl FromMeta for Primitive {
274 fn from_string(s: &str) -> Result<Self, darling::Error> {
275 s.parse::<Self>()
276 .map_err(|_| darling::Error::unknown_value(s))
277 }
278}
279
280impl ToTokens for Primitive {
281 fn to_tokens(&self, tokens: &mut TokenStream) {
282 let ident = format_ident!("{self:?}");
283
284 tokens.extend(quote!(::icydb::schema::types::Primitive::#ident));
285 }
286}