#![allow(clippy::new_without_default)]
use std::collections::{HashMap, HashSet};
use rbx_types::{Variant, VariantType};
use serde::{Deserialize, Serialize};
use crate::{ClassTag, PropertyMigration, PropertyTag};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
#[non_exhaustive]
pub struct ReflectionDatabase<'a> {
pub version: [u32; 4],
#[serde(borrow)]
#[serde(serialize_with = "crate::serde_util::ordered_map")]
pub classes: HashMap<&'a str, ClassDescriptor<'a>>,
#[serde(borrow)]
#[serde(default, serialize_with = "crate::serde_util::ordered_map")]
pub enums: HashMap<&'a str, EnumDescriptor<'a>>,
}
impl<'a> ReflectionDatabase<'a> {
pub fn new() -> Self {
Self {
version: [0, 0, 0, 0],
classes: HashMap::new(),
enums: HashMap::new(),
}
}
pub fn superclasses(
&'a self,
descriptor: &'a ClassDescriptor<'a>,
) -> Option<Vec<&'a ClassDescriptor<'a>>> {
let mut list = Vec::with_capacity(6);
let mut current_class = Some(descriptor);
while let Some(class) = current_class {
list.push(class);
current_class = class.superclass.and_then(|s| self.classes.get(s));
}
Some(list)
}
pub fn superclasses_iter(
&'a self,
descriptor: &'a ClassDescriptor<'a>,
) -> impl Iterator<Item = &'a ClassDescriptor<'a>> {
std::iter::successors(Some(descriptor), move |class| {
class.superclass.and_then(|s| self.classes.get(s))
})
}
pub fn has_superclass(
&self,
descriptor: &ClassDescriptor,
superclass_descriptor: &ClassDescriptor,
) -> bool {
self.superclasses_iter(descriptor)
.any(|class_descriptor| class_descriptor.name == superclass_descriptor.name)
}
pub fn find_default_property(
&'a self,
mut class: &'a ClassDescriptor<'a>,
property_name: &str,
) -> Option<&'a Variant> {
loop {
match class.default_properties.get(property_name) {
None => {
class = self
.classes
.get(class.superclass?)
.expect("superclass that is Some should exist in reflection database")
}
default_value => return default_value,
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
#[non_exhaustive]
pub struct ClassDescriptor<'a> {
pub name: &'a str,
#[serde(serialize_with = "crate::serde_util::ordered_set")]
pub tags: HashSet<ClassTag>,
#[serde(default)]
pub superclass: Option<&'a str>,
#[serde(serialize_with = "crate::serde_util::ordered_map")]
pub properties: HashMap<&'a str, PropertyDescriptor<'a>>,
#[serde(serialize_with = "crate::serde_util::ordered_map")]
pub default_properties: HashMap<&'a str, Variant>,
}
impl<'a> ClassDescriptor<'a> {
pub fn new(name: &'a str) -> Self {
Self {
name,
tags: HashSet::new(),
superclass: None,
properties: HashMap::new(),
default_properties: HashMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
#[non_exhaustive]
pub struct PropertyDescriptor<'a> {
pub name: &'a str,
pub scriptability: Scriptability,
pub data_type: DataType<'a>,
#[serde(serialize_with = "crate::serde_util::ordered_set")]
pub tags: HashSet<PropertyTag>,
pub kind: PropertyKind<'a>,
}
impl<'a> PropertyDescriptor<'a> {
pub fn new(name: &'a str, data_type: DataType<'a>) -> Self {
Self {
name,
scriptability: Scriptability::None,
data_type,
tags: HashSet::new(),
kind: PropertyKind::Canonical {
serialization: PropertySerialization::Serializes,
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum PropertyKind<'a> {
#[serde(rename_all = "PascalCase")]
Canonical {
serialization: PropertySerialization<'a>,
},
#[serde(rename_all = "PascalCase")]
Alias { alias_for: &'a str },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum PropertySerialization<'a> {
Serializes,
DoesNotSerialize,
SerializesAs(&'a str),
Migrate(PropertyMigration<'a>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum DataType<'a> {
Value(VariantType),
Enum(&'a str),
}
impl DataType<'_> {
pub fn ty(&self) -> VariantType {
match self {
DataType::Value(variant_type) => *variant_type,
DataType::Enum(_) => VariantType::Enum,
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Scriptability {
None,
ReadWrite,
Read,
Write,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct EnumDescriptor<'a> {
pub name: &'a str,
#[serde(serialize_with = "crate::serde_util::ordered_map")]
pub items: HashMap<&'a str, u32>,
}
impl<'a> EnumDescriptor<'a> {
pub fn new(name: &'a str) -> Self {
Self {
name,
items: HashMap::new(),
}
}
}