icydb_schema/
types.rs

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///
9/// Cardinality
10///
11
12#[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        let sp = paths().schema;
33
34        tokens.extend(quote!(#sp::types::Cardinality::#ident));
35    }
36}
37
38///
39/// Primitive
40///
41
42#[derive(
43    CandidType, Clone, Copy, Debug, Deserialize, Display, Eq, PartialEq, FromStr, Serialize,
44)]
45#[remain::sorted]
46pub enum Primitive {
47    Account,
48    Blob,
49    Bool,
50    Date,
51    Decimal,
52    Duration,
53    E8s,
54    E18s,
55    Float32,
56    Float64,
57    Int,
58    Int8,
59    Int16,
60    Int32,
61    Int64,
62    Int128,
63    Nat,
64    Nat8,
65    Nat16,
66    Nat32,
67    Nat64,
68    Nat128,
69    Principal,
70    Subaccount,
71    Text,
72    Timestamp,
73    Ulid,
74    Unit,
75}
76
77impl Primitive {
78    #[must_use]
79    pub const fn supports_arithmetic(self) -> bool {
80        self.is_int() || self.is_fixed_point() || self.is_decimal()
81    }
82
83    #[must_use]
84    pub const fn supports_copy(self) -> bool {
85        !matches!(self, Self::Blob | Self::Int | Self::Nat | Self::Text)
86    }
87
88    #[must_use]
89    pub const fn supports_display(self) -> bool {
90        !matches!(self, Self::Blob | Self::Unit)
91    }
92
93    #[must_use]
94    pub const fn supports_hash(self) -> bool {
95        !matches!(self, Self::Blob | Self::Unit)
96    }
97
98    // Int and Nat are unbounded integers so have no native representation
99    #[must_use]
100    pub const fn supports_num_cast(self) -> bool {
101        matches!(
102            self,
103            Self::Date
104                | Self::Decimal
105                | Self::Duration
106                | Self::E8s
107                | Self::E18s
108                | Self::Int8
109                | Self::Int16
110                | Self::Int32
111                | Self::Int64
112                | Self::Float32
113                | Self::Float64
114                | Self::Nat8
115                | Self::Nat16
116                | Self::Nat32
117                | Self::Nat64
118                | Self::Timestamp
119        )
120    }
121
122    // both Ord and PartialOrd
123    #[must_use]
124    pub const fn supports_ord(self) -> bool {
125        !matches!(self, Self::Blob | Self::Unit)
126    }
127
128    //
129    // grouped helpers
130    //
131
132    #[must_use]
133    pub const fn is_decimal(self) -> bool {
134        matches!(self, Self::Decimal)
135    }
136
137    // is_numeric
138    // Includes ints, floats, fixed‑point (E8s/E18s), and Decimal.
139    #[must_use]
140    pub const fn is_numeric(self) -> bool {
141        self.is_int() || self.is_float() || self.is_fixed_point() || self.is_decimal()
142    }
143
144    #[must_use]
145    pub const fn is_float(self) -> bool {
146        matches!(self, Self::Float32 | Self::Float64)
147    }
148
149    #[must_use]
150    pub const fn is_signed_int(self) -> bool {
151        matches!(
152            self,
153            Self::Int | Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64
154        )
155    }
156
157    #[must_use]
158    pub const fn is_unsigned_int(self) -> bool {
159        matches!(
160            self,
161            Self::Nat | Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64
162        )
163    }
164
165    #[must_use]
166    pub const fn is_int(self) -> bool {
167        self.is_signed_int() || self.is_unsigned_int()
168    }
169
170    #[must_use]
171    pub const fn is_fixed_point(self) -> bool {
172        matches!(self, Self::E8s | Self::E18s)
173    }
174
175    #[must_use]
176    pub fn as_type(self) -> TokenStream {
177        let ident = format_ident!("{self}");
178        let cp = paths().core;
179
180        quote!(#cp::types::#ident)
181    }
182
183    #[must_use]
184    pub fn num_cast_fn(self) -> String {
185        match self {
186            Self::E18s => "u128",
187            Self::Float32 => "f32",
188            Self::Float64 | Self::Decimal => "f64",
189            Self::Int8 => "i8",
190            Self::Int16 => "i16",
191            Self::Int32 | Self::Date => "i32",
192            Self::Int64 => "i64",
193            Self::Nat8 => "u8",
194            Self::Nat16 => "u16",
195            Self::Nat32 => "u32",
196            Self::Nat64 | Self::Duration | Self::E8s | Self::Timestamp => "u64",
197            _ => panic!("unexpected primitive type"),
198        }
199        .into()
200    }
201}
202
203impl FromMeta for Primitive {
204    fn from_string(s: &str) -> Result<Self, darling::Error> {
205        s.parse::<Self>()
206            .map_err(|_| darling::Error::unknown_value(s))
207    }
208}
209
210impl ToTokens for Primitive {
211    fn to_tokens(&self, tokens: &mut TokenStream) {
212        let ident = format_ident!("{self}");
213        let sp = paths().schema;
214
215        tokens.extend(quote!(#sp::types::Primitive::#ident));
216    }
217}
218
219///
220/// StoreType
221///
222
223#[derive(CandidType, Clone, Copy, Debug, Deserialize, Display, FromStr, Serialize)]
224pub enum StoreType {
225    Data,
226    Index,
227}
228
229impl FromMeta for StoreType {
230    fn from_string(s: &str) -> Result<Self, darling::Error> {
231        s.parse::<Self>()
232            .map_err(|_| darling::Error::unknown_value(s))
233    }
234}
235
236impl ToTokens for StoreType {
237    fn to_tokens(&self, tokens: &mut TokenStream) {
238        let ident = format_ident!("{self}");
239        let sp = paths().schema;
240
241        tokens.extend(quote!(#sp::types::StoreType::#ident));
242    }
243}