Skip to main content

rbx_rsml/datatype/
types.rs

1use palette::{IntoColor, Oklab, Oklch, Srgb};
2use rbx_types::{Color3, EnumItem, Variant, VariantType};
3
4use crate::datatype::variants::EnumItemFromNameAndValueName;
5
6#[derive(Clone, Debug, PartialEq)]
7pub enum Datatype {
8    Variant(Variant),
9    TupleData(Vec<Datatype>),
10    IncompleteEnumShorthand(String),
11    Oklab(Oklab),
12    Oklch(Oklch),
13    None,
14}
15
16// Datatype contains floats (via rbx_types::Variant, Oklab, Oklch) that do not
17// legitimately produce NaN from parsed RSML input, so PartialEq is effectively
18// reflexive in practice. Eq is required for rangemap coalescing of Definitions.
19impl Eq for Datatype {}
20
21impl Datatype {
22    pub fn coerce_to_variant(self, key: Option<&str>) -> Option<Variant> {
23        match self {
24            Datatype::Variant(variant) => Some(variant),
25
26            Datatype::TupleData(tuple_data) => {
27                if !tuple_data.is_empty() {
28                    tuple_data[0].to_owned().coerce_to_variant(key)
29                } else {
30                    None
31                }
32            }
33
34            Datatype::IncompleteEnumShorthand(value) => {
35                let key = key?;
36                let enum_item = EnumItem::from_name_and_value_name(key, &value)?;
37                Some(Variant::EnumItem(enum_item))
38            }
39
40            Datatype::Oklab(color) => {
41                let color: Srgb<f32> = color.into_color();
42                Some(Variant::Color3(Color3::new(
43                    color.red,
44                    color.green,
45                    color.blue,
46                )))
47            }
48            Datatype::Oklch(color) => {
49                let color: Srgb<f32> = color.into_color();
50                Some(Variant::Color3(Color3::new(
51                    color.red,
52                    color.green,
53                    color.blue,
54                )))
55            }
56
57            Datatype::None => None,
58        }
59    }
60
61    pub fn coerce_to_static(self, key: Option<&str>) -> Option<Datatype> {
62        match self {
63            Datatype::None => None,
64            Datatype::IncompleteEnumShorthand(value) => {
65                let key = key?;
66                let enum_item = EnumItem::from_name_and_value_name(key, &value)?;
67                Some(Datatype::Variant(Variant::EnumItem(enum_item)))
68            }
69            d => Some(d),
70        }
71    }
72
73    pub fn type_name(&self) -> String {
74        match self {
75            Datatype::Variant(variant) => variant_type_name(variant.ty()).to_string(),
76            Datatype::TupleData(items) => {
77                let inner: Vec<String> = items.iter().map(Datatype::type_name).collect();
78                format!("({})", inner.join(", "))
79            }
80            Datatype::IncompleteEnumShorthand(_) => "EnumItem".to_string(),
81            Datatype::Oklab(_) => "Oklab".to_string(),
82            Datatype::Oklch(_) => "Oklch".to_string(),
83            Datatype::None => "unknown".to_string(),
84        }
85    }
86}
87
88pub fn variant_type_name(ty: VariantType) -> &'static str {
89    match ty {
90        VariantType::Axes => "Axes",
91        VariantType::BinaryString => "BinaryString",
92        VariantType::Bool => "boolean",
93        VariantType::BrickColor => "BrickColor",
94        VariantType::CFrame => "CFrame",
95        VariantType::Color3 => "Color3",
96        VariantType::Color3uint8 => "Color3uint8",
97        VariantType::ColorSequence => "ColorSequence",
98        VariantType::ContentId => "ContentId",
99        VariantType::Enum => "Enum",
100        VariantType::Faces => "Faces",
101        VariantType::Float32 => "number",
102        VariantType::Float64 => "number",
103        VariantType::Int32 => "number",
104        VariantType::Int64 => "number",
105        VariantType::NumberRange => "NumberRange",
106        VariantType::NumberSequence => "NumberSequence",
107        VariantType::PhysicalProperties => "PhysicalProperties",
108        VariantType::Ray => "Ray",
109        VariantType::Rect => "Rect",
110        VariantType::Ref => "Ref",
111        VariantType::Region3 => "Region3",
112        VariantType::Region3int16 => "Region3int16",
113        VariantType::SharedString => "SharedString",
114        VariantType::String => "string",
115        VariantType::UDim => "UDim",
116        VariantType::UDim2 => "UDim2",
117        VariantType::Vector2 => "Vector2",
118        VariantType::Vector2int16 => "Vector2int16",
119        VariantType::Vector3 => "Vector3",
120        VariantType::Vector3int16 => "Vector3int16",
121        VariantType::OptionalCFrame => "CFrame?",
122        VariantType::Tags => "Tags",
123        VariantType::Attributes => "Attributes",
124        VariantType::Font => "Font",
125        VariantType::UniqueId => "UniqueId",
126        VariantType::MaterialColors => "MaterialColors",
127        VariantType::SecurityCapabilities => "SecurityCapabilities",
128        VariantType::EnumItem => "EnumItem",
129        VariantType::Content => "Content",
130        _ => "unknown",
131    }
132}