use crate::{Error, Field, Type, Value};
use core::fmt;
type IsVarHelper = fn(&Value<'_>) -> bool;
#[derive(Debug, Clone, PartialEq)]
pub enum Variant {
Unit(UnitVariant),
Tuple(TupleVariant),
Struct(StructVariant),
}
impl Variant {
pub fn name(&self) -> &str {
match self {
Variant::Unit(var) => var.name(),
Variant::Tuple(var) => var.name(),
Variant::Struct(var) => var.name(),
}
}
pub fn assoc_ty(&self) -> Type {
match self {
Variant::Unit(var) => var.assoc_ty(),
Variant::Tuple(var) => var.assoc_ty(),
Variant::Struct(var) => var.assoc_ty(),
}
}
pub fn is_variant(&self, val: &Value<'_>) -> Result<bool, Error> {
match self {
Variant::Unit(variant) => variant.is_variant(val),
Variant::Tuple(variant) => variant.is_variant(val),
Variant::Struct(variant) => variant.is_variant(val),
}
}
}
#[derive(Clone)]
pub struct UnitVariant {
name: &'static str,
assoc_ty: Type,
is_var: IsVarHelper,
}
impl UnitVariant {
pub unsafe fn new(name: &'static str, assoc_ty: Type, is_var: IsVarHelper) -> UnitVariant {
UnitVariant {
name,
assoc_ty,
is_var,
}
}
pub fn name(&self) -> &str {
self.name
}
pub fn assoc_ty(&self) -> Type {
self.assoc_ty
}
pub fn is_variant(&self, val: &Value<'_>) -> Result<bool, Error> {
if val.ty() == self.assoc_ty() {
Ok((self.is_var)(val))
} else {
Err(Error::wrong_type(val.ty(), self.assoc_ty()))
}
}
}
impl PartialEq for UnitVariant {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.assoc_ty == other.assoc_ty
}
}
impl fmt::Debug for UnitVariant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"UnitVariant {{ name: {:?}, assoc_ty: {:?}, is_var: {:p} }}",
self.name, self.assoc_ty, self.is_var as *const ()
)
}
}
#[derive(Clone)]
pub struct TupleVariant {
name: &'static str,
assoc_ty: Type,
fields: fn() -> Vec<Field>,
is_var: IsVarHelper,
}
impl TupleVariant {
pub unsafe fn new(
name: &'static str,
assoc_ty: Type,
fields: fn() -> Vec<Field>,
is_var: IsVarHelper,
) -> TupleVariant {
TupleVariant {
name,
assoc_ty,
fields,
is_var,
}
}
pub fn name(&self) -> &str {
self.name
}
pub fn assoc_ty(&self) -> Type {
self.assoc_ty
}
pub fn fields(&self) -> Vec<Field> {
(self.fields)()
}
pub fn is_variant(&self, val: &Value<'_>) -> Result<bool, Error> {
if val.ty() == self.assoc_ty() {
Ok((self.is_var)(val))
} else {
Err(Error::wrong_type(val.ty(), self.assoc_ty()))
}
}
}
impl PartialEq for TupleVariant {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.assoc_ty == other.assoc_ty
}
}
impl fmt::Debug for TupleVariant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"TupleVariant {{ name: {:?}, assoc_ty: {:?}, fields: {:?}, is_var: {:p} }}",
self.name, self.assoc_ty, self.fields, self.is_var as *const ()
)
}
}
#[derive(Clone)]
pub struct StructVariant {
name: &'static str,
assoc_ty: Type,
fields: fn() -> Vec<Field>,
is_var: IsVarHelper,
}
impl StructVariant {
pub unsafe fn new(
name: &'static str,
assoc_ty: Type,
fields: fn() -> Vec<Field>,
is_var: IsVarHelper,
) -> StructVariant {
StructVariant {
name,
assoc_ty,
fields,
is_var,
}
}
pub fn name(&self) -> &str {
self.name
}
pub fn assoc_ty(&self) -> Type {
self.assoc_ty
}
pub fn fields(&self) -> Vec<Field> {
(self.fields)()
}
pub fn is_variant(&self, val: &Value<'_>) -> Result<bool, Error> {
if val.ty() == self.assoc_ty() {
Ok((self.is_var)(val))
} else {
Err(Error::wrong_type(val.ty(), self.assoc_ty()))
}
}
}
impl PartialEq for StructVariant {
fn eq(&self, other: &Self) -> bool {
self.name == other.name && self.assoc_ty == other.assoc_ty
}
}
impl fmt::Debug for StructVariant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"StructVariant {{ name: {:?}, assoc_ty: {:?}, fields: {:?}, is_var: {:p} }}",
self.name, self.assoc_ty, self.fields, self.is_var as *const ()
)
}
}