use crate::prelude::*;
use candid::CandidType;
use darling::FromMeta;
use icydb_primitives::ScalarKind;
use proc_macro2::TokenStream;
use quote::{ToTokens, format_ident, quote};
use std::str::FromStr;
#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub enum Cardinality {
#[default]
One,
Opt,
Many,
}
impl FromStr for Cardinality {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"One" => Ok(Self::One),
"Opt" => Ok(Self::Opt),
"Many" => Ok(Self::Many),
_ => Err("unknown Cardinality"),
}
}
}
impl FromMeta for Cardinality {
fn from_string(s: &str) -> Result<Self, darling::Error> {
s.parse::<Self>()
.map_err(|_| darling::Error::unknown_value(s))
}
}
impl ToTokens for Cardinality {
fn to_tokens(&self, tokens: &mut TokenStream) {
let ident = format_ident!("{self:?}");
tokens.extend(quote!(::icydb::schema::types::Cardinality::#ident));
}
}
#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[remain::sorted]
pub enum Primitive {
Account,
Blob,
Bool,
Date,
Decimal,
Duration,
Float32,
Float64,
Int,
Int8,
Int16,
Int32,
Int64,
Int128,
Nat,
Nat8,
Nat16,
Nat32,
Nat64,
Nat128,
Principal,
Subaccount,
Text,
Timestamp,
Ulid,
Unit,
}
impl FromStr for Primitive {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Account" => Ok(Self::Account),
"Blob" => Ok(Self::Blob),
"Bool" => Ok(Self::Bool),
"Date" => Ok(Self::Date),
"Decimal" => Ok(Self::Decimal),
"Duration" => Ok(Self::Duration),
"Float32" => Ok(Self::Float32),
"Float64" => Ok(Self::Float64),
"Int" => Ok(Self::Int),
"Int8" => Ok(Self::Int8),
"Int16" => Ok(Self::Int16),
"Int32" => Ok(Self::Int32),
"Int64" => Ok(Self::Int64),
"Int128" => Ok(Self::Int128),
"Nat" => Ok(Self::Nat),
"Nat8" => Ok(Self::Nat8),
"Nat16" => Ok(Self::Nat16),
"Nat32" => Ok(Self::Nat32),
"Nat64" => Ok(Self::Nat64),
"Nat128" => Ok(Self::Nat128),
"Principal" => Ok(Self::Principal),
"Subaccount" => Ok(Self::Subaccount),
"Text" => Ok(Self::Text),
"Timestamp" => Ok(Self::Timestamp),
"Ulid" => Ok(Self::Ulid),
"Unit" => Ok(Self::Unit),
_ => Err("unknown Primitive"),
}
}
}
const fn primitive_scalar_kind(primitive: Primitive) -> ScalarKind {
match primitive {
Primitive::Account => ScalarKind::Account,
Primitive::Blob => ScalarKind::Blob,
Primitive::Bool => ScalarKind::Bool,
Primitive::Date => ScalarKind::Date,
Primitive::Decimal => ScalarKind::Decimal,
Primitive::Duration => ScalarKind::Duration,
Primitive::Float32 => ScalarKind::Float32,
Primitive::Float64 => ScalarKind::Float64,
Primitive::Int => ScalarKind::IntBig,
Primitive::Int8 | Primitive::Int16 | Primitive::Int32 | Primitive::Int64 => ScalarKind::Int,
Primitive::Int128 => ScalarKind::Int128,
Primitive::Nat => ScalarKind::UintBig,
Primitive::Nat8 | Primitive::Nat16 | Primitive::Nat32 | Primitive::Nat64 => {
ScalarKind::Uint
}
Primitive::Nat128 => ScalarKind::Uint128,
Primitive::Principal => ScalarKind::Principal,
Primitive::Subaccount => ScalarKind::Subaccount,
Primitive::Text => ScalarKind::Text,
Primitive::Timestamp => ScalarKind::Timestamp,
Primitive::Ulid => ScalarKind::Ulid,
Primitive::Unit => ScalarKind::Unit,
}
}
impl Primitive {
#[must_use]
pub const fn supports_arithmetic(self) -> bool {
primitive_scalar_kind(self).supports_arithmetic()
}
#[must_use]
pub const fn is_storage_key_encodable(self) -> bool {
primitive_scalar_kind(self).is_storage_key_encodable()
}
#[must_use]
pub const fn supports_remainder(self) -> bool {
matches!(
self,
Self::Decimal
| Self::Int8
| Self::Int16
| Self::Int32
| Self::Int64
| Self::Int128
| Self::Nat8
| Self::Nat16
| Self::Nat32
| Self::Nat64
| Self::Nat128
)
}
#[must_use]
pub const fn supports_copy(self) -> bool {
!matches!(self, Self::Blob | Self::Int | Self::Nat | Self::Text)
}
#[must_use]
pub const fn supports_hash(self) -> bool {
!matches!(self, Self::Blob | Self::Unit)
}
#[must_use]
pub const fn supports_numeric_value(self) -> bool {
matches!(
self,
Self::Date
| Self::Decimal
| Self::Duration
| Self::Int
| Self::Int8
| Self::Int16
| Self::Int32
| Self::Int64
| Self::Int128
| Self::Float32
| Self::Float64
| Self::Nat
| Self::Nat8
| Self::Nat16
| Self::Nat32
| Self::Nat64
| Self::Nat128
| Self::Timestamp
)
}
#[must_use]
pub const fn supports_ord(self) -> bool {
primitive_scalar_kind(self).supports_ordering()
}
#[must_use]
pub const fn is_decimal(self) -> bool {
matches!(self, Self::Decimal)
}
#[must_use]
pub const fn is_numeric(self) -> bool {
self.is_int() || self.is_float() || self.is_decimal()
}
#[must_use]
pub const fn is_float(self) -> bool {
matches!(self, Self::Float32 | Self::Float64)
}
#[must_use]
pub const fn is_signed_int(self) -> bool {
matches!(
self,
Self::Int | Self::Int8 | Self::Int16 | Self::Int32 | Self::Int64 | Self::Int128
)
}
#[must_use]
pub const fn is_unsigned_int(self) -> bool {
matches!(
self,
Self::Nat | Self::Nat8 | Self::Nat16 | Self::Nat32 | Self::Nat64 | Self::Nat128
)
}
#[must_use]
pub const fn is_int(self) -> bool {
self.is_signed_int() || self.is_unsigned_int()
}
#[must_use]
pub fn as_type(self) -> TokenStream {
let ident = format_ident!("{self:?}");
quote!(::icydb::types::#ident)
}
}
impl FromMeta for Primitive {
fn from_string(s: &str) -> Result<Self, darling::Error> {
s.parse::<Self>()
.map_err(|_| darling::Error::unknown_value(s))
}
}
impl ToTokens for Primitive {
fn to_tokens(&self, tokens: &mut TokenStream) {
let ident = format_ident!("{self:?}");
tokens.extend(quote!(::icydb::schema::types::Primitive::#ident));
}
}