use syn::{Ident, Type};
use super::TupleElement;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DateTimeUnit {
Milliseconds,
Microseconds,
Nanoseconds,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DurationSource {
Std,
Chrono,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumericKind {
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
U64,
U128,
F32,
F64,
ISize,
USize,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroISize,
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUSize,
}
impl NumericKind {
pub const fn storage_kind(self) -> StorageNumericKind {
match self {
Self::I8 | Self::NonZeroI8 => StorageNumericKind::I8,
Self::I16 | Self::NonZeroI16 => StorageNumericKind::I16,
Self::I32 | Self::NonZeroI32 => StorageNumericKind::I32,
Self::I64 | Self::NonZeroI64 => StorageNumericKind::I64,
Self::I128 | Self::NonZeroI128 => StorageNumericKind::I128,
Self::U8 | Self::NonZeroU8 => StorageNumericKind::U8,
Self::U16 | Self::NonZeroU16 => StorageNumericKind::U16,
Self::U32 | Self::NonZeroU32 => StorageNumericKind::U32,
Self::U64 | Self::NonZeroU64 => StorageNumericKind::U64,
Self::U128 | Self::NonZeroU128 => StorageNumericKind::U128,
Self::F32 => StorageNumericKind::F32,
Self::F64 => StorageNumericKind::F64,
Self::ISize | Self::NonZeroISize => StorageNumericKind::ISize,
Self::USize | Self::NonZeroUSize => StorageNumericKind::USize,
}
}
pub const fn is_widened(self) -> bool {
matches!(
self.storage_kind(),
StorageNumericKind::ISize | StorageNumericKind::USize
)
}
pub const fn is_nonzero(self) -> bool {
matches!(
self,
Self::NonZeroI8
| Self::NonZeroI16
| Self::NonZeroI32
| Self::NonZeroI64
| Self::NonZeroI128
| Self::NonZeroISize
| Self::NonZeroU8
| Self::NonZeroU16
| Self::NonZeroU32
| Self::NonZeroU64
| Self::NonZeroU128
| Self::NonZeroUSize
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StorageNumericKind {
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
U64,
U128,
F32,
F64,
ISize,
USize,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StringyBase {
String,
BorrowedStr,
CowStr,
Struct(Type),
Generic(Ident),
}
impl StringyBase {
pub const fn is_string(&self) -> bool {
matches!(self, Self::String)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DisplayBase {
Inherent,
Struct(Type),
Generic(Ident),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DecimalBackend {
RuntimeKnown,
Generic(Ident),
Struct(Type),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LeafSpec {
Numeric(NumericKind),
String,
Bool,
DateTime(DateTimeUnit),
NaiveDateTime(DateTimeUnit),
NaiveDate,
NaiveTime,
Duration {
unit: DateTimeUnit,
source: DurationSource,
},
Decimal {
precision: u8,
scale: u8,
backend: DecimalBackend,
},
AsString(DisplayBase),
AsStr(StringyBase),
Binary,
Struct(Type),
Generic(Ident),
Tuple(Vec<TupleElement>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PrimitiveLeaf<'a> {
Numeric(NumericKind),
String,
Bool,
Binary,
DateTime(DateTimeUnit),
NaiveDateTime(DateTimeUnit),
NaiveDate,
NaiveTime,
Duration {
unit: DateTimeUnit,
source: DurationSource,
},
Decimal {
precision: u8,
scale: u8,
},
AsString,
AsStr(&'a StringyBase),
}
impl PrimitiveLeaf<'_> {
pub const fn is_copy(self) -> bool {
matches!(
self,
Self::Numeric(_)
| Self::Bool
| Self::NaiveDate
| Self::NaiveTime
| Self::NaiveDateTime(_)
| Self::Duration { .. }
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NestedLeaf<'a> {
Struct(&'a Type),
Generic(&'a Ident),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TerminalLeafRoute<'a> {
Primitive(PrimitiveLeaf<'a>),
Nested(NestedLeaf<'a>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TerminalLeafSpec(LeafSpec);
impl TerminalLeafSpec {
pub fn new(leaf: LeafSpec) -> Option<Self> {
leaf.terminal_route()?;
Some(Self(leaf))
}
pub const fn route(&self) -> TerminalLeafRoute<'_> {
self.0
.terminal_route()
.expect("TerminalLeafSpec invariant violated")
}
pub const fn as_leaf_spec(&self) -> &LeafSpec {
&self.0
}
}
impl LeafSpec {
pub const fn terminal_route(&self) -> Option<TerminalLeafRoute<'_>> {
match self {
Self::Numeric(kind) => {
Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::Numeric(*kind)))
}
Self::String => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::String)),
Self::Bool => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::Bool)),
Self::DateTime(unit) => {
Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::DateTime(*unit)))
}
Self::NaiveDateTime(unit) => Some(TerminalLeafRoute::Primitive(
PrimitiveLeaf::NaiveDateTime(*unit),
)),
Self::NaiveDate => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::NaiveDate)),
Self::NaiveTime => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::NaiveTime)),
Self::Duration { unit, source } => {
Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::Duration {
unit: *unit,
source: *source,
}))
}
Self::Decimal {
precision, scale, ..
} => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::Decimal {
precision: *precision,
scale: *scale,
})),
Self::AsString(_) => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::AsString)),
Self::AsStr(stringy) => {
Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::AsStr(stringy)))
}
Self::Binary => Some(TerminalLeafRoute::Primitive(PrimitiveLeaf::Binary)),
Self::Struct(ty) => Some(TerminalLeafRoute::Nested(NestedLeaf::Struct(ty))),
Self::Generic(ident) => Some(TerminalLeafRoute::Nested(NestedLeaf::Generic(ident))),
Self::Tuple(_) => None,
}
}
#[allow(dead_code)]
pub const fn is_tuple(&self) -> bool {
matches!(self, Self::Tuple(_))
}
}