1use std::{any::TypeId, collections::HashMap};
2
3use glam::{Mat4, Quat, UVec2, UVec3, UVec4, Vec2, Vec3, Vec4};
4use once_cell::sync::Lazy;
5use paste::paste;
6
7use crate::{
8 AttributeConstructor, AttributeStore, ComponentDesc, ComponentRegistry, ComponentVTable, Description, EntityId,
9 ExternalComponentAttributes, Name,
10};
11
12use ambient_shared_types::primitive_component_definitions;
13
14macro_rules! build_attribute_registration {
16 ($type:ty, $store:ident, $attributes:ident) => {{
17 if let Some(name) = $attributes.name {
18 <Name as AttributeConstructor<$type, _>>::construct(&mut $store, &name);
19 }
20 if let Some(description) = $attributes.description {
21 <Description as AttributeConstructor<$type, _>>::construct(&mut $store, &description);
22 }
23 $attributes.flags.construct_for_store::<$type>(&mut $store);
24
25 static VTABLE: &ComponentVTable<$type> = &ComponentVTable::construct_external();
26 unsafe { VTABLE.erase() }
27 }};
28}
29
30macro_rules! make_primitive_component {
31 ($(($value:ident, $type:ty)),*) => {
32 paste! {
33 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34 pub struct PrimitiveComponent {
35 pub ty: PrimitiveComponentType,
36 pub desc: ComponentDesc,
37 }
38
39 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40 #[derive(serde::Serialize, serde::Deserialize)]
41 pub enum PrimitiveComponentContainerType {
42 Vec,
43 Option
44 }
45 impl PrimitiveComponentContainerType {
46 pub fn as_str(&self) -> &'static str {
47 match self {
48 Self::Vec => "Vec",
49 Self::Option => "Option",
50 }
51 }
52 }
53
54 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55 #[derive(serde::Serialize, serde::Deserialize)]
56 pub enum PrimitiveComponentType {
57 $($value), *,
58 $([< Vec $value >]), *,
59 $([< Option$value >]), *,
60 }
61
62 impl TryFrom<&str> for PrimitiveComponentType {
63 type Error = &'static str;
64
65 fn try_from(value: &str) -> Result<Self, Self::Error> {
66 match value {
67 $(stringify!($value) => Ok(Self::$value),)*
68 "Vec" | "Option" => Err("The specified type is a container type, not primitive"),
69 _ => Err("Unsupported type")
70 }
71 }
72 }
73
74 impl PrimitiveComponent {
75 pub fn as_component(&self) -> ComponentDesc {
76 self.desc
77 }
78 }
79
80 impl PrimitiveComponentType {
81 pub fn as_str(&self) -> Option<&'static str> {
83 match self {
84 $(Self::$value => Some(stringify!($value)),)*
85 _ => None,
86 }
87 }
88
89 pub fn to_vec_type(&self) -> Option<Self> {
90 match self {
91 $(Self::$value => Some(Self::[<Vec $value>]),)*
92 _ => None
93 }
94 }
95
96 pub fn to_option_type(&self) -> Option<Self> {
97 match self {
98 $(Self::$value => Some(Self::[<Option $value>]),)*
99 _ => None
100 }
101 }
102
103 pub fn decompose_container_type(&self) -> Option<(PrimitiveComponentContainerType, Self)> {
104 match self {
105 $(Self::[<Vec $value>] => Some((PrimitiveComponentContainerType::Vec, Self::$value)),)*
106 $(Self::[<Option $value>] => Some((PrimitiveComponentContainerType::Option, Self::$value)),)*
107 _ => None
108 }
109 }
110
111 pub(crate) fn register(&self, reg: &mut ComponentRegistry, path: &str, attributes: ExternalComponentAttributes) {
112 let mut store = AttributeStore::new();
113 let vtable = match self {
114 $(
115 PrimitiveComponentType::$value => {
116 build_attribute_registration!($type, store, attributes)
117 },
118 PrimitiveComponentType::[< Vec $value >] => {
119 build_attribute_registration!(Vec<$type>, store, attributes)
120 },
121 PrimitiveComponentType::[< Option $value >] => {
122 build_attribute_registration!(Option<$type>, store, attributes)
123 },
124 )*
125 };
126
127 reg.register_external(path.into(), vtable, store);
128 }
129 }
130 impl PartialEq<PrimitiveComponentType> for PrimitiveComponent {
131 fn eq(&self, other: &PrimitiveComponentType) -> bool {
132 &self.ty == other
133 }
134 }
135
136 pub static TYPE_ID_TO_PRIMITIVE_TYPE: Lazy<HashMap<TypeId, PrimitiveComponentType>> = Lazy::new(|| {
137 HashMap::from_iter([
138 $((TypeId::of::<$type>(), PrimitiveComponentType::$value),)*
139 $((TypeId::of::<Vec<$type>>(), PrimitiveComponentType::[<Vec $value>]),)*
140 $((TypeId::of::<Option<$type>>(), PrimitiveComponentType::[<Option $value>]),)*
141 ])
142 });
143 }
144 }
145}
146
147primitive_component_definitions!(make_primitive_component);