use ltk_meta::{property::values, traits::PropertyExt, PropertyKind, PropertyValueEnum};
use std::fmt::Display;
pub trait RitobinName {
fn from_rito_name(name: &str) -> Option<Self>
where
Self: Sized;
fn to_rito_name(&self) -> &'static str;
}
impl RitobinName for PropertyKind {
fn from_rito_name(name: &str) -> Option<Self> {
match name {
"none" => Some(Self::None),
"bool" => Some(Self::Bool),
"i8" => Some(Self::I8),
"u8" => Some(Self::U8),
"i16" => Some(Self::I16),
"u16" => Some(Self::U16),
"i32" => Some(Self::I32),
"u32" => Some(Self::U32),
"i64" => Some(Self::I64),
"u64" => Some(Self::U64),
"f32" => Some(Self::F32),
"vec2" => Some(Self::Vector2),
"vec3" => Some(Self::Vector3),
"vec4" => Some(Self::Vector4),
"mtx44" => Some(Self::Matrix44),
"rgba" => Some(Self::Color),
"string" => Some(Self::String),
"hash" => Some(Self::Hash),
"file" => Some(Self::WadChunkLink),
"list" => Some(Self::Container),
"list2" => Some(Self::UnorderedContainer),
"pointer" => Some(Self::Struct),
"embed" => Some(Self::Embedded),
"link" => Some(Self::ObjectLink),
"option" => Some(Self::Optional),
"map" => Some(Self::Map),
"flag" => Some(Self::BitBool),
_ => None,
}
}
fn to_rito_name(&self) -> &'static str {
match self {
Self::None => "none",
Self::Bool => "bool",
Self::I8 => "i8",
Self::U8 => "u8",
Self::I16 => "i16",
Self::U16 => "u16",
Self::I32 => "i32",
Self::U32 => "u32",
Self::I64 => "i64",
Self::U64 => "u64",
Self::F32 => "f32",
Self::Vector2 => "vec2",
Self::Vector3 => "vec3",
Self::Vector4 => "vec4",
Self::Matrix44 => "mtx44",
Self::Color => "rgba",
Self::String => "string",
Self::Hash => "hash",
Self::WadChunkLink => "file",
Self::Container => "list",
Self::UnorderedContainer => "list2",
Self::Struct => "pointer",
Self::Embedded => "embed",
Self::ObjectLink => "link",
Self::Optional => "option",
Self::Map => "map",
Self::BitBool => "flag",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RitoType {
pub base: PropertyKind,
pub subtypes: [Option<PropertyKind>; 2],
}
impl Display for RitoType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let base = self.base.to_rito_name();
match self.subtypes {
[None, None] => f.write_str(base),
[Some(a), None] => write!(f, "{base}[{}]", a.to_rito_name()),
[Some(a), Some(b)] => {
write!(f, "{base}[{},{}]", a.to_rito_name(), b.to_rito_name())
}
_ => write!(f, "{base}[!!]"),
}
}
}
impl RitoType {
pub fn simple(kind: PropertyKind) -> Self {
Self {
base: kind,
subtypes: [None, None],
}
}
pub fn container(value: PropertyKind) -> Self {
Self {
base: PropertyKind::Container,
subtypes: [Some(value), None],
}
}
pub fn map(key: PropertyKind, value: PropertyKind) -> Self {
Self {
base: PropertyKind::Map,
subtypes: [Some(key), Some(value)],
}
}
pub fn subtype(&self, idx: usize) -> PropertyKind {
self.subtypes[idx].unwrap_or_default()
}
pub fn value_subtype(&self) -> Option<PropertyKind> {
self.subtypes[1].or(self.subtypes[0])
}
pub fn item_shape(&self) -> Option<ItemShape> {
use PropertyKind as K;
Some(match self.base {
K::Struct | K::Embedded | K::Map => ItemShape::Entry,
K::Container | K::UnorderedContainer | K::Optional => ItemShape::Value,
K::Vector2 | K::Vector3 | K::Vector4 | K::Color | K::Matrix44 => ItemShape::Value,
_ => return None,
})
}
pub fn make_default<M: Default>(&self, span: M) -> PropertyValueEnum<M> {
let mut value = match self.base {
PropertyKind::Map => {
PropertyValueEnum::Map(values::Map::empty(self.subtype(0), self.subtype(1)))
}
PropertyKind::UnorderedContainer => {
PropertyValueEnum::UnorderedContainer(values::UnorderedContainer(
values::Container::empty(self.subtype(0)).unwrap_or_default(),
))
}
PropertyKind::Container => PropertyValueEnum::Container(
values::Container::empty(self.subtype(0)).unwrap_or_default(),
),
PropertyKind::Optional => PropertyValueEnum::Optional(
values::Optional::empty(self.subtype(0)).unwrap_or_default(),
),
_ => self.base.default_value(),
};
*value.meta_mut() = span;
value
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum ItemShape {
Entry,
Value,
}
impl Display for ItemShape {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
ItemShape::Entry => "an entry ('name: type = value')",
ItemShape::Value => "a value",
})
}
}
pub trait PropertyValueExt {
fn rito_type(&self) -> RitoType;
}
impl<M> PropertyValueExt for PropertyValueEnum<M> {
fn rito_type(&self) -> RitoType {
let base = self.kind();
let subtypes = match self {
PropertyValueEnum::Map(map) => [Some(map.key_kind()), Some(map.value_kind())],
PropertyValueEnum::UnorderedContainer(values::UnorderedContainer(container))
| PropertyValueEnum::Container(container) => [Some(container.item_kind()), None],
PropertyValueEnum::Optional(optional) => [Some(optional.item_kind()), None],
_ => [None, None],
};
RitoType { base, subtypes }
}
}