Skip to main content

steel_registry/data_components/
component_data.rs

1//! Type-erased data component values.
2
3use std::fmt::{self, Debug, Formatter};
4
5use steel_utils::{Downcast as _, DowncastType, DowncastTypeKey, ErasedType};
6
7use crate::block_transformer::BlockTransformerComponent;
8
9use super::components::{
10    ArmorTrim, AttackRange, BannerPatternLayers, Bees, BlockEntityData, BlockItemStateProperties,
11    BlocksAttacks, BrewingFuel, BundleContents, ChargedProjectiles, Compostable, Consumable,
12    CookingFuel, CustomData, CustomModelData, DamageResistant, DamageTypeComponent,
13    DeathProtection, DebugStickState, DyedItemColor, Enchantable, EntityData, Equippable,
14    FireworkExplosion, Fireworks, FoodProperties, InstrumentComponent, ItemAttributeModifiers,
15    ItemContainerContents, ItemEnchantments, ItemLore, JukeboxPlayable, KineticWeapon,
16    LodestoneTracker, MapDecorations, MapId, MapItemColor, MapPostProcessing, MobVisibility,
17    OminousBottleAmplifier, PaintingVariantComponent, PiercingWeapon, PotDecorations,
18    PotionContents, ProvidesBannerPatterns, ProvidesPotteryPattern, ProvidesTrimMaterial, Rarity,
19    Recipes, Repairable, SeededContainerLoot, SignText, SulfurCubeContent, SuspiciousStewEffects,
20    SwingAnimation, Tool, TooltipDisplay, UseCooldown, UseEffects, UseRemainder, VillagerFood,
21    Weapon, WritableBookContent, WrittenBookContent,
22};
23use crate::cat_sound_variant::CatSoundVariant;
24use crate::cat_variant::CatVariant;
25use crate::chicken_sound_variant::ChickenSoundVariant;
26use crate::chicken_variant::ChickenVariant;
27use crate::cow_sound_variant::CowSoundVariant;
28use crate::cow_variant::CowVariant;
29use crate::frog_variant::FrogVariant;
30use crate::item_predicate::{AdventureModePredicate, LockCode};
31use crate::pig_sound_variant::PigSoundVariant;
32use crate::pig_variant::PigVariant;
33use crate::resolvable_profile::ResolvableProfile;
34use crate::villager_type::VillagerType;
35use crate::wolf_sound_variant::WolfSoundVariant;
36use crate::wolf_variant::WolfVariant;
37use crate::zombie_nautilus_variant::ZombieNautilusVariant;
38use crate::{
39    AxolotlVariant, DyeColor, FoxVariant, HorseVariant, LlamaVariant, MooshroomVariant,
40    ParrotVariant, RabbitVariant, RegistryReference, SalmonVariant, TropicalFishPattern,
41};
42
43/// Behavior required from a value stored in a [`ComponentData`].
44///
45/// Concrete type recovery is provided by Steel's deterministic keyed
46/// downcasting foundation. A value is eligible for the blanket implementation
47/// when it also supports cloning, comparison, debugging, and shared server
48/// access. Persistent-codec hashing is registered separately so transient
49/// values do not need a fake hash representation.
50pub trait Component: ErasedType + Debug + Send + Sync + 'static {
51    #[doc(hidden)]
52    fn clone_component(&self) -> Box<dyn Component>;
53
54    #[doc(hidden)]
55    fn component_eq(&self, other: &dyn Component) -> bool;
56}
57
58impl<T> Component for T
59where
60    T: DowncastType + Clone + Debug + PartialEq + Send + Sync,
61{
62    fn clone_component(&self) -> Box<dyn Component> {
63        Box::new(self.clone())
64    }
65
66    fn component_eq(&self, other: &dyn Component) -> bool {
67        other.downcast_ref::<T>() == Some(self)
68    }
69}
70
71/// A type-erased component value.
72///
73/// Component values retain their concrete Rust type and can be recovered with
74/// [`Self::downcast_ref`].
75pub struct ComponentData {
76    value: Box<dyn Component>,
77}
78
79impl ComponentData {
80    /// Erases a typed component value.
81    #[must_use]
82    pub fn new(value: impl Component) -> Self {
83        Self {
84            value: Box::new(value),
85        }
86    }
87
88    /// Returns the concrete value when it has type `T`.
89    #[must_use]
90    pub fn downcast_ref<T: DowncastType>(&self) -> Option<&T> {
91        self.value.downcast_ref::<T>()
92    }
93
94    /// Returns the concrete type key.
95    #[must_use]
96    pub fn type_key(&self) -> DowncastTypeKey {
97        self.value.downcast_type_key()
98    }
99}
100
101impl Clone for ComponentData {
102    fn clone(&self) -> Self {
103        Self {
104            value: self.value.clone_component(),
105        }
106    }
107}
108
109impl Debug for ComponentData {
110    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
111        formatter
112            .debug_tuple("ComponentData")
113            .field(&self.value)
114            .finish()
115    }
116}
117
118impl PartialEq for ComponentData {
119    fn eq(&self, other: &Self) -> bool {
120        self.value.component_eq(other.value.as_ref())
121    }
122}
123
124macro_rules! impl_component_downcast_type {
125    ($type:ty, $key:literal) => {
126        // SAFETY: This Steel-owned key uniquely identifies the concrete
127        // component implementation within the process.
128        unsafe impl DowncastType for $type {
129            const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new($key);
130        }
131    };
132}
133
134impl_component_downcast_type!(DamageTypeComponent, "steel:item_component/damage_type");
135impl_component_downcast_type!(
136    AdventureModePredicate,
137    "steel:item_component/adventure_mode_predicate"
138);
139impl_component_downcast_type!(LockCode, "steel:item_component/lock");
140impl_component_downcast_type!(CustomData, "steel:item_component/custom_data");
141impl_component_downcast_type!(CustomModelData, "steel:item_component/custom_model_data");
142impl_component_downcast_type!(DyeColor, "steel:dye_color");
143impl_component_downcast_type!(FoxVariant, "steel:fox_variant");
144impl_component_downcast_type!(SalmonVariant, "steel:salmon_variant");
145impl_component_downcast_type!(ParrotVariant, "steel:parrot_variant");
146impl_component_downcast_type!(TropicalFishPattern, "steel:tropical_fish_pattern");
147impl_component_downcast_type!(MooshroomVariant, "steel:mooshroom_variant");
148impl_component_downcast_type!(RabbitVariant, "steel:rabbit_variant");
149impl_component_downcast_type!(HorseVariant, "steel:horse_variant");
150impl_component_downcast_type!(LlamaVariant, "steel:llama_variant");
151impl_component_downcast_type!(AxolotlVariant, "steel:axolotl_variant");
152impl_component_downcast_type!(DyedItemColor, "steel:item_component/dyed_item_color");
153impl_component_downcast_type!(MapItemColor, "steel:item_component/map_item_color");
154impl_component_downcast_type!(MapId, "steel:item_component/map_id");
155impl_component_downcast_type!(FoodProperties, "steel:item_component/food");
156impl_component_downcast_type!(
157    SuspiciousStewEffects,
158    "steel:item_component/suspicious_stew_effects"
159);
160impl_component_downcast_type!(
161    WritableBookContent,
162    "steel:item_component/writable_book_content"
163);
164impl_component_downcast_type!(
165    WrittenBookContent,
166    "steel:item_component/written_book_content"
167);
168impl_component_downcast_type!(DebugStickState, "steel:item_component/debug_stick_state");
169impl_component_downcast_type!(Bees, "steel:item_component/bees");
170impl_component_downcast_type!(EntityData, "steel:item_component/entity_data");
171impl_component_downcast_type!(BlockEntityData, "steel:item_component/block_entity_data");
172impl_component_downcast_type!(KineticWeapon, "steel:item_component/kinetic_weapon");
173impl_component_downcast_type!(LodestoneTracker, "steel:item_component/lodestone_tracker");
174impl_component_downcast_type!(MapDecorations, "steel:item_component/map_decorations");
175impl_component_downcast_type!(FireworkExplosion, "steel:item_component/firework_explosion");
176impl_component_downcast_type!(Fireworks, "steel:item_component/fireworks");
177impl_component_downcast_type!(BlockItemStateProperties, "steel:item_component/block_state");
178impl_component_downcast_type!(BlocksAttacks, "steel:item_component/blocks_attacks");
179impl_component_downcast_type!(Consumable, "steel:item_component/consumable");
180impl_component_downcast_type!(DeathProtection, "steel:item_component/death_protection");
181impl_component_downcast_type!(ResolvableProfile, "steel:item_component/profile");
182impl_component_downcast_type!(SeededContainerLoot, "steel:item_component/container_loot");
183impl_component_downcast_type!(
184    OminousBottleAmplifier,
185    "steel:item_component/ominous_bottle_amplifier"
186);
187impl_component_downcast_type!(Enchantable, "steel:item_component/enchantable");
188impl_component_downcast_type!(InstrumentComponent, "steel:item_component/instrument");
189impl_component_downcast_type!(ArmorTrim, "steel:item_component/trim");
190impl_component_downcast_type!(Recipes, "steel:item_component/recipes");
191impl_component_downcast_type!(PotDecorations, "steel:item_component/pot_decorations");
192impl_component_downcast_type!(PotionContents, "steel:item_component/potion_contents");
193impl_component_downcast_type!(UseRemainder, "steel:item_component/use_remainder");
194impl_component_downcast_type!(
195    ChargedProjectiles,
196    "steel:item_component/charged_projectiles"
197);
198impl_component_downcast_type!(BundleContents, "steel:item_component/bundle_contents");
199impl_component_downcast_type!(ItemContainerContents, "steel:item_component/container");
200impl_component_downcast_type!(
201    SulfurCubeContent,
202    "steel:item_component/sulfur_cube_content"
203);
204impl_component_downcast_type!(BannerPatternLayers, "steel:item_component/banner_patterns");
205impl_component_downcast_type!(
206    PaintingVariantComponent,
207    "steel:item_component/painting_variant"
208);
209impl_component_downcast_type!(
210    ProvidesTrimMaterial,
211    "steel:item_component/provides_trim_material"
212);
213impl_component_downcast_type!(
214    ProvidesPotteryPattern,
215    "steel:item_component/provides_pottery_pattern"
216);
217impl_component_downcast_type!(JukeboxPlayable, "steel:item_component/jukebox_playable");
218impl_component_downcast_type!(
219    ProvidesBannerPatterns,
220    "steel:item_component/provides_banner_patterns"
221);
222impl_component_downcast_type!(DamageResistant, "steel:item_component/damage_resistant");
223impl_component_downcast_type!(Repairable, "steel:item_component/repairable");
224impl_component_downcast_type!(Tool, "steel:item_component/tool");
225impl_component_downcast_type!(Weapon, "steel:item_component/weapon");
226impl_component_downcast_type!(AttackRange, "steel:item_component/attack_range");
227impl_component_downcast_type!(UseCooldown, "steel:item_component/use_cooldown");
228impl_component_downcast_type!(UseEffects, "steel:item_component/use_effects");
229impl_component_downcast_type!(ItemLore, "steel:item_component/lore");
230impl_component_downcast_type!(Rarity, "steel:item_component/rarity");
231impl_component_downcast_type!(TooltipDisplay, "steel:item_component/tooltip_display");
232impl_component_downcast_type!(SwingAnimation, "steel:item_component/swing_animation");
233impl_component_downcast_type!(CookingFuel, "steel:item_component/cooking_fuel");
234impl_component_downcast_type!(BrewingFuel, "steel:item_component/brewing_fuel");
235impl_component_downcast_type!(MobVisibility, "steel:item_component/mob_visibility");
236impl_component_downcast_type!(
237    BlockTransformerComponent,
238    "steel:item_component/block_transformer"
239);
240impl_component_downcast_type!(VillagerFood, "steel:item_component/villager_food");
241impl_component_downcast_type!(SignText, "steel:item_component/sign_text");
242impl_component_downcast_type!(Compostable, "steel:item_component/compostable");
243impl_component_downcast_type!(
244    MapPostProcessing,
245    "steel:item_component/map_post_processing"
246);
247impl_component_downcast_type!(PiercingWeapon, "steel:item_component/piercing_weapon");
248impl_component_downcast_type!(Equippable, "steel:item_component/equippable");
249impl_component_downcast_type!(
250    ItemAttributeModifiers,
251    "steel:item_component/attribute_modifiers"
252);
253impl_component_downcast_type!(ItemEnchantments, "steel:item_component/enchantments");
254impl_component_downcast_type!(
255    RegistryReference<VillagerType>,
256    "steel:item_component/villager_variant"
257);
258impl_component_downcast_type!(
259    RegistryReference<WolfVariant>,
260    "steel:item_component/wolf_variant"
261);
262impl_component_downcast_type!(
263    RegistryReference<WolfSoundVariant>,
264    "steel:item_component/wolf_sound_variant"
265);
266impl_component_downcast_type!(
267    RegistryReference<PigVariant>,
268    "steel:item_component/pig_variant"
269);
270impl_component_downcast_type!(
271    RegistryReference<PigSoundVariant>,
272    "steel:item_component/pig_sound_variant"
273);
274impl_component_downcast_type!(
275    RegistryReference<CowVariant>,
276    "steel:item_component/cow_variant"
277);
278impl_component_downcast_type!(
279    RegistryReference<CowSoundVariant>,
280    "steel:item_component/cow_sound_variant"
281);
282impl_component_downcast_type!(
283    RegistryReference<ChickenVariant>,
284    "steel:item_component/chicken_variant"
285);
286impl_component_downcast_type!(
287    RegistryReference<ChickenSoundVariant>,
288    "steel:item_component/chicken_sound_variant"
289);
290impl_component_downcast_type!(
291    RegistryReference<ZombieNautilusVariant>,
292    "steel:item_component/zombie_nautilus_variant"
293);
294impl_component_downcast_type!(
295    RegistryReference<FrogVariant>,
296    "steel:item_component/frog_variant"
297);
298impl_component_downcast_type!(
299    RegistryReference<CatVariant>,
300    "steel:item_component/cat_variant"
301);
302impl_component_downcast_type!(
303    RegistryReference<CatSoundVariant>,
304    "steel:item_component/cat_sound_variant"
305);
306
307#[cfg(test)]
308mod tests {
309    use super::ComponentData;
310
311    #[test]
312    fn typed_values_downcast_by_deterministic_key() {
313        let value = ComponentData::new(17_i32);
314
315        assert_eq!(value.downcast_ref::<i32>(), Some(&17));
316        assert_eq!(value.downcast_ref::<bool>(), None);
317    }
318
319    #[test]
320    fn equality_requires_the_same_concrete_type() {
321        assert_eq!(ComponentData::new(17_i32), ComponentData::new(17_i32));
322        assert_ne!(ComponentData::new(17_i32), ComponentData::new(17.0_f32));
323    }
324}