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 Int,
74 Int8,
75 Int16,
76 Int32,
77 Int64,
78 Int128,
79 Nat,
80 Nat8,
81 Nat16,
82 Nat32,
83 Nat64,
84 Nat128,
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 "Int" => Ok(Self::Int),
107 "Int8" => Ok(Self::Int8),
108 "Int16" => Ok(Self::Int16),
109 "Int32" => Ok(Self::Int32),
110 "Int64" => Ok(Self::Int64),
111 "Int128" => Ok(Self::Int128),
112 "Nat" => Ok(Self::Nat),
113 "Nat8" => Ok(Self::Nat8),
114 "Nat16" => Ok(Self::Nat16),
115 "Nat32" => Ok(Self::Nat32),
116 "Nat64" => Ok(Self::Nat64),
117 "Nat128" => Ok(Self::Nat128),
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::Int => ScalarKind::IntBig,
140 Primitive::Int8 | Primitive::Int16 | Primitive::Int32 | Primitive::Int64 => ScalarKind::Int,
141 Primitive::Int128 => ScalarKind::Int128,
142 Primitive::Nat => ScalarKind::NatBig,
143 Primitive::Nat8 | Primitive::Nat16 | Primitive::Nat32 | Primitive::Nat64 => ScalarKind::Nat,
144 Primitive::Nat128 => ScalarKind::Nat128,
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_storage_key_encodable(self) -> bool {
162 primitive_scalar_kind(self).is_storage_key_encodable()
163 }
164
165 #[must_use]
166 pub const fn supports_remainder(self) -> bool {
167 matches!(
168 self,
169 Self::Decimal
170 | Self::Int8
171 | Self::Int16
172 | Self::Int32
173 | Self::Int64
174 | Self::Int128
175 | Self::Nat8
176 | Self::Nat16
177 | Self::Nat32
178 | Self::Nat64
179 | Self::Nat128
180 )
181 }
182
183 #[must_use]
184 pub const fn supports_copy(self) -> bool {
185 !matches!(self, Self::Blob | Self::Int | Self::Nat | Self::Text)
186 }
187
188 #[must_use]
189 pub const fn supports_hash(self) -> bool {
190 !matches!(self, Self::Blob | Self::Unit)
191 }
192
193 #[must_use]
195 pub const fn supports_numeric_value(self) -> bool {
196 matches!(
197 self,
198 Self::Date
199 | Self::Decimal
200 | Self::Duration
201 | Self::Int
202 | Self::Int8
203 | Self::Int16
204 | Self::Int32
205 | Self::Int64
206 | Self::Int128
207 | Self::Float32
208 | Self::Float64
209 | Self::Nat
210 | Self::Nat8
211 | Self::Nat16
212 | Self::Nat32
213 | Self::Nat64
214 | Self::Nat128
215 | Self::Timestamp
216 )
217 }
218
219 #[must_use]
221 pub const fn supports_ord(self) -> bool {
222 primitive_scalar_kind(self).supports_ordering()
223 }
224
225 #[must_use]
230 pub const fn is_decimal(self) -> bool {
231 matches!(self, Self::Decimal)
232 }
233
234 #[must_use]
237 pub const fn is_numeric(self) -> bool {
238 self.is_int() || self.is_float() || self.is_decimal()
239 }
240
241 #[must_use]
242 pub const fn is_float(self) -> bool {
243 matches!(self, Self::Float32 | Self::Float64)
244 }
245
246 #[must_use]
247 pub const fn is_signed_int(self) -> bool {
248 matches!(
249 self,
250 Self::Int | Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64 | Self::Int128
251 )
252 }
253
254 #[must_use]
255 pub const fn is_unsigned_int(self) -> bool {
256 matches!(
257 self,
258 Self::Nat | Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64 | Self::Nat128
259 )
260 }
261
262 #[must_use]
263 pub const fn is_int(self) -> bool {
264 self.is_signed_int() || self.is_unsigned_int()
265 }
266
267 #[must_use]
268 pub fn as_type(self) -> TokenStream {
269 let ident = format_ident!("{self:?}");
270
271 quote!(::icydb::types::#ident)
272 }
273}
274
275impl FromMeta for Primitive {
276 fn from_string(s: &str) -> Result<Self, darling::Error> {
277 s.parse::<Self>()
278 .map_err(|_| darling::Error::unknown_value(s))
279 }
280}
281
282impl ToTokens for Primitive {
283 fn to_tokens(&self, tokens: &mut TokenStream) {
284 let ident = format_ident!("{self:?}");
285
286 tokens.extend(quote!(::icydb::schema::types::Primitive::#ident));
287 }
288}