1use crate::prelude::*;
2use candid::CandidType;
3use darling::FromMeta;
4use derive_more::{Display, FromStr};
5use icydb_primitives::ScalarKind;
6use proc_macro2::TokenStream;
7use quote::{ToTokens, format_ident, quote};
8
9#[derive(
19 CandidType, Clone, Copy, Default, Debug, Deserialize, Display, Eq, FromStr, PartialEq, Serialize,
20)]
21pub enum Cardinality {
22 #[default]
23 One,
24 Opt,
25 Many,
26}
27
28impl FromMeta for Cardinality {
29 fn from_string(s: &str) -> Result<Self, darling::Error> {
30 s.parse::<Self>()
31 .map_err(|_| darling::Error::unknown_value(s))
32 }
33}
34
35impl ToTokens for Cardinality {
36 fn to_tokens(&self, tokens: &mut TokenStream) {
37 let ident = format_ident!("{self}");
38
39 tokens.extend(quote!(::icydb::schema::types::Cardinality::#ident));
40 }
41}
42
43#[derive(
52 CandidType, Clone, Copy, Debug, Deserialize, Display, Eq, PartialEq, FromStr, Serialize,
53)]
54#[remain::sorted]
55pub enum Primitive {
56 Account,
57 Blob,
58 Bool,
59 Date,
60 Decimal,
61 Duration,
62 Float32,
63 Float64,
64 Int,
65 Int8,
66 Int16,
67 Int32,
68 Int64,
69 Int128,
70 Nat,
71 Nat8,
72 Nat16,
73 Nat32,
74 Nat64,
75 Nat128,
76 Principal,
77 Subaccount,
78 Text,
79 Timestamp,
80 Ulid,
81 Unit,
82}
83
84const fn primitive_scalar_kind(primitive: Primitive) -> ScalarKind {
85 match primitive {
86 Primitive::Account => ScalarKind::Account,
87 Primitive::Blob => ScalarKind::Blob,
88 Primitive::Bool => ScalarKind::Bool,
89 Primitive::Date => ScalarKind::Date,
90 Primitive::Decimal => ScalarKind::Decimal,
91 Primitive::Duration => ScalarKind::Duration,
92 Primitive::Float32 => ScalarKind::Float32,
93 Primitive::Float64 => ScalarKind::Float64,
94 Primitive::Int => ScalarKind::IntBig,
95 Primitive::Int8 | Primitive::Int16 | Primitive::Int32 | Primitive::Int64 => ScalarKind::Int,
96 Primitive::Int128 => ScalarKind::Int128,
97 Primitive::Nat => ScalarKind::UintBig,
98 Primitive::Nat8 | Primitive::Nat16 | Primitive::Nat32 | Primitive::Nat64 => {
99 ScalarKind::Uint
100 }
101 Primitive::Nat128 => ScalarKind::Uint128,
102 Primitive::Principal => ScalarKind::Principal,
103 Primitive::Subaccount => ScalarKind::Subaccount,
104 Primitive::Text => ScalarKind::Text,
105 Primitive::Timestamp => ScalarKind::Timestamp,
106 Primitive::Ulid => ScalarKind::Ulid,
107 Primitive::Unit => ScalarKind::Unit,
108 }
109}
110
111impl Primitive {
112 #[must_use]
113 pub const fn supports_arithmetic(self) -> bool {
114 primitive_scalar_kind(self).supports_arithmetic()
115 }
116
117 #[must_use]
118 pub const fn is_storage_key_encodable(self) -> bool {
119 primitive_scalar_kind(self).is_storage_key_encodable()
120 }
121
122 #[must_use]
123 pub const fn supports_remainder(self) -> bool {
124 matches!(
125 self,
126 Self::Decimal
127 | Self::Int8
128 | Self::Int16
129 | Self::Int32
130 | Self::Int64
131 | Self::Int128
132 | Self::Nat8
133 | Self::Nat16
134 | Self::Nat32
135 | Self::Nat64
136 | Self::Nat128
137 )
138 }
139
140 #[must_use]
141 pub const fn supports_copy(self) -> bool {
142 !matches!(self, Self::Blob | Self::Int | Self::Nat | Self::Text)
143 }
144
145 #[must_use]
146 pub const fn supports_hash(self) -> bool {
147 !matches!(self, Self::Blob | Self::Unit)
148 }
149
150 #[must_use]
152 pub const fn supports_numeric_value(self) -> bool {
153 matches!(
154 self,
155 Self::Date
156 | Self::Decimal
157 | Self::Duration
158 | Self::Int
159 | Self::Int8
160 | Self::Int16
161 | Self::Int32
162 | Self::Int64
163 | Self::Int128
164 | Self::Float32
165 | Self::Float64
166 | Self::Nat
167 | Self::Nat8
168 | Self::Nat16
169 | Self::Nat32
170 | Self::Nat64
171 | Self::Nat128
172 | Self::Timestamp
173 )
174 }
175
176 #[must_use]
178 pub const fn supports_ord(self) -> bool {
179 primitive_scalar_kind(self).supports_ordering()
180 }
181
182 #[must_use]
187 pub const fn is_decimal(self) -> bool {
188 matches!(self, Self::Decimal)
189 }
190
191 #[must_use]
194 pub const fn is_numeric(self) -> bool {
195 self.is_int() || self.is_float() || self.is_decimal()
196 }
197
198 #[must_use]
199 pub const fn is_float(self) -> bool {
200 matches!(self, Self::Float32 | Self::Float64)
201 }
202
203 #[must_use]
204 pub const fn is_signed_int(self) -> bool {
205 matches!(
206 self,
207 Self::Int | Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64 | Self::Int128
208 )
209 }
210
211 #[must_use]
212 pub const fn is_unsigned_int(self) -> bool {
213 matches!(
214 self,
215 Self::Nat | Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64 | Self::Nat128
216 )
217 }
218
219 #[must_use]
220 pub const fn is_int(self) -> bool {
221 self.is_signed_int() || self.is_unsigned_int()
222 }
223
224 #[must_use]
225 pub fn as_type(self) -> TokenStream {
226 let ident = format_ident!("{self}");
227
228 quote!(::icydb::types::#ident)
229 }
230}
231
232impl FromMeta for Primitive {
233 fn from_string(s: &str) -> Result<Self, darling::Error> {
234 s.parse::<Self>()
235 .map_err(|_| darling::Error::unknown_value(s))
236 }
237}
238
239impl ToTokens for Primitive {
240 fn to_tokens(&self, tokens: &mut TokenStream) {
241 let ident = format_ident!("{self}");
242
243 tokens.extend(quote!(::icydb::schema::types::Primitive::#ident));
244 }
245}