rbx_reflection 6.1.0

Roblox reflection database and ambiguous type resolution
Documentation
use rbx_types::{Content, Enum, Font, FontStyle, FontWeight, Variant};
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Debug, Error)]
pub enum MigrationError {
    #[error(
        "Invalid type for migration {migration:?}: expected a type of {expected}, got {actual:?}"
    )]
    InvalidTypeForMigration {
        migration: MigrationOperation,
        expected: &'static str,
        actual: Variant,
    },
    #[error("Invalid value for migration {migration:?}: expected {expected}, got {actual:?}")]
    InvalidValueForMigration {
        migration: MigrationOperation,
        expected: &'static str,
        actual: Variant,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct PropertyMigration {
    #[serde(rename = "To")]
    pub new_property_name: String,
    migration: MigrationOperation,
}

#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
#[non_exhaustive]
pub enum MigrationOperation {
    IgnoreGuiInsetToScreenInsets,
    FontToFontFace,
    BrickColorToColor,
    ContentIdToContent,
}

impl PropertyMigration {
    pub fn perform(&self, input: &Variant) -> Result<Variant, MigrationError> {
        match self.migration {
            MigrationOperation::IgnoreGuiInsetToScreenInsets => {
                if let Variant::Bool(value) = input {
                    if *value {
                        Ok(Enum::from_u32(1).into())
                    } else {
                        Ok(Enum::from_u32(2).into())
                    }
                } else {
                    Err(MigrationError::InvalidTypeForMigration {
                        migration: MigrationOperation::IgnoreGuiInsetToScreenInsets,
                        expected: "Enum",
                        actual: input.clone(),
                    })
                }
            }
            MigrationOperation::FontToFontFace => {
                if let Variant::Enum(value) = input {
                    let value = value.to_u32();
                    Ok(match value {
                        0 => Font::regular("rbxasset://fonts/families/LegacyArial.json"),
                        1 => Font::regular("rbxasset://fonts/families/Arial.json"),
                        2 => Font::new(
                            "rbxasset://fonts/families/Arial.json",
                            FontWeight::Bold,
                            FontStyle::Normal,
                        ),
                        3 => Font::regular("rbxasset://fonts/families/SourceSansPro.json"),
                        4 => Font::new(
                            "rbxasset://fonts/families/SourceSansPro.json",
                            FontWeight::Bold,
                            FontStyle::Normal,
                        ),
                        16 => Font::new(
                            "rbxasset://fonts/families/SourceSansPro.json",
                            FontWeight::SemiBold,
                            FontStyle::Normal,
                        ),
                        5 => Font::new(
                            "rbxasset://fonts/families/SourceSansPro.json",
                            FontWeight::Light,
                            FontStyle::Normal,
                        ),
                        6 => Font::new(
                            "rbxasset://fonts/families/SourceSansPro.json",
                            FontWeight::Regular,
                            FontStyle::Italic,
                        ),
                        7 => Font::regular("rbxasset://fonts/families/AccanthisADFStd.json"),
                        8 => Font::regular("rbxasset://fonts/families/Guru.json"),
                        9 => Font::regular("rbxasset://fonts/families/ComicNeueAngular.json"),
                        10 => Font::regular("rbxasset://fonts/families/Inconsolata.json"),
                        11 => Font::regular("rbxasset://fonts/families/HighwayGothic.json"),
                        12 => Font::regular("rbxasset://fonts/families/Zekton.json"),
                        13 => Font::regular("rbxasset://fonts/families/PressStart2P.json"),
                        14 => Font::regular("rbxasset://fonts/families/Balthazar.json"),
                        15 => Font::regular("rbxasset://fonts/families/RomanAntique.json"),
                        17 => Font::regular("rbxasset://fonts/families/GothamSSm.json"),
                        18 => Font::new(
                            "rbxasset://fonts/families/GothamSSm.json",
                            FontWeight::Medium,
                            FontStyle::Normal,
                        ),
                        19 => Font::new(
                            "rbxasset://fonts/families/GothamSSm.json",
                            FontWeight::Bold,
                            FontStyle::Normal,
                        ),
                        20 => Font::new(
                            "rbxasset://fonts/families/GothamSSm.json",
                            FontWeight::Heavy,
                            FontStyle::Normal,
                        ),
                        21 => Font::regular("rbxasset://fonts/families/AmaticSC.json"),
                        22 => Font::regular("rbxasset://fonts/families/Bangers.json"),
                        23 => Font::regular("rbxasset://fonts/families/Creepster.json"),
                        24 => Font::regular("rbxasset://fonts/families/DenkOne.json"),
                        25 => Font::regular("rbxasset://fonts/families/Fondamento.json"),
                        26 => Font::regular("rbxasset://fonts/families/FredokaOne.json"),
                        27 => Font::regular("rbxasset://fonts/families/GrenzeGotisch.json"),
                        28 => Font::regular("rbxasset://fonts/families/IndieFlower.json"),
                        29 => Font::regular("rbxasset://fonts/families/JosefinSans.json"),
                        30 => Font::regular("rbxasset://fonts/families/Jura.json"),
                        31 => Font::regular("rbxasset://fonts/families/Kalam.json"),
                        32 => Font::regular("rbxasset://fonts/families/LuckiestGuy.json"),
                        33 => Font::regular("rbxasset://fonts/families/Merriweather.json"),
                        34 => Font::regular("rbxasset://fonts/families/Michroma.json"),
                        35 => Font::regular("rbxasset://fonts/families/Nunito.json"),
                        36 => Font::regular("rbxasset://fonts/families/Oswald.json"),
                        37 => Font::regular("rbxasset://fonts/families/PatrickHand.json"),
                        38 => Font::regular("rbxasset://fonts/families/PermanentMarker.json"),
                        39 => Font::regular("rbxasset://fonts/families/Roboto.json"),
                        40 => Font::regular("rbxasset://fonts/families/RobotoCondensed.json"),
                        41 => Font::regular("rbxasset://fonts/families/RobotoMono.json"),
                        42 => Font::regular("rbxasset://fonts/families/Sarpanch.json"),
                        43 => Font::regular("rbxasset://fonts/families/SpecialElite.json"),
                        44 => Font::regular("rbxasset://fonts/families/TitilliumWeb.json"),
                        45 => Font::regular("rbxasset://fonts/families/Ubuntu.json"),
                        _ => {
                            return Err(MigrationError::InvalidValueForMigration {
                                migration: MigrationOperation::FontToFontFace,
                                expected: "a Font enum value between 0 and 45",
                                actual: input.clone(),
                            })
                        }
                    }
                    .into())
                } else {
                    Err(MigrationError::InvalidTypeForMigration {
                        migration: MigrationOperation::FontToFontFace,
                        expected: "Enum",
                        actual: input.clone(),
                    })
                }
            }
            MigrationOperation::BrickColorToColor => {
                if let Variant::BrickColor(color) = input {
                    Ok(color.to_color3uint8().into())
                } else {
                    Err(MigrationError::InvalidTypeForMigration {
                        migration: MigrationOperation::BrickColorToColor,
                        expected: "BrickColor",
                        actual: input.clone(),
                    })
                }
            }
            MigrationOperation::ContentIdToContent => {
                if let Variant::ContentId(uri) = input {
                    let uri = uri.as_str();
                    if uri.is_empty() {
                        Ok(Content::none().into())
                    } else {
                        Ok(Content::from_uri(uri).into())
                    }
                } else {
                    Err(MigrationError::InvalidTypeForMigration {
                        migration: MigrationOperation::ContentIdToContent,
                        expected: "ContentId",
                        actual: input.clone(),
                    })
                }
            }
        }
    }
}