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::UintBig,
143 Primitive::Nat8 | Primitive::Nat16 | Primitive::Nat32 | Primitive::Nat64 => {
144 ScalarKind::Uint
145 }
146 Primitive::Nat128 => ScalarKind::Uint128,
147 Primitive::Principal => ScalarKind::Principal,
148 Primitive::Subaccount => ScalarKind::Subaccount,
149 Primitive::Text => ScalarKind::Text,
150 Primitive::Timestamp => ScalarKind::Timestamp,
151 Primitive::Ulid => ScalarKind::Ulid,
152 Primitive::Unit => ScalarKind::Unit,
153 }
154}
155
156impl Primitive {
157 #[must_use]
158 pub const fn supports_arithmetic(self) -> bool {
159 primitive_scalar_kind(self).supports_arithmetic()
160 }
161
162 #[must_use]
163 pub const fn is_storage_key_encodable(self) -> bool {
164 primitive_scalar_kind(self).is_storage_key_encodable()
165 }
166
167 #[must_use]
168 pub const fn supports_remainder(self) -> bool {
169 matches!(
170 self,
171 Self::Decimal
172 | Self::Int8
173 | Self::Int16
174 | Self::Int32
175 | Self::Int64
176 | Self::Int128
177 | Self::Nat8
178 | Self::Nat16
179 | Self::Nat32
180 | Self::Nat64
181 | Self::Nat128
182 )
183 }
184
185 #[must_use]
186 pub const fn supports_copy(self) -> bool {
187 !matches!(self, Self::Blob | Self::Int | Self::Nat | Self::Text)
188 }
189
190 #[must_use]
191 pub const fn supports_hash(self) -> bool {
192 !matches!(self, Self::Blob | Self::Unit)
193 }
194
195 #[must_use]
197 pub const fn supports_numeric_value(self) -> bool {
198 matches!(
199 self,
200 Self::Date
201 | Self::Decimal
202 | Self::Duration
203 | Self::Int
204 | Self::Int8
205 | Self::Int16
206 | Self::Int32
207 | Self::Int64
208 | Self::Int128
209 | Self::Float32
210 | Self::Float64
211 | Self::Nat
212 | Self::Nat8
213 | Self::Nat16
214 | Self::Nat32
215 | Self::Nat64
216 | Self::Nat128
217 | Self::Timestamp
218 )
219 }
220
221 #[must_use]
223 pub const fn supports_ord(self) -> bool {
224 primitive_scalar_kind(self).supports_ordering()
225 }
226
227 #[must_use]
232 pub const fn is_decimal(self) -> bool {
233 matches!(self, Self::Decimal)
234 }
235
236 #[must_use]
239 pub const fn is_numeric(self) -> bool {
240 self.is_int() || self.is_float() || self.is_decimal()
241 }
242
243 #[must_use]
244 pub const fn is_float(self) -> bool {
245 matches!(self, Self::Float32 | Self::Float64)
246 }
247
248 #[must_use]
249 pub const fn is_signed_int(self) -> bool {
250 matches!(
251 self,
252 Self::Int | Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64 | Self::Int128
253 )
254 }
255
256 #[must_use]
257 pub const fn is_unsigned_int(self) -> bool {
258 matches!(
259 self,
260 Self::Nat | Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64 | Self::Nat128
261 )
262 }
263
264 #[must_use]
265 pub const fn is_int(self) -> bool {
266 self.is_signed_int() || self.is_unsigned_int()
267 }
268
269 #[must_use]
270 pub fn as_type(self) -> TokenStream {
271 let ident = format_ident!("{self:?}");
272
273 quote!(::icydb::types::#ident)
274 }
275}
276
277impl FromMeta for Primitive {
278 fn from_string(s: &str) -> Result<Self, darling::Error> {
279 s.parse::<Self>()
280 .map_err(|_| darling::Error::unknown_value(s))
281 }
282}
283
284impl ToTokens for Primitive {
285 fn to_tokens(&self, tokens: &mut TokenStream) {
286 let ident = format_ident!("{self:?}");
287
288 tokens.extend(quote!(::icydb::schema::types::Primitive::#ident));
289 }
290}