1use crate::prelude::*;
2use candid::CandidType;
3use darling::FromMeta;
4use derive_more::{Display, FromStr};
5use proc_macro2::TokenStream;
6use quote::{ToTokens, format_ident, quote};
7
8#[derive(
13 CandidType, Clone, Copy, Default, Debug, Deserialize, Display, Eq, FromStr, PartialEq, Serialize,
14)]
15pub enum Cardinality {
16 #[default]
17 One,
18 Opt,
19 Many,
20}
21
22impl FromMeta for Cardinality {
23 fn from_string(s: &str) -> Result<Self, darling::Error> {
24 s.parse::<Self>()
25 .map_err(|_| darling::Error::unknown_value(s))
26 }
27}
28
29impl ToTokens for Cardinality {
30 fn to_tokens(&self, tokens: &mut TokenStream) {
31 let ident = format_ident!("{self}");
32
33 tokens.extend(quote!(::icydb::schema::types::Cardinality::#ident));
34 }
35}
36
37#[derive(
42 CandidType, Clone, Copy, Debug, Deserialize, Display, Eq, PartialEq, FromStr, Serialize,
43)]
44#[remain::sorted]
45pub enum Primitive {
46 Account,
47 Blob,
48 Bool,
49 Date,
50 Decimal,
51 Duration,
52 E8s,
53 E18s,
54 Float32,
55 Float64,
56 Int,
57 Int8,
58 Int16,
59 Int32,
60 Int64,
61 Int128,
62 Nat,
63 Nat8,
64 Nat16,
65 Nat32,
66 Nat64,
67 Nat128,
68 Principal,
69 Subaccount,
70 Text,
71 Timestamp,
72 Ulid,
73 Unit,
74}
75
76impl Primitive {
77 #[must_use]
78 pub const fn supports_arithmetic(self) -> bool {
79 self.is_int() || self.is_fixed_point() || self.is_decimal()
80 }
81
82 #[must_use]
83 pub const fn supports_remainder(self) -> bool {
84 matches!(
85 self,
86 Self::Decimal
87 | Self::Int8
88 | Self::Int16
89 | Self::Int32
90 | Self::Int64
91 | Self::Int128
92 | Self::Nat8
93 | Self::Nat16
94 | Self::Nat32
95 | Self::Nat64
96 | Self::Nat128
97 )
98 }
99
100 #[must_use]
101 pub const fn supports_copy(self) -> bool {
102 !matches!(self, Self::Blob | Self::Int | Self::Nat | Self::Text)
103 }
104
105 #[must_use]
106 pub const fn supports_hash(self) -> bool {
107 !matches!(self, Self::Blob | Self::Unit)
108 }
109
110 #[must_use]
112 pub const fn supports_num_cast(self) -> bool {
113 matches!(
114 self,
115 Self::Date
116 | Self::Decimal
117 | Self::Duration
118 | Self::E8s
119 | Self::E18s
120 | Self::Int8
121 | Self::Int16
122 | Self::Int32
123 | Self::Int64
124 | Self::Float32
125 | Self::Float64
126 | Self::Nat8
127 | Self::Nat16
128 | Self::Nat32
129 | Self::Nat64
130 | Self::Timestamp
131 )
132 }
133
134 #[must_use]
136 pub const fn supports_ord(self) -> bool {
137 !matches!(self, Self::Blob | Self::Unit)
138 }
139
140 #[must_use]
145 pub const fn is_decimal(self) -> bool {
146 matches!(self, Self::Decimal)
147 }
148
149 #[must_use]
152 pub const fn is_numeric(self) -> bool {
153 self.is_int() || self.is_float() || self.is_fixed_point() || self.is_decimal()
154 }
155
156 #[must_use]
157 pub const fn is_float(self) -> bool {
158 matches!(self, Self::Float32 | Self::Float64)
159 }
160
161 #[must_use]
162 pub const fn is_signed_int(self) -> bool {
163 matches!(
164 self,
165 Self::Int | Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64 | Self::Int128
166 )
167 }
168
169 #[must_use]
170 pub const fn is_unsigned_int(self) -> bool {
171 matches!(
172 self,
173 Self::Nat | Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64 | Self::Nat128
174 )
175 }
176
177 #[must_use]
178 pub const fn is_int(self) -> bool {
179 self.is_signed_int() || self.is_unsigned_int()
180 }
181
182 #[must_use]
183 pub const fn is_fixed_point(self) -> bool {
184 matches!(self, Self::E8s | Self::E18s)
185 }
186
187 #[must_use]
188 pub fn as_type(self) -> TokenStream {
189 let ident = format_ident!("{self}");
190
191 quote!(::icydb::types::#ident)
192 }
193
194 pub fn num_cast_fn(self) -> Result<&'static str, darling::Error> {
199 match self {
200 Self::E18s => Ok("u128"),
201 Self::Float32 => Ok("f32"),
202 Self::Float64 | Self::Decimal => Ok("f64"),
203 Self::Int8 => Ok("i8"),
204 Self::Int16 => Ok("i16"),
205 Self::Int32 | Self::Date => Ok("i32"),
206 Self::Int64 => Ok("i64"),
207 Self::Nat8 => Ok("u8"),
208 Self::Nat16 => Ok("u16"),
209 Self::Nat32 => Ok("u32"),
210 Self::Nat64 | Self::Duration | Self::E8s | Self::Timestamp => Ok("u64"),
211 _ => Err(darling::Error::custom(format!(
212 "numeric cast is unsupported for primitive {self}"
213 ))),
214 }
215 }
216}
217
218impl FromMeta for Primitive {
219 fn from_string(s: &str) -> Result<Self, darling::Error> {
220 s.parse::<Self>()
221 .map_err(|_| darling::Error::unknown_value(s))
222 }
223}
224
225impl ToTokens for Primitive {
226 fn to_tokens(&self, tokens: &mut TokenStream) {
227 let ident = format_ident!("{self}");
228
229 tokens.extend(quote!(::icydb::schema::types::Primitive::#ident));
230 }
231}