aframe/utils/
mod.rs

1//! The `js!` macro, vectors and other useful utility modules.
2
3pub mod color;
4pub mod htmlify;
5
6pub use ::htmlify::*;
7pub use const_default::ConstDefault;
8use js_sys::{Object, Reflect};
9use wasm_bindgen::{JsCast, JsValue};
10use std::{borrow::Cow, fmt::Display};
11use serde::{Serialize, Serializer};
12pub use js_sys::Function;
13
14/// Allows a javascript function to be defined inline. Accepts 2 forms of syntax:
15/// `js!(<js code>);`
16/// `js!(arg1, arg2, arg3 =>> <js code>)`
17/// There are some limitations: 
18/// - `===` and `!==` cannot be parsed correctly, use `==` and `!=` instead.
19/// - String literals must be double-quoted, not single-quoted.
20/// - Statements missing a terminating a semi-colon may not parse correctly.
21#[macro_export]
22macro_rules! js
23{
24    ($($arg:ident),* =>> $($tt:tt)*) => 
25    {
26        $crate::utils::Function::new_with_args(stringify!($($arg), *), stringify!($($tt)*))
27    };
28    ($($tt:tt)*) => 
29    {
30        $crate::utils::Function::new_no_args(stringify!($($tt)*))
31    }
32}
33
34/// A 2-dimensional vector
35#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
36pub struct Vector2
37{
38    pub x: f64,
39    pub y: f64
40}
41impl ConstDefault for Vector2
42{
43    const DEFAULT: Vector2 = Vector2 { x: 0.0, y: 0.0 };
44}
45
46/// A 3-dimensional vector
47#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
48pub struct Vector3
49{
50    pub x: f64,
51    pub y: f64,
52    pub z: f64
53}
54impl ConstDefault for Vector3
55{
56    const DEFAULT: Vector3 = Vector3 { x: 0.0, y: 0.0, z: 0.0 };
57}
58
59/// A 4-dimensional vector
60#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
61pub struct Vector4
62{
63    pub x: f64,
64    pub y: f64,
65    pub z: f64,
66    pub w: f64
67}
68impl ConstDefault for Vector4
69{
70    const DEFAULT: Vector4 = Vector4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 };
71}
72
73impl Display for Vector2
74{
75    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result 
76    {
77        write!(f, "{} {}", self.x, self.y)
78    }
79}
80
81impl Display for Vector3
82{
83    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result 
84    {
85        write!(f, "{} {} {}", self.x, self.y, self.z)
86    }
87}
88
89impl Display for Vector4
90{
91    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result 
92    {
93        write!(f, "{} {} {} {}", self.x, self.y, self.z, self.w)
94    }
95}
96
97/// Helper function to attach JsFunctions to a serialized JsValue
98pub(crate) fn define_property(src: &Object, name: &str, value: &Object)
99{
100    if src.unchecked_ref::<JsValue>() != &JsValue::UNDEFINED
101    {
102        #[allow(unused_unsafe)]
103        unsafe
104        {
105            Reflect::set(src, &JsValue::from_str(name), value).expect(&format!("Failed to define property on: {}", name));
106        }
107    }
108}
109
110/// A property used for some registrations in Aframe. 
111/// Contains the type string and the default value.
112#[derive(Serialize, Clone)]
113pub struct AframeProperty
114{
115    #[serde(rename = "type")] 
116    component_type: &'static str,
117    #[serde(skip_serializing_if = "Option::is_none")]
118    default: Option<AframeVal>
119}
120
121impl AframeProperty
122{
123    pub fn array(default: Option<Vec<Cow<'static, str>>>) -> Self
124    {
125        Self { component_type: "array", default: default.map(AframeVal::Array) }
126    }
127
128    pub fn asset(default: Option<Cow<'static, str>>) -> Self
129    {
130        Self { component_type: "asset", default: default.map(AframeVal::Str) }
131    }
132
133    pub fn audio(default: Option<Cow<'static, str>>) -> Self
134    {
135        Self { component_type: "audio", default: default.map(AframeVal::Str) }
136    }
137
138    pub fn boolean(default: Option<bool>) -> Self
139    {
140        Self { component_type: "boolean", default: default.map(AframeVal::Bool) }
141    }
142
143    pub fn color(default: Option<Cow<'static, str>>) -> Self
144    {
145        Self { component_type: "color", default: default.map(AframeVal::Str) }
146    }
147
148    pub fn int(default: Option<i64>) -> Self
149    {
150        Self { component_type: "int", default: default.map(AframeVal::Int) }
151    }
152
153    pub fn map(default: Option<Cow<'static, str>>) -> Self
154    {
155        Self { component_type: "map", default: default.map(AframeVal::Str) }
156    }
157
158    pub fn model(default: Option<Cow<'static, str>>) -> Self
159    {
160        Self { component_type: "model", default: default.map(AframeVal::Str) }
161    }
162
163    pub fn number(default: Option<f32>) -> Self
164    {
165        Self { component_type: "number", default: default.map(AframeVal::Float) }
166    }
167
168    pub fn selector(default: Option<Cow<'static, str>>) -> Self
169    {
170        Self { component_type: "selector", default: default.map(AframeVal::Str) }
171    }
172
173    pub fn selector_all(default: Option<Cow<'static, str>>) -> Self
174    {
175        Self { component_type: "selectorAll", default: default.map(AframeVal::Str) }
176    }
177
178    pub fn string(default: Option<Cow<'static, str>>) -> Self
179    {
180        Self { component_type: "string", default: default.map(AframeVal::Str) }
181    }
182
183    pub fn vec2(default: Option<Vector2>) -> Self
184    {
185        Self { component_type: "vec2", default: default.map(AframeVal::Vec2) }
186    }
187
188    pub fn vec3(default: Option<Vector3>) -> Self
189    {
190        Self { component_type: "vec3", default: default.map(AframeVal::Vec3) }
191    }
192
193    pub fn vec4(default: Option<Vector4>) -> Self
194    {
195        Self { component_type: "vec4", default: default.map(AframeVal::Vec4) }
196    }
197}
198
199#[derive(Clone)]
200pub enum AframeVal
201{
202    Array(Vec<Cow<'static, str>>),
203    Bool(bool),
204    Int(i64),
205    Str(Cow<'static, str>),
206    Float(f32),
207    Vec2(Vector2),
208    Vec3(Vector3),
209    Vec4(Vector4)
210}
211
212impl Serialize for AframeVal
213{
214    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
215    {
216        match self
217        {
218            Self::Str(s) => s.serialize(serializer),
219            Self::Float(f) => f.serialize(serializer),
220            Self::Vec2(vec) => vec.serialize(serializer),
221            Self::Vec3(vec) => vec.serialize(serializer),
222            Self::Vec4(vec) => vec.serialize(serializer),
223            Self::Array(arr) => arr.serialize(serializer),
224            Self::Bool(b) => b.serialize(serializer),
225            Self::Int(i) => i.serialize(serializer),
226        }
227    }
228}