• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

djeedai / bevy_hanabi / 27067874567

06 Jun 2026 04:37PM UTC coverage: 58.459% (+0.8%) from 57.667%
27067874567

Pull #534

github

web-flow
Merge 9cf17eb8c into 0ab4f8012
Pull Request #534: Serialization through Bevy's type registry

280 of 410 new or added lines in 6 files covered. (68.29%)

8 existing lines in 2 files now uncovered.

5121 of 8760 relevant lines covered (58.46%)

190.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.77
/src/graph/expr.rs
1
//! Expression API
2
//!
3
//! This module contains the low-level _Expression API_, designed to produce
4
//! highly customizable modifier behaviors through a code-first API focused on
5
//! runtime and serialization. For asset editing, the higher-level [Node API]
6
//! offers an easier-to-use abstraction built on top of the Expression API.
7
//!
8
//! # Modules and expressions
9
//!
10
//! A particle effect is composed of a series [`Modifier`]s decribing how to
11
//! initialize and update (simulate) the particles of the effect. Choosing which
12
//! modifier to add to an effect provides the user some limited level of
13
//! customizing. However modifiers alone cannot provide enough customizing to
14
//! build visual effects. For this reason, modifier inputs can be further
15
//! customized with _expressions_. An expression produces a value which is
16
//! assigned to the input. That value can be constant, in which case it will be
17
//! hard-coded into the generated WGSL shader, for performance reasons.
18
//! Alternatively, that value can vary based on other quantities, like an effect
19
//! property, a particle attribute, or some built-in simulation variable like
20
//! the simulation time.
21
//!
22
//! An expression is represented by the [`Expr`] enum. Expressions can be
23
//! combined together to form more complex expression; for example, the Add
24
//! expression computes the sum between two other expressions. [`Expr`]
25
//! represents a form of abstraction over the actual WGSL shader code, and is
26
//! generally closely related to the actual expressions of the WGSL language
27
//! itself.
28
//!
29
//! An expression often refers to other expressions. However, [`Expr`] as an
30
//! enum cannot directly contain other [`Expr`], otherwise the type would become
31
//! infinitely recursive. Instead, each expression is stored into a [`Module`]
32
//! and indexed by an [`ExprHandle`], a non-zero index referencing the
33
//! expression inside the module. This indirection avoids the recursion issue.
34
//! This means all expressions are implicitly associated with a unique module,
35
//! and care must be taken to not mix exressions from different modules.
36
//!
37
//! Each [`EffectAsset`] contains a single [`Module`] storing all the [`Expr`]
38
//! used in all its modifiers.
39
//!
40
//! # Kinds of expressions
41
//!
42
//! Expressions can be grouped into various kinds, for the sake of
43
//! comprehension:
44
//! - Literal expressions represent a constant, which will be hard-coded into
45
//!   the final WGSL shader code. Expressions like `1.42` or `vec3<f32>(0.)` are
46
//!   literal expressions in WGSL, and are represented by a [`LiteralExpr`].
47
//! - Built-in expressions represent specific built-in values provided by the
48
//!   simulation context. For example, the current simulation time is a built-in
49
//!   expression accessible from the shader code of any visual effect to animate
50
//!   it. A built-in expression is represented by a [`BuiltInExpr`].
51
//! - Attribute expressions represent the value of an attribute of a particle. A
52
//!   typical example is the particle position, represented by
53
//!   [`Attribute::POSITION`], which can be obtained as an expression through an
54
//!   [`AttributeExpr`].
55
//! - Property expressions represent the value of a visual effect property, a
56
//!   quantity assigned by the user on the CPU side and uploaded each frame into
57
//!   the GPU for precise per-frame control over an effect. It's represented by
58
//!   a [`PropertyExpr`].
59
//! - Unary and binary operations are expressions taking one or two operand
60
//!   expressions and transforming them. A typical example is the Add operator,
61
//!   which takes two operand expressions and produces their sum.
62
//!
63
//! # Building expressions
64
//!
65
//! The fundamental way to build expressions is to directly write them into a
66
//! [`Module`] itself. The [`Module`] type contains various methods to create
67
//! new expressions and immediately write them.
68
//!
69
//! ```
70
//! # use bevy_hanabi::*;
71
//! let mut module = Module::default();
72
//!
73
//! // Build and write a literal expression into the module.
74
//! let expr = module.lit(3.42);
75
//! ```
76
//!
77
//! Due to the code-first nature of the Expression API however, that approach
78
//! can be very verbose. Instead, users are encouraged to use an [`ExprWriter`],
79
//! a simple utility to build expressions with a shortened syntax. Once an
80
//! expression is built, it can be written into the underlying [`Module`]. This
81
//! approach generally makes the code more readable, and is therefore highly
82
//! encouraged, but is not mandatory.
83
//!
84
//! ```
85
//! # use bevy_hanabi::*;
86
//! // Create a writer owning a new Module
87
//! let mut w = ExprWriter::new();
88
//!
89
//! // Build a complex expression: max(3.42, properties.my_prop)
90
//! let prop = w.add_property("my_property", 3.0.into());
91
//! let expr = w.lit(3.42).max(w.prop(prop));
92
//!
93
//! // Finalize the expression and write it into the Module. The returned handle can
94
//! // be assign to a modifier input.
95
//! let handle = expr.expr();
96
//!
97
//! // Finish using the writer and recover the Module with all written expressions
98
//! let module = w.finish();
99
//! ```
100
//!
101
//! [Node API]: crate::graph::node
102
//! [`Modifier`]: crate::Modifier
103
//! [`EffectAsset`]: crate::EffectAsset
104

105
use std::{cell::RefCell, num::NonZeroU32, rc::Rc};
106

107
use bevy::{
108
    platform::collections::HashSet,
109
    prelude::default,
110
    reflect::{Reflect, ReflectDeserialize, ReflectSerialize},
111
};
112
use serde::{Deserialize, Serialize};
113
use thiserror::Error;
114

115
use super::Value;
116
use crate::{
117
    Attribute, ModifierContext, ParticleLayout, Property, PropertyLayout, ScalarType,
118
    TextureLayout, TextureSlot, ToWgslString, ValueType, VectorType,
119
};
120

121
/// A one-based ID into a collection of a [`Module`].
122
type Id = NonZeroU32;
123

124
/// Handle of an expression inside a given [`Module`].
125
///
126
/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a
127
/// lightweight representation, similar to a simple array index. For this
128
/// reason, it's easily copyable. However it's also lacking any kind of error
129
/// checking, and mixing handles to different modules produces undefined
130
/// behaviors (like an index does when indexing the wrong array).
131
///
132
/// # Serialization
133
///
134
/// [`ExprHandle`] is serialized as a string `#<id>`, where `<id>` is the
135
/// 1-based integer index of the expression in the implicitly associated
136
/// [`Module`]'s expression array. Valid `<id>` values are in the range
137
/// `1..=u32::MAX`.
138
///
139
/// Note that during deserialization, there is no validation that the index
140
/// actually refers to a valid entry in the expression array.
141
///
142
/// Examples of valid values:
143
/// - `"#1"`
144
/// - `"#42"`
145
/// - `"#4000"` -- deserializes OK, but unlikely there are 4000 expressions in
146
///   the Module
147
///
148
/// Examples of **invalid** values:
149
/// - `"#0"` -- 0 is a reserved value
150
/// - `"#-1"` -- must be positive
151
/// - `"#4294967296"` -- out of bounds (> u32::MAX)
152
/// - `33` -- not a string
153
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect)]
154
#[reflect(Serialize, Deserialize)]
155
#[repr(transparent)]
156
pub struct ExprHandle {
157
    id: Id,
158
}
159

160
impl serde::Serialize for ExprHandle {
161
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
11✔
162
    where
163
        S: serde::Serializer,
164
    {
165
        serializer.serialize_str(&format!("#{}", self.id.get()))
44✔
166
    }
167
}
168

169
impl<'de> serde::Deserialize<'de> for ExprHandle {
170
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
18✔
171
    where
172
        D: serde::Deserializer<'de>,
173
    {
174
        struct IdVisitor;
175

NEW
176
        impl<'de2> serde::de::Visitor<'de2> for IdVisitor {
×
177
            type Value = ExprHandle;
178

179
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1✔
180
                formatter.write_str(
2✔
181
                    "a string of the form \"#<N>\" where <N> is a non-zero expression index",
182
                )
183
            }
184

185
            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
17✔
186
            where
187
                E: serde::de::Error,
188
            {
189
                if v.len() > 1 && v.chars().nth(0) == Some('#') {
34✔
190
                    let id = v[1..]
30✔
191
                        .parse::<u32>()
192
                        .map_err(|_| serde::de::Error::custom("Failed to parse ID value"))?;
20✔
NEW
193
                    NonZeroU32::try_from(id)
×
194
                        .map(|id| ExprHandle { id })
26✔
195
                        .map_err(|_| serde::de::Error::custom("Invalid ID value"))
1✔
196
                } else {
197
                    Err(serde::de::Error::custom(
1✔
198
                        "Invalid ID format (expected '#N')",
1✔
199
                    ))
200
                }
201
            }
202

NEW
203
            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
×
204
            where
205
                E: serde::de::Error,
206
            {
NEW
207
                self.visit_str(&v[..])
×
208
            }
209
        }
210

211
        deserializer.deserialize_any(IdVisitor)
54✔
212
    }
213
}
214

215
impl ExprHandle {
216
    /// Create a new handle from a 1-based [`Id`].
217
    #[allow(dead_code)]
218
    fn new(id: Id) -> Self {
×
219
        Self { id }
220
    }
221

222
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
223
    /// the index is known to be non-zero already.
224
    #[allow(unsafe_code)]
225
    unsafe fn new_unchecked(id: usize) -> Self {
511✔
226
        debug_assert!(id != 0);
1,022✔
227
        Self {
228
            id: NonZeroU32::new_unchecked(id as u32),
511✔
229
        }
230
    }
231

232
    /// Get the zero-based index into the array of the module.
233
    pub fn index(&self) -> usize {
434✔
234
        (self.id.get() - 1) as usize
434✔
235
    }
236
}
237

238
/// Handle of a property inside a given [`Module`].
239
///
240
/// A handle uniquely references a [`Property`] stored inside a [`Module`]. It's
241
/// a lightweight representation, similar to a simple array index. For this
242
/// reason, it's easily copyable. However it's also lacking any kind of error
243
/// checking, and mixing handles to different modules produces undefined
244
/// behaviors (like an index does when indexing the wrong array).
245
#[derive(
246
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
247
)]
248
#[repr(transparent)]
249
#[serde(transparent)]
250
pub struct PropertyHandle {
251
    id: Id,
252
}
253

254
impl PropertyHandle {
255
    /// Create a new handle from a 1-based [`Id`].
256
    #[allow(dead_code)]
257
    fn new(id: Id) -> Self {
×
258
        Self { id }
259
    }
260

261
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
262
    /// the index is known to be non-zero already.
263
    #[allow(unsafe_code)]
264
    unsafe fn new_unchecked(id: usize) -> Self {
7✔
265
        debug_assert!(id != 0);
14✔
266
        Self {
267
            id: NonZeroU32::new_unchecked(id as u32),
7✔
268
        }
269
    }
270

271
    /// Get the zero-based index into the array of the module.
272
    pub fn index(&self) -> usize {
2✔
273
        (self.id.get() - 1) as usize
2✔
274
    }
275
}
276

277
/// Handle of a texture inside a given [`Module`].
278
///
279
/// A handle uniquely references a [`TextureSlot`] stored inside a [`Module`].
280
/// It's a lightweight representation, similar to a simple array index. For this
281
/// reason, it's easily copyable. However it's also lacking any kind of error
282
/// checking, and mixing handles to different modules produces undefined
283
/// behaviors (like an index does when indexing the wrong array).
284
#[derive(
285
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
286
)]
287
#[repr(transparent)]
288
#[serde(transparent)]
289
pub struct TextureHandle {
290
    id: Id,
291
}
292

293
impl TextureHandle {
294
    /// Create a new handle from a 1-based [`Id`].
295
    #[allow(dead_code)]
296
    fn new(id: Id) -> Self {
×
297
        Self { id }
298
    }
299

300
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
301
    /// the index is known to be non-zero already.
302
    #[allow(unsafe_code)]
303
    unsafe fn new_unchecked(id: usize) -> Self {
×
304
        debug_assert!(id != 0);
×
305
        Self {
306
            id: NonZeroU32::new_unchecked(id as u32),
×
307
        }
308
    }
309

310
    /// Get the zero-based index into the array of the module.
311
    #[allow(dead_code)]
312
    fn index(&self) -> usize {
×
313
        (self.id.get() - 1) as usize
×
314
    }
315
}
316

317
/// Container for expressions.
318
///
319
/// A module represents a storage for a set of expressions used in a single
320
/// [`EffectAsset`]. Modules are not reusable accross effect assets; each effect
321
/// asset owns a single module, containing all the expressions used in all the
322
/// modifiers attached to that asset. However, for convenience, a module can be
323
/// cloned into an unrelated module, and the clone can be assigned to another
324
/// effect asset.
325
///
326
/// Modules are built incrementally. Expressions are written into the module
327
/// through convenience helpers like [`lit()`] or [`attr()`]. Alternatively, an
328
/// [`ExprWriter`] can be used to populate a new or existing module. Either way,
329
/// once an expression is written into a module, it cannot be modified or
330
/// deleted. Modules are not designed to be used as editing structures, but as
331
/// storage and serialization ones.
332
///
333
/// [`EffectAsset`]: crate::EffectAsset
334
/// [`lit()`]: Module::lit
335
/// [`attr()`]: Module::attr
336
#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)]
337
pub struct Module {
338
    /// Expressions defined in the module.
339
    expressions: Vec<Expr>,
340
    /// Properties used as part of a [`PropertyExpr`].
341
    properties: Vec<Property>,
342
    /// Texture layout.
343
    texture_layout: TextureLayout,
344
}
345

346
macro_rules! impl_module_unary {
347
    ($t: ident, $T: ident) => {
348
        #[doc = concat!("Build a [`UnaryOperator::", stringify!($T), "`](crate::graph::expr::UnaryOperator::", stringify!($T),") unary expression and append it to the module.\n\nThis is a shortcut for [`unary(UnaryOperator::", stringify!($T), ", inner)`](crate::graph::expr::Module::unary).")]
349
        #[inline]
350
        pub fn $t(&mut self, inner: ExprHandle) -> ExprHandle {
38✔
351
            self.unary(UnaryOperator::$T, inner)
152✔
352
        }
353
    };
354
}
355

356
macro_rules! impl_module_binary {
357
    ($t: ident, $T: ident) => {
358
        #[doc = concat!("Build a [`BinaryOperator::", stringify!($T), "`](crate::graph::expr::BinaryOperator::", stringify!($T),") binary expression and append it to the module.\n\nThis is a shortcut for [`binary(BinaryOperator::", stringify!($T), ", left, right)`](crate::graph::expr::Module::binary).")]
359
        #[inline]
360
        pub fn $t(&mut self, left: ExprHandle, right: ExprHandle) -> ExprHandle {
35✔
361
            self.binary(BinaryOperator::$T, left, right)
175✔
362
        }
363
    };
364
}
365

366
macro_rules! impl_module_ternary {
367
    ($t: ident, $T: ident) => {
368
        #[doc = concat!("Build a [`TernaryOperator::", stringify!($T), "`](crate::graph::expr::TernaryOperator::", stringify!($T),") ternary expression and append it to the module.\n\nThis is a shortcut for [`ternary(TernaryOperator::", stringify!($T), ", first, second, third)`](crate::graph::expr::Module::ternary).")]
369
        #[inline]
370
        pub fn $t(&mut self, first: ExprHandle, second: ExprHandle, third: ExprHandle) -> ExprHandle {
5✔
371
            self.ternary(TernaryOperator::$T, first, second, third)
30✔
372
        }
373
    };
374
}
375

376
impl Module {
377
    /// Create a new module from an existing collection of expressions.
378
    pub fn from_raw(expr: Vec<Expr>) -> Self {
×
379
        Self {
380
            expressions: expr,
381
            properties: vec![],
×
382
            texture_layout: default(),
×
383
        }
384
    }
385

386
    /// Get all the expressions in this module.
387
    pub fn expressions(&self) -> impl Iterator<Item = (ExprHandle, &Expr)> {
1✔
388
        self.expressions.iter().enumerate().map(|(index, expr)| {
9✔
389
            (
390
                // SAFETY - We directly iterate over the array with enumerate() so all indices are
391
                // valid by design.
392
                #[allow(unsafe_code)]
6✔
393
                unsafe {
6✔
394
                    ExprHandle::new_unchecked(index + 1)
12✔
395
                },
396
                expr,
6✔
397
            )
398
        })
399
    }
400

401
    /// Append a new expression to the module.
402
    pub fn add_expr(&mut self, expr: impl Into<Expr>) -> ExprHandle {
504✔
403
        self.expressions.push(expr.into());
2,016✔
404
        #[allow(unsafe_code)]
×
405
        unsafe {
406
            ExprHandle::new_unchecked(self.expressions.len())
1,512✔
407
        }
408
    }
409

410
    /// Add a new property to the module.
411
    ///
412
    /// See [`Property`] for more details on what effect properties are.
413
    ///
414
    /// # Panics
415
    ///
416
    /// Panics if a property with the same name already exists.
417
    pub fn add_property(
7✔
418
        &mut self,
419
        name: impl Into<String>,
420
        default_value: Value,
421
    ) -> PropertyHandle {
422
        let name = name.into();
21✔
423
        assert!(!self.properties.iter().any(|p| p.name() == name));
23✔
424
        self.properties.push(Property::new(name, default_value));
7✔
425
        // SAFETY - We just pushed a new property into the array, so its length is
426
        // non-zero.
427
        #[allow(unsafe_code)]
×
428
        unsafe {
429
            PropertyHandle::new_unchecked(self.properties.len())
×
430
        }
431
    }
432

433
    /// Get an existing property by handle.
434
    ///
435
    /// Existing properties are properties previously created with
436
    /// [`add_property()`].
437
    ///
438
    /// [`add_property()`]: crate::Module::add_property
439
    pub fn get_property(&self, property: PropertyHandle) -> Option<&Property> {
2✔
440
        self.properties.get(property.index())
6✔
441
    }
442

443
    /// Get an existing property by name.
444
    ///
445
    /// Existing properties are properties previously created with
446
    /// [`add_property()`].
447
    ///
448
    /// [`add_property()`]: crate::Module::add_property
449
    pub fn get_property_by_name(&self, name: &str) -> Option<PropertyHandle> {
×
450
        self.properties
×
451
            .iter()
452
            .enumerate()
453
            .find(|(_, prop)| prop.name() == name)
×
454
            .map(|(index, _)| PropertyHandle::new(NonZeroU32::new(index as u32 + 1).unwrap()))
×
455
    }
456

457
    /// Get the list of existing properties.
458
    pub fn properties(&self) -> &[Property] {
326✔
459
        &self.properties
326✔
460
    }
461

462
    /// Add a new texture slot to the module.
463
    ///
464
    /// The `name` parameter defines a new [`TextureSlot`] associated with this
465
    /// module, and must be unique inside this module. A unique index is also
466
    /// associated with the slot, corresponding to the value returned by
467
    /// [`TextureLayout::get_slot_by_name()`].
468
    ///
469
    /// Once a slot is added, an actual texture resource, defined by its
470
    /// `Handle<Image>`, is bound to that slot through the
471
    /// [`EffectMaterial`] component. Expressions like [`TextureSampleExpr`] can
472
    /// be used to sample the texture using the returned [`TextureHandle`].
473
    ///
474
    /// # Returns
475
    ///
476
    /// The handle of the texture inside this module. This handle is used in
477
    /// expressions like the [`TextureSampleExpr`] to reference this texture
478
    /// slot.
479
    ///
480
    /// # Panics
481
    ///
482
    /// Panics if a texture slot with the same name already exists inside this
483
    /// module. Different effect asset (different modules) can have the same
484
    /// slot name.
485
    ///
486
    /// [`EffectMaterial`]: crate::EffectMaterial
487
    pub fn add_texture_slot(&mut self, name: impl Into<String>) -> TextureHandle {
×
488
        let name = name.into();
×
489
        assert!(!self.texture_layout.layout.iter().any(|t| t.name == name));
×
490
        self.texture_layout.layout.push(TextureSlot { name });
×
491
        // SAFETY - We just pushed a new slot into the array, so its length is non-zero.
492
        #[allow(unsafe_code)]
×
493
        unsafe {
494
            TextureHandle::new_unchecked(self.texture_layout.layout.len())
×
495
        }
496
    }
497

498
    /// Insert into the given set all attributes referenced by any
499
    /// [`AttributeExpr`] present in the module.
500
    ///
501
    /// Note that this **excludes** the attributes from an
502
    /// [`Expr::ParentAttribute`] expression.
503
    pub fn gather_attributes(&self, set: &mut HashSet<Attribute>) {
648✔
504
        for expr in &self.expressions {
1,896✔
505
            if let Expr::Attribute(attr) = expr {
1✔
506
                set.insert(attr.attr);
507
            }
508
        }
509
    }
510

511
    /// Build a literal expression and append it to the module.
512
    #[inline]
513
    pub fn lit<V>(&mut self, value: V) -> ExprHandle
339✔
514
    where
515
        Value: From<V>,
516
    {
517
        self.add_expr(Expr::Literal(LiteralExpr::new(value)))
1,017✔
518
    }
519

520
    /// Build an attribute expression and append it to the module.
521
    #[inline]
522
    pub fn attr(&mut self, attr: Attribute) -> ExprHandle {
31✔
523
        self.add_expr(Expr::Attribute(AttributeExpr::new(attr)))
93✔
524
    }
525

526
    /// Build a parent attribute expression and append it to the module.
527
    #[inline]
528
    pub fn parent_attr(&mut self, attr: Attribute) -> ExprHandle {
×
529
        self.add_expr(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
530
    }
531

532
    /// Build a property expression and append it to the module.
533
    ///
534
    /// A property expression retrieves the value of the given property.
535
    #[inline]
536
    pub fn prop(&mut self, property: PropertyHandle) -> ExprHandle {
3✔
537
        self.add_expr(Expr::Property(PropertyExpr::new(property)))
9✔
538
    }
539

540
    /// Build a built-in expression and append it to the module.
541
    #[inline]
542
    pub fn builtin(&mut self, op: BuiltInOperator) -> ExprHandle {
30✔
543
        self.add_expr(Expr::BuiltIn(BuiltInExpr::new(op)))
90✔
544
    }
545

546
    /// Build a unary expression and append it to the module.
547
    ///
548
    /// The handle to the expression representing the operand of the unary
549
    /// operation must be valid, that is reference an expression
550
    /// contained in the current [`Module`].
551
    ///
552
    /// # Panics
553
    ///
554
    /// Panics in some cases if the operand handle do not reference an existing
555
    /// expression in the current module. Note however that this check can
556
    /// miss some invalid handles (false negative), so only represents an
557
    /// extra safety net that users shouldn't rely exclusively on
558
    /// to ensure the operand handles are valid. Instead, it's the
559
    /// responsibility of the user to ensure the operand handle references an
560
    /// existing expression in the current [`Module`].
561
    #[inline]
562
    pub fn unary(&mut self, op: UnaryOperator, inner: ExprHandle) -> ExprHandle {
38✔
563
        assert!(inner.index() < self.expressions.len());
152✔
564
        self.add_expr(Expr::Unary { op, expr: inner })
114✔
565
    }
566

567
    impl_module_unary!(abs, Abs);
568
    impl_module_unary!(acos, Acos);
569
    impl_module_unary!(asin, Asin);
570
    impl_module_unary!(atan, Atan);
571
    impl_module_unary!(all, All);
572
    impl_module_unary!(any, Any);
573
    impl_module_unary!(ceil, Ceil);
574
    impl_module_unary!(cos, Cos);
575
    impl_module_unary!(exp, Exp);
576
    impl_module_unary!(exp2, Exp2);
577
    impl_module_unary!(floor, Floor);
578
    impl_module_unary!(fract, Fract);
579
    impl_module_unary!(inverse_sqrt, InvSqrt);
580
    impl_module_unary!(length, Length);
581
    impl_module_unary!(log, Log);
582
    impl_module_unary!(log2, Log2);
583
    impl_module_unary!(normalize, Normalize);
584
    impl_module_unary!(pack4x8snorm, Pack4x8snorm);
585
    impl_module_unary!(pack4x8unorm, Pack4x8unorm);
586
    impl_module_unary!(round, Round);
587
    impl_module_unary!(saturate, Saturate);
588
    impl_module_unary!(sign, Sign);
589
    impl_module_unary!(sin, Sin);
590
    impl_module_unary!(sqrt, Sqrt);
591
    impl_module_unary!(tan, Tan);
592
    impl_module_unary!(unpack4x8snorm, Unpack4x8snorm);
593
    impl_module_unary!(unpack4x8unorm, Unpack4x8unorm);
594
    impl_module_unary!(w, W);
595
    impl_module_unary!(x, X);
596
    impl_module_unary!(y, Y);
597
    impl_module_unary!(z, Z);
598

599
    /// Build a binary expression and append it to the module.
600
    ///
601
    /// The handles to the expressions representing the left and right operands
602
    /// of the binary operation must be valid, that is reference expressions
603
    /// contained in the current [`Module`].
604
    ///
605
    /// # Panics
606
    ///
607
    /// Panics in some cases if either of the left or right operand handles do
608
    /// not reference existing expressions in the current module. Note however
609
    /// that this check can miss some invalid handles (false negative), so only
610
    /// represents an extra safety net that users shouldn't rely exclusively on
611
    /// to ensure the operand handles are valid. Instead, it's the
612
    /// responsibility of the user to ensure handles reference existing
613
    /// expressions in the current [`Module`].
614
    #[inline]
615
    pub fn binary(
35✔
616
        &mut self,
617
        op: BinaryOperator,
618
        left: ExprHandle,
619
        right: ExprHandle,
620
    ) -> ExprHandle {
621
        assert!(left.index() < self.expressions.len());
140✔
622
        assert!(right.index() < self.expressions.len());
140✔
623
        self.add_expr(Expr::Binary { op, left, right })
140✔
624
    }
625

626
    impl_module_binary!(add, Add);
627
    impl_module_binary!(atan2, Atan2);
628
    impl_module_binary!(cross, Cross);
629
    impl_module_binary!(distance, Distance);
630
    impl_module_binary!(div, Div);
631
    impl_module_binary!(dot, Dot);
632
    impl_module_binary!(ge, GreaterThanOrEqual);
633
    impl_module_binary!(gt, GreaterThan);
634
    impl_module_binary!(le, LessThanOrEqual);
635
    impl_module_binary!(lt, LessThan);
636
    impl_module_binary!(max, Max);
637
    impl_module_binary!(min, Min);
638
    impl_module_binary!(mul, Mul);
639
    impl_module_binary!(rem, Remainder);
640
    impl_module_binary!(step, Step);
641
    impl_module_binary!(sub, Sub);
642
    impl_module_binary!(uniform, UniformRand);
643
    impl_module_binary!(normal, NormalRand);
644
    impl_module_binary!(vec2, Vec2);
645
    impl_module_binary!(vec4_xyz_w, Vec4XyzW);
646

647
    /// Build a ternary expression and append it to the module.
648
    ///
649
    /// The handles to the expressions representing the three operands of the
650
    /// ternary operation must be valid, that is reference expressions
651
    /// contained in the current [`Module`].
652
    ///
653
    /// # Panics
654
    ///
655
    /// Panics in some cases if any of the operand handles do not reference
656
    /// existing expressions in the current module. Note however
657
    /// that this check can miss some invalid handles (false negative), so only
658
    /// represents an extra safety net that users shouldn't rely exclusively on
659
    /// to ensure the operand handles are valid. Instead, it's the
660
    /// responsibility of the user to ensure handles reference existing
661
    /// expressions in the current [`Module`].
662
    #[inline]
663
    pub fn ternary(
5✔
664
        &mut self,
665
        op: TernaryOperator,
666
        first: ExprHandle,
667
        second: ExprHandle,
668
        third: ExprHandle,
669
    ) -> ExprHandle {
670
        assert!(first.index() < self.expressions.len());
20✔
671
        assert!(second.index() < self.expressions.len());
20✔
672
        assert!(third.index() < self.expressions.len());
20✔
673
        self.add_expr(Expr::Ternary {
15✔
674
            op,
10✔
675
            first,
10✔
676
            second,
5✔
677
            third,
5✔
678
        })
679
    }
680

681
    impl_module_ternary!(mix, Mix);
682
    impl_module_ternary!(clamp, Clamp);
683
    impl_module_ternary!(smoothstep, SmoothStep);
684
    impl_module_ternary!(vec3, Vec3);
685

686
    /// Build a cast expression and append it to the module.
687
    ///
688
    /// The handle to the expressions representing the operand of the cast
689
    /// operation must be valid, that is reference expressions contained in
690
    /// the current [`Module`].
691
    ///
692
    /// # Panics
693
    ///
694
    /// Panics in some cases if the operand handle does not reference existing
695
    /// expressions in the current module. Note however that this check can
696
    /// miss some invalid handles (false negative), so only represents an
697
    /// extra safety net that users shouldn't rely exclusively on
698
    /// to ensure the operand handles are valid. Instead, it's the
699
    /// responsibility of the user to ensure handles reference existing
700
    /// expressions in the current [`Module`].
701
    ///
702
    /// Panics if the resulting cast expression is not valid. See
703
    /// [`CastExpr::is_valid()`] for the exact meaning.
704
    pub fn cast(&mut self, expr: ExprHandle, target: impl Into<ValueType>) -> ExprHandle {
9✔
705
        assert!(expr.index() < self.expressions.len());
36✔
706
        let target = target.into();
27✔
707
        let expr = CastExpr::new(expr, target);
36✔
708
        if let Some(valid) = expr.is_valid(self) {
27✔
709
            assert!(valid);
×
710
        }
711
        self.add_expr(Expr::Cast(expr))
4✔
712
    }
713

714
    /// Get an existing expression from its handle.
715
    #[inline]
716
    pub fn get(&self, expr: ExprHandle) -> Option<&Expr> {
20✔
717
        let index = expr.index();
60✔
718
        self.expressions.get(index)
40✔
719
    }
720

721
    /// Get an existing expression from its handle.
722
    #[inline]
723
    pub fn get_mut(&mut self, expr: ExprHandle) -> Option<&mut Expr> {
2✔
724
        let index = expr.index();
6✔
725
        self.expressions.get_mut(index)
4✔
726
    }
727

728
    /// Get an existing expression from its handle.
729
    #[inline]
730
    pub fn try_get(&self, expr: ExprHandle) -> Result<&Expr, ExprError> {
272✔
731
        let index = expr.index();
816✔
732
        self.expressions
544✔
733
            .get(index)
272✔
734
            .ok_or(ExprError::InvalidExprHandleError(format!(
544✔
735
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
272✔
736
    }
737

738
    /// Get an existing expression from its handle.
739
    #[inline]
740
    pub fn try_get_mut(&mut self, expr: ExprHandle) -> Result<&mut Expr, ExprError> {
2✔
741
        let index = expr.index();
6✔
742
        self.expressions
4✔
743
            .get_mut(index)
2✔
744
            .ok_or(ExprError::InvalidExprHandleError(format!(
4✔
745
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
2✔
746
    }
747

748
    /// Is the expression resulting in a compile-time constant which can be
749
    /// hard-coded into a shader's code?
750
    ///
751
    /// # Panics
752
    ///
753
    /// Panics if `expr` doesn't refer to an expression of this module.
754
    #[inline]
755
    pub fn is_const(&self, expr: ExprHandle) -> bool {
×
756
        let expr = self.get(expr).unwrap();
×
757
        expr.is_const(self)
×
758
    }
759

760
    /// Has the expression any side-effect?
761
    ///
762
    /// Expressions with side-effect need to be stored into temporary variables
763
    /// when the shader code is emitted, so that the side effect is only applied
764
    /// once when the expression is reused in multiple locations.
765
    ///
766
    /// # Panics
767
    ///
768
    /// Panics if `expr` doesn't refer to an expression of this module.
769
    pub fn has_side_effect(&self, expr: ExprHandle) -> bool {
×
770
        let expr = self.get(expr).unwrap();
×
771
        expr.has_side_effect(self)
×
772
    }
773

774
    /// Get the texture layout of this module.
775
    pub fn texture_layout(&self) -> TextureLayout {
342✔
776
        self.texture_layout.clone()
684✔
777
    }
778
}
779

780
/// Errors raised when manipulating expressions [`Expr`] and node graphs
781
/// [`Graph`].
782
///
783
/// [`Graph`]: crate::graph::Graph
784
#[derive(Debug, Clone, PartialEq, Eq, Error)]
785
pub enum ExprError {
786
    /// Expression type error.
787
    ///
788
    /// Generally used for invalid type conversion (casting).
789
    #[error("Type error: {0}")]
790
    TypeError(String),
791

792
    /// Expression syntax error.
793
    #[error("Syntax error: {0}")]
794
    SyntaxError(String),
795

796
    /// Generic graph evaluation error.
797
    #[error("Graph evaluation error: {0}")]
798
    GraphEvalError(String),
799

800
    /// Error resolving a property.
801
    ///
802
    /// An unknown property was not defined in the evaluation context, which
803
    /// usually means that the property was not defined with
804
    /// [`Module::add_property()`].
805
    #[error("Property error: {0}")]
806
    PropertyError(String),
807

808
    /// Invalid expression handle not referencing any existing [`Expr`] in the
809
    /// evaluation [`Module`].
810
    ///
811
    /// This error is commonly raised when using an [`ExprWriter`] and
812
    /// forgetting to transfer the underlying [`Module`] where the expressions
813
    /// are written to the [`EffectAsset`]. See [`ExprWriter`] for details.
814
    ///
815
    /// [`EffectAsset`]: crate::EffectAsset
816
    #[error("Invalid expression handle: {0}")]
817
    InvalidExprHandleError(String),
818

819
    /// Invalid modifier context.
820
    ///
821
    /// The operation was expecting a given [`ModifierContext`], but instead
822
    /// another [`ModifierContext`] was available.
823
    #[error("Invalid modifier context {0}, expected {1} instead.")]
824
    InvalidModifierContext(ModifierContext, ModifierContext),
825
}
826

827
/// Evaluation context for transforming expressions into WGSL code.
828
///
829
/// The evaluation context references a [`Module`] storing all [`Expr`] in use,
830
/// as well as a [`ParticleLayout`] defining the existing attributes of each
831
/// particle and their layout in memory, and a [`PropertyLayout`] defining
832
/// existing properties and their layout in memory. These together define the
833
/// context within which expressions are evaluated.
834
///
835
/// A same expression can be valid in one context and invalid in another. The
836
/// most obvious example is a [`PropertyExpr`] which is only valid if the
837
/// property is actually defined in the property layout of the evaluation
838
/// context.
839
pub trait EvalContext {
840
    /// Get the modifier context of the evaluation.
841
    fn modifier_context(&self) -> ModifierContext;
842

843
    /// Get the particle layout of the effect.
844
    fn particle_layout(&self) -> &ParticleLayout;
845

846
    /// Get the property layout of the effect.
847
    fn property_layout(&self) -> &PropertyLayout;
848

849
    /// Evaluate an expression, returning its WGSL shader code.
850
    ///
851
    /// The evaluation is guaranteed to be unique. Calling `eval()` multiple
852
    /// times with the same handle will return the same result. If the
853
    /// expression referenced by `handle` has side effects, it's evaluated only
854
    /// once on first call, stored in a local variable, and the variable cached
855
    /// and returned on subsequent calls.
856
    fn eval(&mut self, module: &Module, handle: ExprHandle) -> Result<String, ExprError>;
857

858
    /// Generate a unique local variable name.
859
    ///
860
    /// Each time this function is called, a new unique name is generated. The
861
    /// name is guaranteed to be unique within the current evaluation context
862
    /// only. Do not use for global top-level identifiers.
863
    ///
864
    /// The variable name is not registered automatically in the [`Module`]. If
865
    /// you call `make_local_var()` but doesn't use the returned name, it won't
866
    /// appear in the shader.
867
    fn make_local_var(&mut self) -> String;
868

869
    /// Push an intermediate statement during an evaluation.
870
    ///
871
    /// Intermediate statements are inserted before the expression evaluation
872
    /// which produced them. They're generally used to define temporary local
873
    /// variables, for example to store the result of expressions with side
874
    /// effects.
875
    fn push_stmt(&mut self, stmt: &str);
876

877
    /// Create a function.
878
    ///
879
    /// Create a new function with the given `func_name` inside the given
880
    /// [`Module`]. The function takes a list of arguments `args`, which are
881
    /// copied verbatim into the shader code without any validation. The body of
882
    /// the function is generated by invoking the given closure once with the
883
    /// input `module` and a temporary [`EvalContext`] local to the function.
884
    /// The closure must return the generated shader code of the function
885
    /// body. Any statement pushed to the temporary function context with
886
    /// [`EvalContext::push_stmt()`] is emitted inside the function body before
887
    /// the returned code. The function can subsequently be called from the
888
    /// parent context by generating code to call `func_name`, with the correct
889
    /// arguments.
890
    fn make_fn(
891
        &mut self,
892
        func_name: &str,
893
        args: &str,
894
        module: &mut Module,
895
        f: &mut dyn FnMut(&mut Module, &mut dyn EvalContext) -> Result<String, ExprError>,
896
    ) -> Result<(), ExprError>;
897

898
    /// Check if the particle attribute struct is a pointer?
899
    ///
900
    /// In some context the attribute struct (named 'particle' in WGSL code) is
901
    /// a pointer instead of being a struct instance. This happens in particular
902
    /// when defining a function for a modifier, and passing the attribute
903
    /// struct to be modified. In that case the generated code needs to emit
904
    /// a pointer indirection code to access the fields of the struct.
905
    fn is_attribute_pointer(&self) -> bool;
906
}
907

908
/// Language expression producing a value.
909
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
910
pub enum Expr {
911
    /// Built-in expression ([`BuiltInExpr`]).
912
    ///
913
    /// A built-in expression provides access to some internal
914
    /// quantities like the simulation time.
915
    BuiltIn(BuiltInExpr),
916

917
    /// Literal expression ([`LiteralExpr`]).
918
    ///
919
    /// A literal expression represents a shader constants.
920
    Literal(LiteralExpr),
921

922
    /// Property expression ([`PropertyExpr`]).
923
    ///
924
    /// A property expression represents the value of an [`EffectAsset`]'s
925
    /// property.
926
    ///
927
    /// [`EffectAsset`]: crate::EffectAsset
928
    Property(PropertyExpr),
929

930
    /// Attribute expression ([`AttributeExpr`]).
931
    ///
932
    /// An attribute expression represents the value of an attribute for a
933
    /// particle, like its position or velocity.
934
    Attribute(AttributeExpr),
935

936
    /// Attribute expression ([`AttributeExpr`]) from a parent effect.
937
    ///
938
    /// An attribute expression represents the value of an attribute for a
939
    /// particle, like its position or velocity. This attribute however refers
940
    /// to the parent particle which spawned this one, via GPU events.
941
    ///
942
    /// This attribute is only valid when used in init modifiers, from an effect
943
    /// with a parent effect (an effect which has an [`EffectParent`]
944
    /// component).
945
    ///
946
    /// [`EffectParent`]: crate::EffectParent
947
    ParentAttribute(AttributeExpr),
948

949
    /// Unary operation expression.
950
    ///
951
    /// A unary operation transforms an expression into another expression.
952
    Unary {
953
        /// Unary operator.
954
        op: UnaryOperator,
955
        /// Operand the unary operation applies to.
956
        expr: ExprHandle,
957
    },
958

959
    /// Binary operation expression.
960
    ///
961
    /// A binary operation composes two expressions into a third one.
962
    Binary {
963
        /// Binary operator.
964
        op: BinaryOperator,
965
        /// Left-hand side operand the binary operation applies to.
966
        left: ExprHandle,
967
        /// Right-hand side operand the binary operation applies to.
968
        right: ExprHandle,
969
    },
970

971
    /// Ternary operation expression.
972
    ///
973
    /// A ternary operation composes three expressions into a fourth one.
974
    Ternary {
975
        /// Ternary operator.
976
        op: TernaryOperator,
977
        /// First operand the ternary operation applies to.
978
        first: ExprHandle,
979
        /// Second operand the ternary operation applies to.
980
        second: ExprHandle,
981
        /// Third operand the ternary operation applies to.
982
        third: ExprHandle,
983
    },
984

985
    /// Cast expression.
986
    ///
987
    /// An expression to cast an expression to another type.
988
    Cast(CastExpr),
989

990
    /// Access to textures.
991
    ///
992
    /// An expression to sample a texture from the effect's material. Currently
993
    /// only color textures (returning a `vec4<f32>`) are supported.
994
    TextureSample(TextureSampleExpr),
995
}
996

997
impl Expr {
998
    /// Is the expression resulting in a compile-time constant which can be
999
    /// hard-coded into a shader's code?
1000
    ///
1001
    /// The [`Module`] passed as argument is the owning module of the
1002
    /// expression, which is used to recursively evaluate the const-ness of the
1003
    /// entire expression. For some expressions like literals or attributes or
1004
    /// properties their const-ness is intrinsic to the expression type, but for
1005
    /// other expressions like binary operations (addition, ...) their
1006
    /// const-ness depends in turn on the const-ness of their sub-expressions
1007
    /// (left and right operands), which requires a [`Module`] to be retrieved
1008
    /// and evaluated.
1009
    ///
1010
    /// # Example
1011
    ///
1012
    /// ```
1013
    /// # use bevy_hanabi::*;
1014
    /// # let mut module = Module::default();
1015
    /// // Literals are always constant by definition.
1016
    /// assert!(Expr::Literal(LiteralExpr::new(1.)).is_const(&module));
1017
    ///
1018
    /// // Properties and attributes are never constant, since they're by definition used
1019
    /// // to provide runtime customization.
1020
    /// let prop = module.add_property("my_property", 3.0.into());
1021
    /// assert!(!Expr::Property(PropertyExpr::new(prop)).is_const(&module));
1022
    /// assert!(!Expr::Attribute(AttributeExpr::new(Attribute::POSITION)).is_const(&module));
1023
    /// ```
1024
    pub fn is_const(&self, module: &Module) -> bool {
×
1025
        match self {
×
1026
            Expr::BuiltIn(expr) => expr.is_const(),
×
1027
            Expr::Literal(expr) => expr.is_const(),
×
1028
            Expr::Property(expr) => expr.is_const(),
×
1029
            Expr::Attribute(expr) => expr.is_const(),
×
1030
            Expr::ParentAttribute(expr) => expr.is_const(),
×
1031
            Expr::Unary { expr, .. } => module.is_const(*expr),
×
1032
            Expr::Binary { left, right, .. } => module.is_const(*left) && module.is_const(*right),
×
1033
            Expr::Ternary {
1034
                first,
×
1035
                second,
×
1036
                third,
×
1037
                ..
1038
            } => module.is_const(*first) && module.is_const(*second) && module.is_const(*third),
×
1039
            Expr::Cast(expr) => module.is_const(expr.inner),
×
1040
            Expr::TextureSample(_) => false,
×
1041
        }
1042
    }
1043

1044
    /// Has the expression any side-effect?
1045
    ///
1046
    /// Expressions with side-effect need to be stored into temporary variables
1047
    /// when the shader code is emitted, so that the side effect is only applied
1048
    /// once when the expression is reused in multiple locations.
1049
    pub fn has_side_effect(&self, _: &Module) -> bool {
40✔
1050
        match self {
40✔
1051
            Expr::BuiltIn(expr) => expr.has_side_effect(),
×
1052
            Expr::Literal(_) => false,
×
1053
            Expr::Property(_) => false,
×
1054
            Expr::Attribute(_) => false,
×
1055
            Expr::ParentAttribute(_) => false,
×
1056
            Expr::Unary { .. } => false,
×
1057
            Expr::Binary { op, .. } => {
40✔
1058
                *op == BinaryOperator::UniformRand || *op == BinaryOperator::NormalRand
80✔
1059
            }
1060
            Expr::Ternary { .. } => false,
×
1061
            Expr::Cast(_) => false,
×
1062
            Expr::TextureSample(_) => false,
×
1063
        }
1064
    }
1065

1066
    /// The type of the value produced by the expression.
1067
    ///
1068
    /// If the type is variable and depends on the runtime evaluation context,
1069
    /// this returns `None`. In that case the type needs to be obtained by
1070
    /// evaluating the expression with [`eval()`].
1071
    ///
1072
    /// # Example
1073
    ///
1074
    /// ```
1075
    /// # use bevy_hanabi::*;
1076
    /// // Literal expressions always have a constant, build-time value type.
1077
    /// let expr = Expr::Literal(LiteralExpr::new(1.));
1078
    /// assert_eq!(
1079
    ///     expr.value_type(),
1080
    ///     Some(ValueType::Scalar(ScalarType::Float))
1081
    /// );
1082
    /// ```
1083
    ///
1084
    /// [`eval()`]: crate::graph::Expr::eval
1085
    pub fn value_type(&self) -> Option<ValueType> {
25✔
1086
        match self {
25✔
1087
            Expr::BuiltIn(expr) => Some(expr.value_type()),
×
1088
            Expr::Literal(expr) => Some(expr.value_type()),
42✔
1089
            Expr::Property(_) => None,
1✔
1090
            Expr::Attribute(expr) => Some(expr.value_type()),
6✔
1091
            Expr::ParentAttribute(expr) => Some(expr.value_type()),
×
1092
            Expr::Unary { .. } => None,
×
1093
            Expr::Binary { .. } => None,
×
1094
            Expr::Ternary { .. } => None,
×
1095
            Expr::Cast(expr) => Some(expr.value_type()),
×
1096
            Expr::TextureSample(expr) => Some(expr.value_type()),
×
1097
        }
1098
    }
1099

1100
    /// Evaluate the expression in the given context.
1101
    ///
1102
    /// Evaluate the full expression as part of the given evaluation context,
1103
    /// returning the WGSL string representation of the expression on success.
1104
    ///
1105
    /// The evaluation context is used to resolve some quantities related to the
1106
    /// effect asset, like its properties. It also holds the [`Module`] that the
1107
    /// expression is part of, to allow resolving sub-expressions of operators.
1108
    ///
1109
    /// # Example
1110
    ///
1111
    /// ```
1112
    /// # use bevy_hanabi::*;
1113
    /// let mut module = Module::default();
1114
    /// # let pl = PropertyLayout::empty();
1115
    /// # let pal = ParticleLayout::default();
1116
    /// # let mut context = ShaderWriter::new(ModifierContext::Update, &pl, &pal);
1117
    /// let handle = module.lit(1.);
1118
    /// let expr = module.get(handle).unwrap();
1119
    /// assert_eq!(Ok("1.".to_string()), expr.eval(&module, &mut context));
1120
    /// ```
1121
    pub fn eval(
257✔
1122
        &self,
1123
        module: &Module,
1124
        context: &mut dyn EvalContext,
1125
    ) -> Result<String, ExprError> {
1126
        match self {
257✔
1127
            Expr::BuiltIn(expr) => expr.eval(context),
34✔
1128
            Expr::Literal(expr) => expr.eval(context),
416✔
1129
            Expr::Property(expr) => expr.eval(module, context),
10✔
1130
            Expr::Attribute(expr) => expr.eval(context, false),
120✔
1131
            Expr::ParentAttribute(expr) => expr.eval(context, true),
×
1132
            Expr::Unary { op, expr } => {
76✔
1133
                // Recursively evaluate child expressions throught the context to ensure caching
1134
                let expr = context.eval(module, *expr)?;
190✔
1135

1136
                // if expr.value_type() != self.value_type() {
1137
                //     return Err(ExprError::TypeError(format!(
1138
                //         "Cannot apply normalize() function to non-vector expression: {}",
1139
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1140
                //     )));
1141
                // }
1142

1143
                Ok(if op.is_functional() {
1144
                    format!("{}({})", op.to_wgsl_string(), expr)
102✔
1145
                } else {
1146
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1147
                })
1148
            }
1149
            Expr::Binary { op, left, right } => {
120✔
1150
                // Recursively evaluate child expressions throught the context to ensure caching
1151
                let compiled_left = context.eval(module, *left)?;
200✔
1152
                let compiled_right = context.eval(module, *right)?;
40✔
1153

1154
                // if !self.input.value_type().is_vector() {
1155
                //     return Err(ExprError::TypeError(format!(
1156
                //         "Cannot apply normalize() function to non-vector expression: {}",
1157
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1158
                //     )));
1159
                // }
1160

1161
                let body = if op.is_functional() {
40✔
1162
                    if op.needs_type_suffix() {
26✔
1163
                        let lhs_type = module.get(*left).and_then(|arg| arg.value_type());
×
1164
                        let rhs_type = module.get(*right).and_then(|arg| arg.value_type());
×
1165
                        if lhs_type.is_none() || rhs_type.is_none() {
×
1166
                            return Err(ExprError::TypeError(
×
1167
                                "Can't determine the type of the operand".to_string(),
×
1168
                            ));
1169
                        }
1170
                        if lhs_type != rhs_type {
1171
                            return Err(ExprError::TypeError("Mismatched types".to_string()));
×
1172
                        }
1173
                        let value_type = lhs_type.unwrap();
1174
                        let suffix = match value_type {
×
1175
                            ValueType::Scalar(ScalarType::Float) => "f",
×
1176
                            ValueType::Vector(vector_type)
×
1177
                                if vector_type.elem_type() == ScalarType::Float =>
×
1178
                            {
1179
                                match vector_type.count() {
×
1180
                                    2 => "vec2",
×
1181
                                    3 => "vec3",
×
1182
                                    4 => "vec4",
×
1183
                                    _ => unreachable!(),
1184
                                }
1185
                            }
1186
                            _ => {
1187
                                // Add more types here as needed.
1188
                                return Err(ExprError::TypeError("Unsupported type".to_string()));
×
1189
                            }
1190
                        };
1191

1192
                        Ok(format!(
1193
                            "{}_{}({}, {})",
1194
                            op.to_wgsl_string(),
1195
                            suffix,
1196
                            compiled_left,
1197
                            compiled_right
1198
                        ))
1199
                    } else {
1200
                        Ok(format!(
13✔
1201
                            "{}({}, {})",
13✔
1202
                            op.to_wgsl_string(),
13✔
1203
                            compiled_left,
13✔
1204
                            compiled_right
13✔
1205
                        ))
1206
                    }
1207
                } else {
1208
                    Ok(format!(
27✔
1209
                        "({}) {} ({})",
27✔
1210
                        compiled_left,
27✔
1211
                        op.to_wgsl_string(),
27✔
1212
                        compiled_right
27✔
1213
                    ))
1214
                };
1215

1216
                body.map(|body| {
40✔
1217
                    check_side_effects_and_create_local_if_needed(
40✔
1218
                        context,
40✔
1219
                        body,
40✔
1220
                        self.has_side_effect(module),
120✔
1221
                    )
1222
                })
1223
            }
1224
            Expr::Ternary {
1225
                op,
5✔
1226
                first,
5✔
1227
                second,
5✔
1228
                third,
5✔
1229
            } => {
1230
                // Recursively evaluate child expressions throught the context to ensure caching
1231
                let first = context.eval(module, *first)?;
25✔
1232
                let second = context.eval(module, *second)?;
5✔
1233
                let third = context.eval(module, *third)?;
5✔
1234

1235
                // if !self.input.value_type().is_vector() {
1236
                //     return Err(ExprError::TypeError(format!(
1237
                //         "Cannot apply normalize() function to non-vector expression: {}",
1238
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1239
                //     )));
1240
                // }
1241

1242
                Ok(format!(
1243
                    "{}({}, {}, {})",
1244
                    op.to_wgsl_string(),
1245
                    first,
1246
                    second,
1247
                    third
1248
                ))
1249
            }
1250
            Expr::Cast(expr) => {
4✔
1251
                // Recursively evaluate child expressions throught the context to ensure caching
1252
                let inner = context.eval(module, expr.inner)?;
20✔
1253

1254
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
1255
            }
1256
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1257
        }
1258
    }
1259
}
1260

1261
/// A literal constant expression like `3.0` or `vec3<f32>(1.0, 2.0, 3.0)`.
1262
///
1263
/// Literal expression are compile-time constants. They are always constant
1264
/// ([`is_const()`] is `true`) and have a value type equal to the type of the
1265
/// constant itself.
1266
///
1267
/// [`is_const()`]: LiteralExpr::is_const
1268
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
1269
#[serde(transparent)]
1270
pub struct LiteralExpr {
1271
    /// The literal value of this expression.
1272
    pub value: Value,
1273
}
1274

1275
impl LiteralExpr {
1276
    /// Create a new literal expression from a [`Value`].
1277
    pub fn new<V>(value: V) -> Self
340✔
1278
    where
1279
        Value: From<V>,
1280
    {
1281
        Self {
1282
            value: value.into(),
340✔
1283
        }
1284
    }
1285

1286
    /// Is the expression resulting in a compile-time constant which can be
1287
    /// hard-coded into a shader's code?
1288
    pub fn is_const(&self) -> bool {
×
1289
        true
×
1290
    }
1291

1292
    /// Get the value type of the expression.
1293
    pub fn value_type(&self) -> ValueType {
21✔
1294
        self.value.value_type()
42✔
1295
    }
1296

1297
    /// Evaluate the expression in the given context.
1298
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
104✔
1299
        Ok(self.value.to_wgsl_string())
104✔
1300
    }
1301
}
1302

1303
impl ToWgslString for LiteralExpr {
1304
    fn to_wgsl_string(&self) -> String {
×
1305
        self.value.to_wgsl_string()
×
1306
    }
1307
}
1308

1309
impl From<&Value> for LiteralExpr {
1310
    fn from(value: &Value) -> Self {
×
1311
        Self { value: *value }
×
1312
    }
1313
}
1314

1315
impl<T: Into<Value>> From<T> for LiteralExpr {
1316
    fn from(value: T) -> Self {
×
1317
        Self {
1318
            value: value.into(),
×
1319
        }
1320
    }
1321
}
1322

1323
/// Expression representing the value of an attribute of a particle.
1324
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1325
pub struct AttributeExpr {
1326
    /// The attribute this expression represents.
1327
    ///
1328
    /// The expression evaluates to the value of this attribute at the time of
1329
    /// evaluation.
1330
    pub attr: Attribute,
1331
}
1332

1333
impl AttributeExpr {
1334
    /// Create a new attribute expression.
1335
    #[inline]
1336
    pub fn new(attr: Attribute) -> Self {
32✔
1337
        Self { attr }
1338
    }
1339

1340
    /// Is the expression resulting in a compile-time constant which can be
1341
    /// hard-coded into a shader's code?
1342
    pub fn is_const(&self) -> bool {
×
1343
        false
×
1344
    }
1345

1346
    /// Get the value type of the expression.
1347
    pub fn value_type(&self) -> ValueType {
3✔
1348
        self.attr.value_type()
6✔
1349
    }
1350

1351
    /// Evaluate the expression in the given context.
1352
    pub fn eval(&self, context: &dyn EvalContext, parent: bool) -> Result<String, ExprError> {
30✔
1353
        if self.attr == Attribute::ID {
30✔
1354
            // Pseudo-attribute, not stored in the particle buffer
1355
            Ok(if parent {
×
1356
                "parent_particle_index"
×
1357
            } else {
1358
                "particle_index"
×
1359
            }
1360
            .to_string())
×
1361
        } else if self.attr == Attribute::PARTICLE_COUNTER {
30✔
1362
            // Pseudo-attribute, not stored in the particle buffer
1363
            Ok("particle_counter".to_string())
×
1364
        } else {
1365
            let owner = if parent {
30✔
1366
                "parent_particle"
×
1367
            } else {
1368
                "particle"
30✔
1369
            };
1370
            if context.is_attribute_pointer() {
1371
                Ok(format!("(*{}).{}", owner, self.attr.name()))
4✔
1372
            } else {
1373
                Ok(format!("{}.{}", owner, self.attr.name()))
28✔
1374
            }
1375
        }
1376
    }
1377
}
1378

1379
impl ToWgslString for AttributeExpr {
1380
    fn to_wgsl_string(&self) -> String {
×
1381
        format!("particle.{}", self.attr.name())
×
1382
    }
1383
}
1384

1385
impl From<Attribute> for AttributeExpr {
1386
    fn from(value: Attribute) -> Self {
×
1387
        AttributeExpr::new(value)
×
1388
    }
1389
}
1390

1391
/// Expression representing the value of a property of an effect.
1392
///
1393
/// A property expression represents the value of the property at the time the
1394
/// expression appears. In shader, the expression yields a read from the
1395
/// property memory location.
1396
///
1397
/// To create a property to reference with an expression, use
1398
/// [`Module::add_property()`].
1399
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1400
#[repr(transparent)]
1401
#[serde(transparent)]
1402
pub struct PropertyExpr {
1403
    /// The property this expression represents.
1404
    ///
1405
    /// The expression evaluates to the value of this property at the time of
1406
    /// evaluation.
1407
    pub property: PropertyHandle,
1408
}
1409

1410
impl PropertyExpr {
1411
    /// Create a new property expression.
1412
    #[inline]
1413
    pub fn new(property: PropertyHandle) -> Self {
4✔
1414
        Self { property }
1415
    }
1416

1417
    /// Is the expression resulting in a compile-time constant which can be
1418
    /// hard-coded into a shader's code?
1419
    pub fn is_const(&self) -> bool {
×
1420
        false
×
1421
    }
1422

1423
    /// Evaluate the expression in the given context.
1424
    pub fn eval(&self, module: &Module, context: &dyn EvalContext) -> Result<String, ExprError> {
2✔
1425
        let prop = module
4✔
1426
            .get_property(self.property)
4✔
1427
            .ok_or(ExprError::PropertyError(format!(
4✔
1428
                "Unknown property handle {:?} in evaluation module.",
2✔
1429
                self.property
2✔
1430
            )))?;
1431
        if !context.property_layout().contains(prop.name()) {
1432
            return Err(ExprError::PropertyError(format!(
×
1433
                "Unknown property '{}' in evaluation layout.",
×
1434
                prop.name()
×
1435
            )));
1436
        }
1437

1438
        Ok(prop.to_wgsl_string())
2✔
1439
    }
1440
}
1441

1442
/// Expression to cast an expression to another type.
1443
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1444
pub struct CastExpr {
1445
    /// The operand expression to cast.
1446
    pub inner: ExprHandle,
1447
    /// The target type to cast to.
1448
    pub target: ValueType,
1449
}
1450

1451
impl CastExpr {
1452
    /// Create a new cast expression.
1453
    #[inline]
1454
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1455
        Self {
1456
            inner,
1457
            target: target.into(),
12✔
1458
        }
1459
    }
1460

1461
    /// Get the value type of the expression.
1462
    ///
1463
    /// This is the target type the cast converts to.
1464
    pub fn value_type(&self) -> ValueType {
3✔
1465
        self.target
3✔
1466
    }
1467

1468
    /// Try to evaluate if the cast expression is valid.
1469
    ///
1470
    /// The evaluation fails if the value type of the operand cannot be
1471
    /// determined. In that case, the function returns `None`. This doesn't mean
1472
    /// the cast expression is invalid, but rather that we cannot currently
1473
    /// evaluate it, as it likely depends on the runtime context in which it's
1474
    /// used.
1475
    ///
1476
    /// Valid cast expressions are:
1477
    /// - scalar to scalar
1478
    /// - scalar to vector
1479
    /// - vector to vector
1480
    /// - matrix to matrix
1481
    ///
1482
    /// # Returns
1483
    ///
1484
    /// - `Some(is_valid)` if the evaluation was successful in determining
1485
    ///   whether the expression is valid or not.
1486
    /// - `None` if the expression couldn't be evaluated, and so couldn't be
1487
    ///   validated. This generally happens when the inner expression has a
1488
    ///   value type unknown statically (depends on runtime context), which
1489
    ///   prevents evaluating whether the cast expression is valid.
1490
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
12✔
1491
        let Some(inner) = module.get(self.inner) else {
36✔
1492
            return Some(false);
×
1493
        };
1494
        if let Some(inner_type) = inner.value_type() {
11✔
1495
            match self.target {
1496
                ValueType::Scalar(_) => {
1497
                    // scalar -> scalar only
1498
                    Some(matches!(inner_type, ValueType::Scalar(_)))
8✔
1499
                }
1500
                ValueType::Vector(_) => {
1501
                    // {scalar, vector} -> vector
1502
                    Some(!matches!(inner_type, ValueType::Matrix(_)))
7✔
1503
                }
1504
                ValueType::Matrix(_) => {
1505
                    // matrix -> matrix only
1506
                    Some(matches!(inner_type, ValueType::Matrix(_)))
4✔
1507
                }
1508
            }
1509
        } else {
1510
            None
1✔
1511
        }
1512
    }
1513
}
1514

1515
/// Expression to sample a texture from the effect's material.
1516
///
1517
/// This currently supports only 4-component textures sampled with [the WGSL
1518
/// `textureSample()` function], that is all textures which return a `vec4<f32>`
1519
/// when sampled. This is the case of most color textures, including
1520
/// single-channel (e.g. red) textures which return zero for missing components,
1521
/// but excludes depth textures.
1522
///
1523
/// [the WGSL `textureSample()` function]: https://www.w3.org/TR/WGSL/#texturesample
1524
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1525
pub struct TextureSampleExpr {
1526
    /// The index of the image to sample. This is the texture slot defined in
1527
    /// the [`Module`]. The texture bound to the slot is defined in the
1528
    /// [`EffectMaterial`] component.
1529
    ///
1530
    /// [`EffectMaterial`]: crate::EffectMaterial
1531
    pub image: ExprHandle,
1532
    /// The coordinates to sample at.
1533
    pub coordinates: ExprHandle,
1534
}
1535

1536
impl TextureSampleExpr {
1537
    /// Create a new texture sample expression.
1538
    #[inline]
1539
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1540
        Self { image, coordinates }
1541
    }
1542

1543
    /// Get the value type of the expression.
1544
    pub fn value_type(&self) -> ValueType {
×
1545
        // FIXME - depth textures return a single f32 when sampled
1546
        ValueType::Vector(VectorType::VEC4F)
×
1547
    }
1548

1549
    /// Try to evaluate if the texture sample expression is valid.
1550
    ///
1551
    /// This only checks that the expressions exist in the module.
1552
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
×
1553
        let Some(_image) = module.get(self.image) else {
×
1554
            return Some(false);
×
1555
        };
1556
        let Some(_coordinates) = module.get(self.coordinates) else {
×
1557
            return Some(false);
×
1558
        };
1559
        Some(true)
×
1560
    }
1561

1562
    /// Evaluate the expression in the given context.
1563
    pub fn eval(
×
1564
        &self,
1565
        module: &Module,
1566
        context: &mut dyn EvalContext,
1567
    ) -> Result<String, ExprError> {
1568
        let image = module.try_get(self.image)?;
×
1569
        let image = image.eval(module, context)?;
×
1570
        let coordinates = module.try_get(self.coordinates)?;
×
1571
        let coordinates = coordinates.eval(module, context)?;
×
1572
        Ok(format!(
1573
            "textureSample(material_texture_{image}, material_sampler_{image}, {coordinates})",
1574
        ))
1575
    }
1576
}
1577

1578
/// Built-in operators.
1579
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1580
pub enum BuiltInOperator {
1581
    /// Current effect system simulation time since startup, in seconds.
1582
    ///
1583
    /// This is based on the
1584
    /// [`Time<EffectSimulation>`](crate::time::EffectSimulation) clock.
1585
    ///
1586
    /// Type: `f32`
1587
    Time,
1588
    /// Delta time, in seconds, since last effect system update.
1589
    ///
1590
    /// Type: `f32`
1591
    DeltaTime,
1592
    /// Current virtual time since startup, in seconds.
1593
    ///
1594
    /// This is based on the [`Time<Virtual>`](bevy::time::Virtual) clock.
1595
    ///
1596
    /// Type: `f32`
1597
    VirtualTime,
1598
    /// Virtual delta time, in seconds, since last effect system update.
1599
    ///
1600
    /// Type: `f32`
1601
    VirtualDeltaTime,
1602
    /// Current real time since startup, in seconds.
1603
    ///
1604
    /// This is based on the [`Time<Time>`](bevy::time::Real) clock.
1605
    ///
1606
    /// Type: `f32`
1607
    RealTime,
1608
    /// Real delta time, in seconds, since last effect system update.
1609
    ///
1610
    /// Type: `f32`
1611
    RealDeltaTime,
1612
    /// Random unit value of the given type.
1613
    ///
1614
    /// The type can be any scalar or vector type. Matrix types are not
1615
    /// supported. The random values generated are uniformly distributed in
1616
    /// `[0:1]`. For vectors, each component is sampled separately.
1617
    ///
1618
    /// The random number generator is from [the PCG family] of PRNGs, and is
1619
    /// implemented directly inside the shader, and running on the GPU
1620
    /// exclusively. It's seeded by the [`SpawnerSettings`].
1621
    ///
1622
    /// Type: Same as its [`ValueType`].
1623
    ///
1624
    /// [the PCG family]: https://www.pcg-random.org/
1625
    /// [`SpawnerSettings`]: crate::SpawnerSettings
1626
    Rand(ValueType),
1627
    /// Value of the alpha cutoff for alpha masking.
1628
    ///
1629
    /// This value is only available in the render context. It represents the
1630
    /// current threshold, generally in \[0:1\], which the particle's fragment
1631
    /// alpha value will be compared against to determine alpha masking.
1632
    ///
1633
    /// The value is initalized at the beginning of the fragment shader to the
1634
    /// expression stored in [`AlphaMode::Mask`].
1635
    ///
1636
    /// Type: `f32`
1637
    ///
1638
    /// [`AlphaMode::Mask`]: crate::AlphaMode::Mask
1639
    AlphaCutoff,
1640
    /// Alive flag for the particle.
1641
    ///
1642
    /// The alive flag is initialized at the beginning of the update pass:
1643
    /// - If the particle has both the [`Attribute::AGE`] and
1644
    ///   [`Attribute::LIFETIME`], then the initial value at the beginning of
1645
    ///   the update pass is `age < lifetime`.
1646
    /// - Otherwise, the initial value is `true`.
1647
    ///
1648
    /// At the end of the update pass, if the particle has both the
1649
    /// [`Attribute::AGE`] and [`Attribute::LIFETIME`], then the flag is
1650
    /// re-evaluated as:
1651
    ///
1652
    /// ```wgsl
1653
    /// is_alive = is_alive && (particle.age < particle.lifetime);
1654
    /// ```
1655
    ///
1656
    /// If the flag is `false` after that, the particle is considered dead and
1657
    /// it's deallocated.
1658
    ///
1659
    /// This flag is only available in the update pass. Attempting to use it
1660
    /// inside either the init or render passes will generate an invalid shader.
1661
    ///
1662
    /// Type: `bool`
1663
    IsAlive,
1664
}
1665

1666
impl BuiltInOperator {
1667
    /// Get the operator name.
1668
    pub fn name(&self) -> &str {
49✔
1669
        match self {
49✔
1670
            BuiltInOperator::Time => "time",
6✔
1671
            BuiltInOperator::DeltaTime => "delta_time",
13✔
1672
            BuiltInOperator::VirtualTime => "virtual_time",
2✔
1673
            BuiltInOperator::VirtualDeltaTime => "virtual_delta_time",
2✔
1674
            BuiltInOperator::RealTime => "real_time",
2✔
1675
            BuiltInOperator::RealDeltaTime => "real_delta_time",
2✔
1676
            BuiltInOperator::Rand(value_type) => match value_type {
44✔
1677
                ValueType::Scalar(s) => match s {
20✔
1678
                    ScalarType::Bool => "brand",
1✔
1679
                    ScalarType::Float => "frand",
7✔
1680
                    ScalarType::Int => "irand",
1✔
1681
                    ScalarType::Uint => "urand",
1✔
1682
                },
1683
                ValueType::Vector(vector_type) => {
12✔
1684
                    match (vector_type.elem_type(), vector_type.count()) {
36✔
1685
                        (ScalarType::Bool, 2) => "brand2",
1✔
1686
                        (ScalarType::Bool, 3) => "brand3",
1✔
1687
                        (ScalarType::Bool, 4) => "brand4",
1✔
1688
                        (ScalarType::Float, 2) => "frand2",
1✔
1689
                        (ScalarType::Float, 3) => "frand3",
1✔
1690
                        (ScalarType::Float, 4) => "frand4",
1✔
1691
                        (ScalarType::Int, 2) => "irand2",
1✔
1692
                        (ScalarType::Int, 3) => "irand3",
1✔
1693
                        (ScalarType::Int, 4) => "irand4",
1✔
1694
                        (ScalarType::Uint, 2) => "urand2",
1✔
1695
                        (ScalarType::Uint, 3) => "urand3",
1✔
1696
                        (ScalarType::Uint, 4) => "urand4",
1✔
1697
                        _ => panic!("Invalid vector type {:?}", vector_type),
×
1698
                    }
1699
                }
1700
                ValueType::Matrix(_) => panic!("Invalid BuiltInOperator::Rand(ValueType::Matrix)."),
×
1701
            },
1702
            BuiltInOperator::AlphaCutoff => "alpha_cutoff",
×
1703
            BuiltInOperator::IsAlive => "is_alive",
×
1704
        }
1705
    }
1706

1707
    /// Get the type of the value of a built-in operator.
1708
    pub fn value_type(&self) -> ValueType {
4✔
1709
        match self {
4✔
1710
            BuiltInOperator::Time => ValueType::Scalar(ScalarType::Float),
2✔
1711
            BuiltInOperator::DeltaTime => ValueType::Scalar(ScalarType::Float),
2✔
1712
            BuiltInOperator::VirtualTime => ValueType::Scalar(ScalarType::Float),
×
1713
            BuiltInOperator::VirtualDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1714
            BuiltInOperator::RealTime => ValueType::Scalar(ScalarType::Float),
×
1715
            BuiltInOperator::RealDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1716
            BuiltInOperator::Rand(value_type) => *value_type,
×
1717
            BuiltInOperator::AlphaCutoff => ValueType::Scalar(ScalarType::Float),
×
1718
            BuiltInOperator::IsAlive => ValueType::Scalar(ScalarType::Bool),
×
1719
        }
1720
    }
1721

1722
    // /// Evaluate the result of the operator as an expression.
1723
    // pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
1724
    //     match self {
1725
    //         BuiltInOperator::Time => Value::Scalar(Scal)
1726
    //     }
1727
    // }
1728
}
1729

1730
impl ToWgslString for BuiltInOperator {
1731
    fn to_wgsl_string(&self) -> String {
37✔
1732
        match self {
37✔
1733
            BuiltInOperator::Rand(_) => format!("{}()", self.name()),
22✔
1734
            BuiltInOperator::IsAlive => "is_alive".to_string(),
2✔
1735
            _ => format!("sim_params.{}", self.name()),
42✔
1736
        }
1737
    }
1738
}
1739

1740
/// Expression for getting built-in quantities related to the effect system.
1741
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1742
pub struct BuiltInExpr {
1743
    /// The built-in operator this expression represents.
1744
    ///
1745
    /// The expression evaluates to the value of this built-in operator at the
1746
    /// time of evaluation.
1747
    pub operator: BuiltInOperator,
1748
}
1749

1750
impl BuiltInExpr {
1751
    /// Create a new built-in operator expression.
1752
    ///
1753
    /// # Panics
1754
    ///
1755
    /// Panics on invalid [`BuiltInOperator`], like `Rand(MatrixType)`. See
1756
    /// each [`BuiltInOperator`] variant for more details.
1757
    #[inline]
1758
    pub fn new(operator: BuiltInOperator) -> Self {
33✔
1759
        if let BuiltInOperator::Rand(value_type) = operator {
51✔
1760
            assert!(!matches!(value_type, ValueType::Matrix(_)));
18✔
1761
        }
1762
        Self { operator }
1763
    }
1764

1765
    /// Is the expression resulting in a compile-time constant?
1766
    ///
1767
    /// Constant expressions can be hard-coded into a shader's code, making them
1768
    /// more efficient and open to shader compiler optimizing.
1769
    pub fn is_const(&self) -> bool {
×
1770
        false
×
1771
    }
1772

1773
    /// Has the expression any side-effect?
1774
    ///
1775
    /// Expressions with side-effect need to be stored into temporary variables
1776
    /// when the shader code is emitted, so that the side effect is only applied
1777
    /// once when the expression is reused in multiple locations.
1778
    pub fn has_side_effect(&self) -> bool {
37✔
1779
        matches!(self.operator, BuiltInOperator::Rand(_))
52✔
1780
    }
1781

1782
    /// Get the value type of the expression.
1783
    ///
1784
    /// The value type of the expression is the type of the value(s) that an
1785
    /// expression produces.
1786
    pub fn value_type(&self) -> ValueType {
×
1787
        self.operator.value_type()
×
1788
    }
1789

1790
    /// Evaluate the expression in the given context.
1791
    pub fn eval(&self, context: &mut dyn EvalContext) -> Result<String, ExprError> {
37✔
1792
        Ok(check_side_effects_and_create_local_if_needed(
74✔
1793
            context,
74✔
1794
            self.to_wgsl_string(),
111✔
1795
            self.has_side_effect(),
37✔
1796
        ))
1797
    }
1798
}
1799

1800
impl ToWgslString for BuiltInExpr {
1801
    fn to_wgsl_string(&self) -> String {
37✔
1802
        self.operator.to_wgsl_string()
74✔
1803
    }
1804
}
1805

1806
/// Creates a local variable if necessary to avoid evaluating side-effecting
1807
/// expressions multiple times.
1808
///
1809
/// If `has_side_effect` is true, this function creates a local variable within
1810
/// the [`EvalContext`] and stores the `compiled_code` there. Otherwise, it
1811
/// simply returns `compiled_code` unchanged.
1812
fn check_side_effects_and_create_local_if_needed(
77✔
1813
    context: &mut dyn EvalContext,
1814
    compiled_code: String,
1815
    has_side_effect: bool,
1816
) -> String {
1817
    if has_side_effect {
77✔
1818
        let var_name = context.make_local_var();
66✔
1819
        context.push_stmt(&format!("let {} = {};", var_name, compiled_code));
66✔
1820
        var_name
22✔
1821
    } else {
1822
        compiled_code
55✔
1823
    }
1824
}
1825

1826
/// Unary operator.
1827
///
1828
/// Operator applied to a single operand to produce another value. The type of
1829
/// the operand and the result are not necessarily the same. Valid operand types
1830
/// depend on the operator itself.
1831
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1832
pub enum UnaryOperator {
1833
    /// Absolute value operator.
1834
    ///
1835
    /// Return the absolute value of the operand, component-wise for vectors.
1836
    /// Only valid for numeric operands.
1837
    Abs,
1838

1839
    /// Inverse cosine operator.
1840
    ///
1841
    /// Return the inverse cosine of the operand, component-wise for vectors.
1842
    /// Only valid for floating-point operands.
1843
    Acos,
1844

1845
    /// Inverse sine operator.
1846
    ///
1847
    /// Return the inverse sine of the operand, component-wise for vectors.
1848
    /// Only valid for floating-point operands.
1849
    Asin,
1850

1851
    /// Inverse tangent operator.
1852
    ///
1853
    /// Return the inverse tangent of the operand, component-wise for vectors.
1854
    /// Only valid for floating-point operands.
1855
    Atan,
1856

1857
    /// Logical ALL operator for bool vectors.
1858
    ///
1859
    /// Return `true` if all the components of the bool vector operand are
1860
    /// `true`. Invalid for any other type of operand.
1861
    All,
1862

1863
    /// Logical ANY operator for bool vectors.
1864
    ///
1865
    /// Return `true` if any component of the bool vector operand is `true`.
1866
    /// Invalid for any other type of operand.
1867
    Any,
1868

1869
    /// Ceiling operator.
1870
    ///
1871
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1872
    /// `x` is the operand which the operator applies to.
1873
    Ceil,
1874

1875
    /// Cosine operator.
1876
    Cos,
1877

1878
    /// Natural exponent operator.
1879
    ///
1880
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1881
    /// for vectors.
1882
    Exp,
1883

1884
    /// Base-2 exponent operator.
1885
    ///
1886
    /// Return two raised to the power of the operand (`2^x`), component-wise
1887
    /// for vectors.
1888
    Exp2,
1889

1890
    /// Floor operator.
1891
    ///
1892
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1893
    /// `x` is the operand which the operator applies to.
1894
    Floor,
1895

1896
    /// Fractional part operator.
1897
    ///
1898
    /// Return the fractional part of the operand, which is equal to `x -
1899
    /// floor(x)`, component-wise for vectors.
1900
    Fract,
1901

1902
    /// Inverse square root operator.
1903
    ///
1904
    /// Return the inverse square root of the floating-point operand (`1.0 /
1905
    /// sqrt(x)`), component-wise for vectors.
1906
    InvSqrt,
1907

1908
    /// Length operator.
1909
    ///
1910
    /// Return the length of a floating point scalar or vector. The "length" of
1911
    /// a scalar is taken as its absolute value. The length of a vector is the
1912
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1913
    /// squared components).
1914
    ///
1915
    /// The output is always a floating point scalar.
1916
    Length,
1917

1918
    /// Natural logarithm operator.
1919
    ///
1920
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1921
    /// for vectors.
1922
    Log,
1923

1924
    /// Base-2 logarithm operator.
1925
    ///
1926
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1927
    /// for vectors.
1928
    Log2,
1929

1930
    /// Vector normalizing operator.
1931
    ///
1932
    /// Normalize the given numeric vector. Only valid for numeric vector
1933
    /// operands.
1934
    Normalize,
1935

1936
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1937
    ///
1938
    /// Convert the four components of a signed normalized floating point vector
1939
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1940
    /// four values into a single `u32`. Each vector component should be in
1941
    /// `[-1:1]` before packing; values outside this range are clamped.
1942
    Pack4x8snorm,
1943

1944
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1945
    ///
1946
    /// Convert the four components of an unsigned normalized floating point
1947
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1948
    /// those four values into a single `u32`. Each vector component should
1949
    /// be in `[0:1]` before packing; values outside this range are clamped.
1950
    Pack4x8unorm,
1951

1952
    /// Rounding operator.
1953
    ///
1954
    /// Round the given scalar of vector float to the nearest integer, returned
1955
    /// as a float value.
1956
    Round,
1957

1958
    /// Saturate operator.
1959
    ///
1960
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1961
    /// vectors.
1962
    Saturate,
1963

1964
    /// Sign operator.
1965
    ///
1966
    /// Return a value representing the sign of a floating point scalar or
1967
    /// vector input:
1968
    /// - `1.` if the operand is > 0
1969
    /// - `0.` if the operand is = 0
1970
    /// - `-1.` if the operand is < 0
1971
    ///
1972
    /// Applies component-wise for vectors.
1973
    Sign,
1974

1975
    /// Sine operator.
1976
    Sin,
1977

1978
    /// Square root operator.
1979
    ///
1980
    /// Return the square root of the floating-point operand, component-wise for
1981
    /// vectors.
1982
    Sqrt,
1983

1984
    /// Tangent operator.
1985
    Tan,
1986

1987
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1988
    ///
1989
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1990
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1991
    Unpack4x8snorm,
1992

1993
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1994
    ///
1995
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1996
    /// then convert each value to an unsigned normalized `f32` value in
1997
    /// `[0:1]`.
1998
    Unpack4x8unorm,
1999

2000
    /// Get the fourth component of a vector.
2001
    ///
2002
    /// This is only valid for vectors of rank 4.
2003
    W,
2004

2005
    /// Get the first component of a scalar or vector.
2006
    ///
2007
    /// For scalar, return the value itself. For vectors, return the first
2008
    /// component.
2009
    X,
2010

2011
    /// Get the second component of a vector.
2012
    Y,
2013

2014
    /// Get the third component of a vector.
2015
    ///
2016
    /// This is only valid for vectors of rank 3 or more.
2017
    Z,
2018
}
2019

2020
impl UnaryOperator {
2021
    /// Check if a unary operator is called via a functional-style call.
2022
    ///
2023
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
2024
    /// example, while non-functional ones are in the form `inner.op`,
2025
    /// like `v.x` for example. This check is used for formatting the WGSL
2026
    /// code emitted during evaluation of a binary operation expression.
2027
    pub fn is_functional(&self) -> bool {
38✔
2028
        !matches!(
34✔
2029
            *self,
38✔
2030
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
2031
        )
2032
    }
2033
}
2034

2035
impl ToWgslString for UnaryOperator {
2036
    fn to_wgsl_string(&self) -> String {
38✔
2037
        match *self {
38✔
2038
            UnaryOperator::Abs => "abs".to_string(),
5✔
2039
            UnaryOperator::Acos => "acos".to_string(),
2✔
2040
            UnaryOperator::Asin => "asin".to_string(),
2✔
2041
            UnaryOperator::Atan => "atan".to_string(),
2✔
2042
            UnaryOperator::All => "all".to_string(),
2✔
2043
            UnaryOperator::Any => "any".to_string(),
6✔
2044
            UnaryOperator::Ceil => "ceil".to_string(),
2✔
2045
            UnaryOperator::Cos => "cos".to_string(),
2✔
2046
            UnaryOperator::Exp => "exp".to_string(),
2✔
2047
            UnaryOperator::Exp2 => "exp2".to_string(),
2✔
2048
            UnaryOperator::Floor => "floor".to_string(),
2✔
2049
            UnaryOperator::Fract => "fract".to_string(),
2✔
2050
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
2✔
2051
            UnaryOperator::Length => "length".to_string(),
2✔
2052
            UnaryOperator::Log => "log".to_string(),
2✔
2053
            UnaryOperator::Log2 => "log2".to_string(),
2✔
2054
            UnaryOperator::Normalize => "normalize".to_string(),
4✔
2055
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
2✔
2056
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
2✔
2057
            UnaryOperator::Round => "round".to_string(),
2✔
2058
            UnaryOperator::Saturate => "saturate".to_string(),
2✔
2059
            UnaryOperator::Sign => "sign".to_string(),
2✔
2060
            UnaryOperator::Sin => "sin".to_string(),
2✔
2061
            UnaryOperator::Sqrt => "sqrt".to_string(),
2✔
2062
            UnaryOperator::Tan => "tan".to_string(),
2✔
2063
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
2✔
2064
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
2✔
2065
            UnaryOperator::W => "w".to_string(),
2✔
2066
            UnaryOperator::X => "x".to_string(),
2✔
2067
            UnaryOperator::Y => "y".to_string(),
2✔
2068
            UnaryOperator::Z => "z".to_string(),
2✔
2069
        }
2070
    }
2071
}
2072

2073
/// Binary operator.
2074
///
2075
/// Operator applied between two operands, generally denoted "left" and "right".
2076
/// The type of the operands and the result are not necessarily the same. Valid
2077
/// operand types depend on the operator itself.
2078
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2079
pub enum BinaryOperator {
2080
    /// Addition operator.
2081
    ///
2082
    /// Returns the sum of its operands. Only valid for numeric operands.
2083
    Add,
2084

2085
    /// Inverse tangent operator with 2 arguments.
2086
    ///
2087
    /// Returns the arctangent (inverse tangent) of the ratio of the first
2088
    /// argument divided by the second argument.
2089
    Atan2,
2090

2091
    /// Cross product operator.
2092
    ///
2093
    /// Returns the cross product of the left and right operands. Only valid for
2094
    /// vector type operands of size 3. Always produce a vector result of the
2095
    /// same size.
2096
    Cross,
2097

2098
    /// Distance operator.
2099
    ///
2100
    /// Returns the distance between two floating point scalar or vectors, that
2101
    /// is `length(right - left)`.
2102
    Distance,
2103

2104
    /// Division operator.
2105
    ///
2106
    /// Returns the left operand divided by the right operand. Only valid for
2107
    /// numeric operands.
2108
    Div,
2109

2110
    /// Dot product operator.
2111
    ///
2112
    /// Returns the dot product of the left and right operands. Only valid for
2113
    /// vector type operands. Always produce a scalar floating-point result.
2114
    Dot,
2115

2116
    /// Greater-than operator.
2117
    ///
2118
    /// Returns `true` if the left operand is strictly greater than the right
2119
    /// operand. Only valid for numeric types. If the operands are vectors,
2120
    /// they must be of the same rank, and the result is a bool vector of
2121
    /// that rank.
2122
    GreaterThan,
2123

2124
    /// Greater-than-or-equal operator.
2125
    ///
2126
    /// Returns `true` if the left operand is greater than or equal to the right
2127
    /// operand. Only valid for numeric types. If the operands are vectors,
2128
    /// they must be of the same rank, and the result is a bool vector of
2129
    /// that rank.
2130
    GreaterThanOrEqual,
2131

2132
    /// Less-than operator.
2133
    ///
2134
    /// Returns `true` if the left operand is strictly less than the right
2135
    /// operand. Only valid for numeric types. If the operands are vectors,
2136
    /// they must be of the same rank, and the result is a bool vector of
2137
    /// that rank.
2138
    LessThan,
2139

2140
    /// Less-than-or-equal operator.
2141
    ///
2142
    /// Returns `true` if the left operand is less than or equal to the right
2143
    /// operand. Only valid for numeric types. If the operands are vectors,
2144
    /// they must be of the same rank, and the result is a bool vector of
2145
    /// that rank.
2146
    LessThanOrEqual,
2147

2148
    /// Maximum operator.
2149
    ///
2150
    /// Returns the maximum value of its left and right operands. Only valid for
2151
    /// numeric types. If the operands are vectors, they must be of the same
2152
    /// rank, and the result is a vector of that rank and same element
2153
    /// scalar type.
2154
    Max,
2155

2156
    /// Minimum operator.
2157
    ///
2158
    /// Returns the minimum value of its left and right operands. Only valid for
2159
    /// numeric types. If the operands are vectors, they must be of the same
2160
    /// rank, and the result is a vector of that rank and same element
2161
    /// scalar type.
2162
    Min,
2163

2164
    /// Multiply operator.
2165
    ///
2166
    /// Returns the product of its operands. Only valid for numeric operands.
2167
    Mul,
2168

2169
    /// Remainder operator.
2170
    ///
2171
    /// Returns the remainder of the division of the first operand by the
2172
    /// second. Only valid for numeric types. If the operands are vectors,
2173
    /// they must be of the same rank, and the result is a vector of that
2174
    /// rank and same element scalar type.
2175
    Remainder,
2176

2177
    /// Stepping operator.
2178
    ///
2179
    /// Returns `1.0` if the left operand is less than or equal to the right
2180
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
2181
    /// of the same rank, and applied component-wise for vectors.
2182
    Step,
2183

2184
    /// Subtraction operator.
2185
    ///
2186
    /// Returns the difference between its left and right operands. Only valid
2187
    /// for numeric operands.
2188
    Sub,
2189

2190
    /// Uniform random number operator.
2191
    ///
2192
    /// Returns a value generated by a fast non-cryptographically-secure
2193
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2194
    /// are undefined and generally focused around speed. The random value is
2195
    /// uniformly distributed between the left and right operands, which must be
2196
    /// numeric types. If the operands are vectors, they must be of the same
2197
    /// rank, and the result is a vector of that rank and same element
2198
    /// scalar type.
2199
    UniformRand,
2200

2201
    /// Normal distribution random number operator.
2202
    ///
2203
    /// Returns a value generated by a fast non-cryptographically-secure
2204
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2205
    /// are undefined and generally focused around speed. The random value is
2206
    /// normally distributed with mean given by the first operand and standard
2207
    /// deviation by the second, which must be numeric types. If the operands
2208
    /// are vectors, they must be of the same rank, and the result is a vector
2209
    /// of that rank and same element scalar type.
2210
    NormalRand,
2211

2212
    /// Constructor for 2-element vectors.
2213
    ///
2214
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
2215
    /// those two elements `(x, y)`.
2216
    Vec2,
2217

2218
    /// Constructor for a 4-element vector.
2219
    ///
2220
    /// Given a 3-element vector `xyz` and a scalar value `w`, returns the
2221
    /// vector `vec4(xyz, w)`.
2222
    Vec4XyzW,
2223
}
2224

2225
impl BinaryOperator {
2226
    /// Check if a binary operator is called via a functional-style call.
2227
    ///
2228
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
2229
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
2230
    /// like `a + b` for example. This check is used for formatting the WGSL
2231
    /// code emitted during evaluation of a binary operation expression.
2232
    pub fn is_functional(&self) -> bool {
40✔
2233
        match *self {
40✔
2234
            BinaryOperator::Add
2235
            | BinaryOperator::Div
2236
            | BinaryOperator::GreaterThan
2237
            | BinaryOperator::GreaterThanOrEqual
2238
            | BinaryOperator::LessThan
2239
            | BinaryOperator::LessThanOrEqual
2240
            | BinaryOperator::Mul
2241
            | BinaryOperator::Remainder
2242
            | BinaryOperator::Sub => false,
27✔
2243
            BinaryOperator::Atan2
2244
            | BinaryOperator::Cross
2245
            | BinaryOperator::Distance
2246
            | BinaryOperator::Dot
2247
            | BinaryOperator::Max
2248
            | BinaryOperator::Min
2249
            | BinaryOperator::Step
2250
            | BinaryOperator::UniformRand
2251
            | BinaryOperator::NormalRand
2252
            | BinaryOperator::Vec2
2253
            | BinaryOperator::Vec4XyzW => true,
13✔
2254
        }
2255
    }
2256

2257
    /// Check if a binary operator needs a type suffix.
2258
    ///
2259
    /// This is currently just for `rand_uniform`
2260
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2261
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2262
    /// WGSL doesn't support user-defined function overloading, so we need a
2263
    /// suffix to disambiguate the types.
2264
    pub fn needs_type_suffix(&self) -> bool {
13✔
2265
        matches!(
13✔
2266
            *self,
13✔
2267
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2268
        )
2269
    }
2270
}
2271

2272
impl ToWgslString for BinaryOperator {
2273
    fn to_wgsl_string(&self) -> String {
40✔
2274
        match *self {
40✔
2275
            BinaryOperator::Add => "+".to_string(),
5✔
2276
            BinaryOperator::Atan2 => "atan2".to_string(),
2✔
2277
            BinaryOperator::Cross => "cross".to_string(),
2✔
2278
            BinaryOperator::Distance => "distance".to_string(),
2✔
2279
            BinaryOperator::Div => "/".to_string(),
4✔
2280
            BinaryOperator::Dot => "dot".to_string(),
2✔
2281
            BinaryOperator::GreaterThan => ">".to_string(),
6✔
2282
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
2✔
2283
            BinaryOperator::LessThan => "<".to_string(),
2✔
2284
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
2✔
2285
            BinaryOperator::Max => "max".to_string(),
10✔
2286
            BinaryOperator::Min => "min".to_string(),
4✔
2287
            BinaryOperator::Mul => "*".to_string(),
12✔
2288
            BinaryOperator::Remainder => "%".to_string(),
2✔
2289
            BinaryOperator::Step => "step".to_string(),
2✔
2290
            BinaryOperator::Sub => "-".to_string(),
14✔
2291
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
2292
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
2293
            BinaryOperator::Vec2 => "vec2".to_string(),
×
2294
            BinaryOperator::Vec4XyzW => "vec4".to_string(),
2✔
2295
        }
2296
    }
2297
}
2298

2299
/// Ternary operator.
2300
///
2301
/// Operator applied between three operands. The type of the operands and the
2302
/// result are not necessarily the same. Valid operand types depend on the
2303
/// operator itself.
2304
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2305
pub enum TernaryOperator {
2306
    /// Linear blend ("mix") operator.
2307
    ///
2308
    /// Returns the linear blend between the first and second argument, based on
2309
    /// the fraction of the third argument. If the operands are vectors, they
2310
    /// must be of the same rank, and the result is a vector of that rank
2311
    /// and same element scalar type.
2312
    ///
2313
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2314
    /// (1 - t) + y * t`.
2315
    Mix,
2316

2317
    /// Clamp operator.
2318
    ///
2319
    /// Returns the first argument clamped to the range defined by the second
2320
    /// and third arguments. If the operands are vectors, they must be of
2321
    /// the same rank, and the result is a vector of that rank
2322
    /// and same element scalar type.
2323
    ///
2324
    /// The expression `clamp(x, low, high)` is equivalent to `min(max(x, low),
2325
    /// high)`.
2326
    Clamp,
2327

2328
    /// Smooth stepping operator.
2329
    ///
2330
    /// Returns the smooth Hermitian interpolation between the first and second
2331
    /// argument, calculated at the third argument. If the operands are vectors,
2332
    /// they must be of the same rank, and the result is a vector of that
2333
    /// rank and same element scalar type.
2334
    ///
2335
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2336
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2337
    /// represents the fractional position of `x` between `low` and `high`.
2338
    ///
2339
    /// The result is always a floating point scalar in \[0:1\].
2340
    SmoothStep,
2341

2342
    /// Constructor for 3-element vectors.
2343
    ///
2344
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2345
    /// consisting of those three elements `(x, y, z)`.
2346
    Vec3,
2347
}
2348

2349
impl ToWgslString for TernaryOperator {
2350
    fn to_wgsl_string(&self) -> String {
5✔
2351
        match *self {
5✔
2352
            TernaryOperator::Mix => "mix".to_string(),
2✔
2353
            TernaryOperator::Clamp => "clamp".to_string(),
2✔
2354
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
2✔
2355
            TernaryOperator::Vec3 => "vec3".to_string(),
2✔
2356
        }
2357
    }
2358
}
2359

2360
/// Expression writer.
2361
///
2362
/// Utility to write expressions with a simple functional syntax. Expressions
2363
/// created with the writer are gatherned into a [`Module`] which can be
2364
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2365
///
2366
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2367
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2368
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2369
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2370
/// to assign it to the [`EffectAsset`].
2371
///
2372
/// # Example
2373
///
2374
/// ```
2375
/// # use bevy_hanabi::*;
2376
/// # use bevy::prelude::*;
2377
/// // Create a writer
2378
/// let w = ExprWriter::new();
2379
///
2380
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2381
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2382
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2383
///
2384
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2385
/// let expr: ExprHandle = expr.expr();
2386
///
2387
/// // Create a modifier and assign the expression to one of its input(s)
2388
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2389
///
2390
/// // Create an EffectAsset with the modifier and the Module from the writer
2391
/// let effect = EffectAsset::new(1024, SpawnerSettings::rate(32_f32.into()), w.finish())
2392
///     .init(init_modifier);
2393
/// ```
2394
///
2395
/// [`finish()`]: ExprWriter::finish
2396
/// [`EffectAsset`]: crate::EffectAsset
2397
/// [`Modifer`]: crate::Modifier
2398
#[derive(Debug, Default, Clone)]
2399
pub struct ExprWriter {
2400
    module: Rc<RefCell<Module>>,
2401
}
2402

2403
#[allow(dead_code)]
2404
impl ExprWriter {
2405
    /// Create a new writer.
2406
    ///
2407
    /// The writer owns a new [`Module`] internally, and write all expressions
2408
    /// to it. The module can be released to the user with [`finish()`] once
2409
    /// done using the writer.
2410
    ///
2411
    /// [`finish()`]: ExprWriter::finish
2412
    pub fn new() -> Self {
3✔
2413
        Self {
2414
            module: Rc::new(RefCell::new(Module::default())),
6✔
2415
        }
2416
    }
2417

2418
    /// Create a new writer from an existing module.
2419
    ///
2420
    /// This is an advanced use entry point to write expressions into an
2421
    /// existing [`Module`]. In general, users should prefer using
2422
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2423
    /// same [`ExprWriter`] to write all expressions of the same
2424
    /// [`EffectAsset`].
2425
    ///
2426
    /// [`EffectAsset`]: crate::EffectAsset
2427
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2428
        Self { module }
2429
    }
2430

2431
    /// Add a new property.
2432
    ///
2433
    /// See [`Property`] for more details on what effect properties are.
2434
    ///
2435
    /// # Panics
2436
    ///
2437
    /// Panics if a property with the same name already exists.
2438
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2439
        self.module.borrow_mut().add_property(name, default_value)
3✔
2440
    }
2441

2442
    /// Push a new expression into the writer.
2443
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2444
        let expr = {
13✔
2445
            let mut m = self.module.borrow_mut();
26✔
2446
            m.add_expr(expr.into())
39✔
2447
        };
2448
        WriterExpr {
2449
            expr,
2450
            module: Rc::clone(&self.module),
13✔
2451
        }
2452
    }
2453

2454
    /// Create a new writer expression from a literal constant.
2455
    ///
2456
    /// # Example
2457
    ///
2458
    /// ```
2459
    /// # use bevy_hanabi::*;
2460
    /// let mut w = ExprWriter::new();
2461
    /// let x = w.lit(-3.5); // x = -3.5;
2462
    /// ```
2463
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2464
        self.push(Expr::Literal(LiteralExpr {
33✔
2465
            value: value.into(),
11✔
2466
        }))
2467
    }
2468

2469
    /// Create a new writer expression from an attribute.
2470
    ///
2471
    /// # Example
2472
    ///
2473
    /// ```
2474
    /// # use bevy_hanabi::*;
2475
    /// let mut w = ExprWriter::new();
2476
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2477
    /// ```
2478
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2479
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
3✔
2480
    }
2481

2482
    /// Create a new writer expression from an attribute on a parent effect.
2483
    ///
2484
    /// # Example
2485
    ///
2486
    /// ```
2487
    /// # use bevy_hanabi::*;
2488
    /// let mut w = ExprWriter::new();
2489
    /// let x = w.parent_attr(Attribute::POSITION); // x = parent_particle.position;
2490
    /// ```
2491
    pub fn parent_attr(&self, attr: Attribute) -> WriterExpr {
×
2492
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
2493
    }
2494

2495
    /// Create a new writer expression from a property.
2496
    ///
2497
    /// # Example
2498
    ///
2499
    /// ```
2500
    /// # use bevy_hanabi::*;
2501
    /// let mut w = ExprWriter::new();
2502
    /// let prop = w.add_property("my_prop", 3.0.into());
2503
    /// let x = w.prop(prop); // x = properties.my_prop;
2504
    /// ```
2505
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2506
        self.push(Expr::Property(PropertyExpr::new(handle)))
3✔
2507
    }
2508

2509
    /// Create a new writer expression representing the current simulation time.
2510
    ///
2511
    /// # Example
2512
    ///
2513
    /// ```
2514
    /// # use bevy_hanabi::*;
2515
    /// let mut w = ExprWriter::new();
2516
    /// let x = w.time(); // x = sim_params.time;
2517
    /// ```
2518
    pub fn time(&self) -> WriterExpr {
×
2519
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2520
    }
2521

2522
    /// Create a new writer expression representing the simulation delta time
2523
    /// since last frame.
2524
    ///
2525
    /// # Example
2526
    ///
2527
    /// ```
2528
    /// # use bevy_hanabi::*;
2529
    /// let mut w = ExprWriter::new();
2530
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2531
    /// ```
2532
    pub fn delta_time(&self) -> WriterExpr {
×
2533
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2534
    }
2535

2536
    /// Create a new writer expression representing a random value of the given
2537
    /// type.
2538
    ///
2539
    /// The type can be any scalar or vector type. Matrix types are not
2540
    /// supported. The random values generated are uniformly distributed in
2541
    /// `[0:1]`. For vectors, each component is sampled separately.
2542
    ///
2543
    /// # Panics
2544
    ///
2545
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2546
    ///
2547
    /// # Example
2548
    ///
2549
    /// ```
2550
    /// # use bevy_hanabi::*;
2551
    /// let mut w = ExprWriter::new();
2552
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2553
    /// ```
2554
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2555
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2556
            value_type.into(),
×
2557
        ))))
2558
    }
2559

2560
    /// Create a new writer expression representing the alpha cutoff value used
2561
    /// for alpha masking.
2562
    ///
2563
    /// This expression is only valid when used in the context of the fragment
2564
    /// shader, in the render context.
2565
    ///
2566
    /// # Example
2567
    ///
2568
    /// ```
2569
    /// # use bevy_hanabi::*;
2570
    /// let mut w = ExprWriter::new();
2571
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2572
    /// ```
2573
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2574
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2575
            BuiltInOperator::AlphaCutoff,
×
2576
        )))
2577
    }
2578

2579
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2580
    /// were written by the writer.
2581
    ///
2582
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2583
    /// to that effect the modifiers which use the expressions created by this
2584
    /// writer.
2585
    ///
2586
    /// # Example
2587
    ///
2588
    /// ```
2589
    /// # use bevy_hanabi::*;
2590
    /// # let spawner = SpawnerSettings::default();
2591
    /// let mut w = ExprWriter::new();
2592
    /// // [...]
2593
    /// let module = w.finish();
2594
    /// let asset = EffectAsset::new(256, spawner, module);
2595
    /// ```
2596
    ///
2597
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2598
    pub fn finish(self) -> Module {
3✔
2599
        self.module.take()
3✔
2600
    }
2601
}
2602

2603
/// Intermediate expression from an [`ExprWriter`].
2604
///
2605
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2606
/// retains a reference to the underlying [`Module`] and therefore can easily be
2607
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2608
/// being more heavyweight and locking the underlying [`Module`] under a
2609
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2610
/// opposition is a very lightweight type, similar to a simple index. And like
2611
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2612
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2613
///
2614
/// In addition, [`WriterExpr`] implements several numerical operators like the
2615
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2616
/// [`WriterExpr`].
2617
///
2618
/// ```
2619
/// # use bevy_hanabi::*;
2620
/// let mut w = ExprWriter::new();
2621
/// let x = w.lit(-3.5);
2622
/// let y = w.lit(78.);
2623
/// let z = x + y; // == 74.5
2624
/// ```
2625
///
2626
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2627
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2628
///
2629
/// ```
2630
/// # use bevy_hanabi::*;
2631
/// let mut w = ExprWriter::new();
2632
/// let my_prop = w.add_property("my_prop", 3.0.into());
2633
///
2634
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2635
/// let x = (w.lit(-3.5) + w.lit(1.))
2636
///     .max(w.prop(my_prop))
2637
///     .mul(w.lit(0.5))
2638
///     .sub(w.attr(Attribute::POSITION));
2639
///
2640
/// let handle: ExprHandle = x.expr();
2641
/// ```
2642
#[derive(Debug, Clone)]
2643
pub struct WriterExpr {
2644
    expr: ExprHandle,
2645
    module: Rc<RefCell<Module>>,
2646
}
2647

2648
impl WriterExpr {
2649
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2650
        let expr = self.module.borrow_mut().add_expr(Expr::Unary {
4✔
2651
            op,
1✔
2652
            expr: self.expr,
1✔
2653
        });
2654
        WriterExpr {
2655
            expr,
2656
            module: self.module,
1✔
2657
        }
2658
    }
2659

2660
    /// Take the absolute value of the current expression.
2661
    ///
2662
    /// This is a unary operator, which applies component-wise to vector and
2663
    /// matrix operand expressions.
2664
    ///
2665
    /// # Example
2666
    ///
2667
    /// ```
2668
    /// # use bevy_hanabi::*;
2669
    /// # let mut w = ExprWriter::new();
2670
    /// // A literal expression `x = -3.5;`.
2671
    /// let x = w.lit(-3.5);
2672
    ///
2673
    /// // The absolute value `y = abs(x);`.
2674
    /// let y = x.abs(); // == 3.5
2675
    /// ```
2676
    #[inline]
2677
    pub fn abs(self) -> Self {
1✔
2678
        self.unary_op(UnaryOperator::Abs)
3✔
2679
    }
2680

2681
    /// Apply the logical operator "all" to the current bool vector expression.
2682
    ///
2683
    /// This is a unary operator, which applies to vector operand expressions to
2684
    /// produce a scalar boolean.
2685
    ///
2686
    /// # Example
2687
    ///
2688
    /// ```
2689
    /// # use bevy_hanabi::*;
2690
    /// # use bevy::math::BVec3;
2691
    /// # let mut w = ExprWriter::new();
2692
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2693
    /// let x = w.lit(BVec3::new(true, false, true));
2694
    ///
2695
    /// // Check if all components are true `y = all(x);`.
2696
    /// let y = x.all(); // == false
2697
    /// ```
2698
    #[inline]
2699
    pub fn all(self) -> Self {
×
2700
        self.unary_op(UnaryOperator::All)
×
2701
    }
2702

2703
    /// Apply the logical operator "any" to the current bool vector expression.
2704
    ///
2705
    /// This is a unary operator, which applies to vector operand expressions to
2706
    /// produce a scalar boolean.
2707
    ///
2708
    /// # Example
2709
    ///
2710
    /// ```
2711
    /// # use bevy_hanabi::*;
2712
    /// # use bevy::math::BVec3;
2713
    /// # let mut w = ExprWriter::new();
2714
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2715
    /// let x = w.lit(BVec3::new(true, false, true));
2716
    ///
2717
    /// // Check if any components is true `y = any(x);`.
2718
    /// let y = x.any(); // == true
2719
    /// ```
2720
    #[inline]
2721
    pub fn any(self) -> Self {
×
2722
        self.unary_op(UnaryOperator::Any)
×
2723
    }
2724

2725
    /// Apply the "acos" (inverse cosine) operator to the current float scalar
2726
    /// or vector expression.
2727
    ///
2728
    /// This is a unary operator, which applies to float scalar or vector
2729
    /// operand expressions to produce a float scalar or vector. It applies
2730
    /// component-wise to vector operand expressions. The return value lies in
2731
    /// the 0 ≤ x ≤ π range.
2732
    ///
2733
    /// # Example
2734
    ///
2735
    /// ```
2736
    /// # use bevy_hanabi::*;
2737
    /// # use bevy::math::Vec3;
2738
    /// # let mut w = ExprWriter::new();
2739
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2740
    /// let x = w.lit(Vec3::ONE);
2741
    ///
2742
    /// // Acos: `y = acos(x);`
2743
    /// let y = x.acos();
2744
    /// ```
2745
    #[inline]
2746
    pub fn acos(self) -> Self {
×
2747
        self.unary_op(UnaryOperator::Acos)
×
2748
    }
2749

2750
    /// Apply the "asin" (inverse sine) operator to the current float scalar or
2751
    /// vector expression.
2752
    ///
2753
    /// This is a unary operator, which applies to float scalar or vector
2754
    /// operand expressions to produce a float scalar or vector. It applies
2755
    /// component-wise to vector operand expressions. The return value lies in
2756
    /// the -π/2 ≤ x ≤ π/2 range.
2757
    ///
2758
    /// # Example
2759
    ///
2760
    /// ```
2761
    /// # use bevy_hanabi::*;
2762
    /// # use bevy::math::Vec3;
2763
    /// # let mut w = ExprWriter::new();
2764
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2765
    /// let x = w.lit(Vec3::ONE);
2766
    ///
2767
    /// // Asin: `y = asin(x);`
2768
    /// let y = x.asin();
2769
    /// ```
2770
    #[inline]
2771
    pub fn asin(self) -> Self {
×
2772
        self.unary_op(UnaryOperator::Asin)
×
2773
    }
2774

2775
    /// Apply the "atan" (inverse tangent) operator to the current float scalar
2776
    /// or vector expression.
2777
    ///
2778
    /// This is a unary operator, which applies to float scalar or vector
2779
    /// operand expressions to produce a float scalar or vector. It applies
2780
    /// component-wise to vector operand expressions. The return value lies in
2781
    /// the -π/2 ≤ x ≤ π/2 range.
2782
    ///
2783
    /// # Example
2784
    ///
2785
    /// ```
2786
    /// # use bevy_hanabi::*;
2787
    /// # use bevy::math::Vec3;
2788
    /// # let mut w = ExprWriter::new();
2789
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2790
    /// let x = w.lit(Vec3::ONE);
2791
    ///
2792
    /// // Atan: `y = atan(x);`
2793
    /// let y = x.atan();
2794
    /// ```
2795
    #[inline]
2796
    pub fn atan(self) -> Self {
×
2797
        self.unary_op(UnaryOperator::Atan)
×
2798
    }
2799

2800
    /// Apply the "ceil" operator to the current float scalar or vector
2801
    /// expression.
2802
    ///
2803
    /// This is a unary operator, which applies to float scalar or vector
2804
    /// operand expressions to produce a float scalar or vector. It applies
2805
    /// component-wise to vector operand expressions.
2806
    ///
2807
    /// # Example
2808
    ///
2809
    /// ```
2810
    /// # use bevy_hanabi::*;
2811
    /// # use bevy::math::Vec3;
2812
    /// # let mut w = ExprWriter::new();
2813
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2814
    /// let x = w.lit(Vec3::ONE);
2815
    ///
2816
    /// // Ceil: `y = ceil(x);`
2817
    /// let y = x.ceil();
2818
    /// ```
2819
    #[inline]
2820
    pub fn ceil(self) -> Self {
×
2821
        self.unary_op(UnaryOperator::Ceil)
×
2822
    }
2823

2824
    /// Apply the "cos" operator to the current float scalar or vector
2825
    /// expression.
2826
    ///
2827
    /// This is a unary operator, which applies to float scalar or vector
2828
    /// operand expressions to produce a float scalar or vector. It applies
2829
    /// component-wise to vector operand expressions.
2830
    ///
2831
    /// # Example
2832
    ///
2833
    /// ```
2834
    /// # use bevy_hanabi::*;
2835
    /// # use bevy::math::Vec3;
2836
    /// # let mut w = ExprWriter::new();
2837
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2838
    /// let x = w.lit(Vec3::ONE);
2839
    ///
2840
    /// // Cos: `y = cos(x);`
2841
    /// let y = x.cos();
2842
    /// ```
2843
    #[inline]
2844
    pub fn cos(self) -> Self {
×
2845
        self.unary_op(UnaryOperator::Cos)
×
2846
    }
2847

2848
    /// Apply the "exp" operator to the current float scalar or vector
2849
    /// expression.
2850
    ///
2851
    /// This is a unary operator, which applies to float scalar or vector
2852
    /// operand expressions to produce a float scalar or vector. It applies
2853
    /// component-wise to vector operand expressions.
2854
    ///
2855
    /// # Example
2856
    ///
2857
    /// ```
2858
    /// # use bevy_hanabi::*;
2859
    /// # use bevy::math::Vec3;
2860
    /// # let mut w = ExprWriter::new();
2861
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2862
    /// let x = w.lit(Vec3::ONE);
2863
    ///
2864
    /// // Exp: `y = exp(x);`
2865
    /// let y = x.exp();
2866
    /// ```
2867
    #[inline]
2868
    pub fn exp(self) -> Self {
×
2869
        self.unary_op(UnaryOperator::Exp)
×
2870
    }
2871

2872
    /// Apply the "exp2" operator to the current float scalar or vector
2873
    /// expression.
2874
    ///
2875
    /// This is a unary operator, which applies to float scalar or vector
2876
    /// operand expressions to produce a float scalar or vector. It applies
2877
    /// component-wise to vector operand expressions.
2878
    ///
2879
    /// # Example
2880
    ///
2881
    /// ```
2882
    /// # use bevy_hanabi::*;
2883
    /// # use bevy::math::Vec3;
2884
    /// # let mut w = ExprWriter::new();
2885
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2886
    /// let x = w.lit(Vec3::ONE);
2887
    ///
2888
    /// // Exp2: `y = exp2(x);`
2889
    /// let y = x.exp2();
2890
    /// ```
2891
    #[inline]
2892
    pub fn exp2(self) -> Self {
×
2893
        self.unary_op(UnaryOperator::Exp2)
×
2894
    }
2895

2896
    /// Apply the "floor" operator to the current float scalar or vector
2897
    /// expression.
2898
    ///
2899
    /// This is a unary operator, which applies to float scalar or vector
2900
    /// operand expressions to produce a float scalar or vector. It applies
2901
    /// component-wise to vector operand expressions.
2902
    ///
2903
    /// # Example
2904
    ///
2905
    /// ```
2906
    /// # use bevy_hanabi::*;
2907
    /// # use bevy::math::Vec3;
2908
    /// # let mut w = ExprWriter::new();
2909
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2910
    /// let x = w.lit(Vec3::ONE);
2911
    ///
2912
    /// // Floor: `y = floor(x);`
2913
    /// let y = x.floor();
2914
    /// ```
2915
    #[inline]
2916
    pub fn floor(self) -> Self {
×
2917
        self.unary_op(UnaryOperator::Floor)
×
2918
    }
2919

2920
    /// Apply the "fract" operator to the current float scalar or vector
2921
    /// expression.
2922
    ///
2923
    /// This is a unary operator, which applies to float scalar or vector
2924
    /// operand expressions to produce a float scalar or vector. It applies
2925
    /// component-wise to vector operand expressions.
2926
    ///
2927
    /// # Example
2928
    ///
2929
    /// ```
2930
    /// # use bevy_hanabi::*;
2931
    /// # use bevy::math::Vec3;
2932
    /// # let mut w = ExprWriter::new();
2933
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2934
    /// let x = w.lit(Vec3::ONE);
2935
    ///
2936
    /// // Fract: `y = fract(x);`
2937
    /// let y = x.fract();
2938
    /// ```
2939
    #[inline]
2940
    pub fn fract(self) -> Self {
×
2941
        self.unary_op(UnaryOperator::Fract)
×
2942
    }
2943

2944
    /// Apply the "inverseSqrt" (inverse square root) operator to the current
2945
    /// float scalar or vector expression.
2946
    ///
2947
    /// This is a unary operator, which applies to float scalar or vector
2948
    /// operand expressions to produce a float scalar or vector. It applies
2949
    /// component-wise to vector operand expressions.
2950
    ///
2951
    /// # Example
2952
    ///
2953
    /// ```
2954
    /// # use bevy_hanabi::*;
2955
    /// # use bevy::math::Vec3;
2956
    /// # let mut w = ExprWriter::new();
2957
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2958
    /// let x = w.lit(Vec3::ONE);
2959
    ///
2960
    /// // Inverse square root: `y = inverseSqrt(x) = 1.0 / sqrt(x);`
2961
    /// let y = x.inverse_sqrt();
2962
    /// ```
2963
    #[inline]
2964
    pub fn inverse_sqrt(self) -> Self {
×
2965
        self.unary_op(UnaryOperator::InvSqrt)
×
2966
    }
2967

2968
    /// Apply the "length" operator to the current float scalar or vector
2969
    /// expression.
2970
    ///
2971
    /// This is a unary operator, which applies to float scalar or vector
2972
    /// operand expressions to produce a float scalar or vector. It applies
2973
    /// component-wise to vector operand expressions.
2974
    ///
2975
    /// # Example
2976
    ///
2977
    /// ```
2978
    /// # use bevy_hanabi::*;
2979
    /// # use bevy::math::Vec3;
2980
    /// # let mut w = ExprWriter::new();
2981
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2982
    /// let x = w.lit(Vec3::ONE);
2983
    ///
2984
    /// // Length: `y = length(x);`
2985
    /// let y = x.length();
2986
    /// ```
2987
    #[inline]
2988
    pub fn length(self) -> Self {
×
2989
        self.unary_op(UnaryOperator::Length)
×
2990
    }
2991

2992
    /// Apply the "log" operator to the current float scalar or vector
2993
    /// expression.
2994
    ///
2995
    /// This is a unary operator, which applies to float scalar or vector
2996
    /// operand expressions to produce a float scalar or vector. It applies
2997
    /// component-wise to vector operand expressions.
2998
    ///
2999
    /// # Example
3000
    ///
3001
    /// ```
3002
    /// # use bevy_hanabi::*;
3003
    /// # use bevy::math::Vec3;
3004
    /// # let mut w = ExprWriter::new();
3005
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3006
    /// let x = w.lit(Vec3::ONE);
3007
    ///
3008
    /// // Log: `y = log(x);`
3009
    /// let y = x.log();
3010
    /// ```
3011
    #[inline]
3012
    pub fn log(self) -> Self {
×
3013
        self.unary_op(UnaryOperator::Log)
×
3014
    }
3015

3016
    /// Apply the "log2" operator to the current float scalar or vector
3017
    /// expression.
3018
    ///
3019
    /// This is a unary operator, which applies to float scalar or vector
3020
    /// operand expressions to produce a float scalar or vector. It applies
3021
    /// component-wise to vector operand expressions.
3022
    ///
3023
    /// # Example
3024
    ///
3025
    /// ```
3026
    /// # use bevy_hanabi::*;
3027
    /// # use bevy::math::Vec3;
3028
    /// # let mut w = ExprWriter::new();
3029
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3030
    /// let x = w.lit(Vec3::ONE);
3031
    ///
3032
    /// // Log2: `y = log2(x);`
3033
    /// let y = x.log2();
3034
    /// ```
3035
    #[inline]
3036
    pub fn log2(self) -> Self {
×
3037
        self.unary_op(UnaryOperator::Log2)
×
3038
    }
3039

3040
    /// Apply the "normalize" operator to the current float vector expression.
3041
    ///
3042
    /// This is a unary operator, which applies to float vector operand
3043
    /// expressions to produce another float vector with unit length
3044
    /// (normalized).
3045
    ///
3046
    /// # Example
3047
    ///
3048
    /// ```
3049
    /// # use bevy_hanabi::*;
3050
    /// # use bevy::math::Vec3;
3051
    /// # let mut w = ExprWriter::new();
3052
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3053
    /// let x = w.lit(Vec3::ONE);
3054
    ///
3055
    /// // Normalize: `y = normalize(x);`
3056
    /// let y = x.normalized();
3057
    /// ```
3058
    #[inline]
3059
    pub fn normalized(self) -> Self {
×
3060
        self.unary_op(UnaryOperator::Normalize)
×
3061
    }
3062

3063
    /// Apply the "pack4x8snorm" operator to the current 4-component float
3064
    /// vector expression.
3065
    ///
3066
    /// This is a unary operator, which applies to 4-component float vector
3067
    /// operand expressions to produce a single `u32` scalar expression.
3068
    ///
3069
    /// # Example
3070
    ///
3071
    /// ```
3072
    /// # use bevy_hanabi::*;
3073
    /// # use bevy::math::Vec4;
3074
    /// # let mut w = ExprWriter::new();
3075
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
3076
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
3077
    ///
3078
    /// // Pack: `y = pack4x8snorm(x);`
3079
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
3080
    /// ```
3081
    #[inline]
3082
    pub fn pack4x8snorm(self) -> Self {
×
3083
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
3084
    }
3085

3086
    /// Apply the "pack4x8unorm" operator to the current 4-component float
3087
    /// vector expression.
3088
    ///
3089
    /// This is a unary operator, which applies to 4-component float vector
3090
    /// operand expressions to produce a single `u32` scalar expression.
3091
    ///
3092
    /// # Example
3093
    ///
3094
    /// ```
3095
    /// # use bevy_hanabi::*;
3096
    /// # use bevy::math::Vec4;
3097
    /// # let mut w = ExprWriter::new();
3098
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
3099
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
3100
    ///
3101
    /// // Pack: `y = pack4x8unorm(x);`
3102
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
3103
    /// ```
3104
    #[inline]
3105
    pub fn pack4x8unorm(self) -> Self {
×
3106
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
3107
    }
3108

3109
    /// Apply the "round" operator to the current float scalar or vector
3110
    /// expression.
3111
    ///
3112
    /// This is a unary operator, which applies to float scalar or vector
3113
    /// operand expressions to produce a float scalar or vector. It applies
3114
    /// component-wise to vector operand expressions.
3115
    ///
3116
    /// # Example
3117
    ///
3118
    /// ```
3119
    /// # use bevy_hanabi::*;
3120
    /// # use bevy::math::Vec3;
3121
    /// # let mut w = ExprWriter::new();
3122
    /// // A literal expression `x = vec3<f32>(1.5, -3.2, 0.75);`.
3123
    /// let x = w.lit(Vec3::new(1.5, -3.2, 0.75));
3124
    ///
3125
    /// // Sign: `y = round(x);`
3126
    /// let y = x.round();
3127
    /// ```
3128
    #[inline]
3129
    pub fn round(self) -> Self {
×
3130
        self.unary_op(UnaryOperator::Round)
×
3131
    }
3132

3133
    /// Apply the "sign" operator to the current float scalar or vector
3134
    /// expression.
3135
    ///
3136
    /// This is a unary operator, which applies to float scalar or vector
3137
    /// operand expressions to produce a float scalar or vector. It applies
3138
    /// component-wise to vector operand expressions.
3139
    ///
3140
    /// # Example
3141
    ///
3142
    /// ```
3143
    /// # use bevy_hanabi::*;
3144
    /// # use bevy::math::Vec3;
3145
    /// # let mut w = ExprWriter::new();
3146
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3147
    /// let x = w.lit(Vec3::ONE);
3148
    ///
3149
    /// // Sign: `y = sign(x);`
3150
    /// let y = x.sign();
3151
    /// ```
3152
    #[inline]
3153
    pub fn sign(self) -> Self {
×
3154
        self.unary_op(UnaryOperator::Sign)
×
3155
    }
3156

3157
    /// Apply the "sin" operator to the current float scalar or vector
3158
    /// expression.
3159
    ///
3160
    /// This is a unary operator, which applies to float scalar or vector
3161
    /// operand expressions to produce a float scalar or vector. It applies
3162
    /// component-wise to vector operand expressions.
3163
    ///
3164
    /// # Example
3165
    ///
3166
    /// ```
3167
    /// # use bevy_hanabi::*;
3168
    /// # use bevy::math::Vec3;
3169
    /// # let mut w = ExprWriter::new();
3170
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3171
    /// let x = w.lit(Vec3::ONE);
3172
    ///
3173
    /// // Sin: `y = sin(x);`
3174
    /// let y = x.sin();
3175
    /// ```
3176
    #[inline]
3177
    pub fn sin(self) -> Self {
×
3178
        self.unary_op(UnaryOperator::Sin)
×
3179
    }
3180

3181
    /// Apply the "sqrt" (square root) operator to the current float scalar or
3182
    /// vector expression.
3183
    ///
3184
    /// This is a unary operator, which applies to float scalar or vector
3185
    /// operand expressions to produce a float scalar or vector. It applies
3186
    /// component-wise to vector operand expressions.
3187
    ///
3188
    /// # Example
3189
    ///
3190
    /// ```
3191
    /// # use bevy_hanabi::*;
3192
    /// # use bevy::math::Vec3;
3193
    /// # let mut w = ExprWriter::new();
3194
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3195
    /// let x = w.lit(Vec3::ONE);
3196
    ///
3197
    /// // Square root: `y = sqrt(x);`
3198
    /// let y = x.sqrt();
3199
    /// ```
3200
    #[inline]
3201
    pub fn sqrt(self) -> Self {
×
3202
        self.unary_op(UnaryOperator::Sqrt)
×
3203
    }
3204

3205
    /// Apply the "tan" operator to the current float scalar or vector
3206
    /// expression.
3207
    ///
3208
    /// This is a unary operator, which applies to float scalar or vector
3209
    /// operand expressions to produce a float scalar or vector. It applies
3210
    /// component-wise to vector operand expressions.
3211
    ///
3212
    /// # Example
3213
    ///
3214
    /// ```
3215
    /// # use bevy_hanabi::*;
3216
    /// # use bevy::math::Vec3;
3217
    /// # let mut w = ExprWriter::new();
3218
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3219
    /// let x = w.lit(Vec3::ONE);
3220
    ///
3221
    /// // Tan: `y = tan(x);`
3222
    /// let y = x.tan();
3223
    /// ```
3224
    #[inline]
3225
    pub fn tan(self) -> Self {
×
3226
        self.unary_op(UnaryOperator::Tan)
×
3227
    }
3228

3229
    /// Apply the "unpack4x8snorm" operator to the current `u32` scalar
3230
    /// expression.
3231
    ///
3232
    /// This is a unary operator, which applies to `u32` scalar operand
3233
    /// expressions to produce a 4-component floating point vector of signed
3234
    /// normalized components in `[-1:1]`.
3235
    ///
3236
    /// # Example
3237
    ///
3238
    /// ```
3239
    /// # use bevy_hanabi::*;
3240
    /// # use bevy::math::Vec3;
3241
    /// # let mut w = ExprWriter::new();
3242
    /// // A literal expression `y = 0x7F007FFFu32;`.
3243
    /// let y = w.lit(0x7F007FFFu32);
3244
    ///
3245
    /// // Unpack: `x = unpack4x8snorm(y);`
3246
    /// let x = y.unpack4x8snorm(); // vec4<f32>(-1., 1., 0., 7.2)
3247
    /// ```
3248
    #[inline]
3249
    pub fn unpack4x8snorm(self) -> Self {
×
3250
        self.unary_op(UnaryOperator::Unpack4x8snorm)
×
3251
    }
3252

3253
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
3254
    /// expression.
3255
    ///
3256
    /// This is a unary operator, which applies to `u32` scalar operand
3257
    /// expressions to produce a 4-component floating point vector of unsigned
3258
    /// normalized components in `[0:1]`.
3259
    ///
3260
    /// # Example
3261
    ///
3262
    /// ```
3263
    /// # use bevy_hanabi::*;
3264
    /// # use bevy::math::Vec3;
3265
    /// # let mut w = ExprWriter::new();
3266
    /// // A literal expression `y = 0xFF00FF00u32;`.
3267
    /// let y = w.lit(0xFF00FF00u32);
3268
    ///
3269
    /// // Unpack: `x = unpack4x8unorm(y);`
3270
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
3271
    /// ```
3272
    #[inline]
3273
    pub fn unpack4x8unorm(self) -> Self {
×
3274
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
3275
    }
3276

3277
    /// Apply the "saturate" operator to the current float scalar or vector
3278
    /// expression.
3279
    ///
3280
    /// This is a unary operator, which applies to float scalar or vector
3281
    /// operand expressions to produce a float scalar or vector. It applies
3282
    /// component-wise to vector operand expressions.
3283
    ///
3284
    /// # Example
3285
    ///
3286
    /// ```
3287
    /// # use bevy_hanabi::*;
3288
    /// # use bevy::math::Vec3;
3289
    /// # let mut w = ExprWriter::new();
3290
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3291
    /// let x = w.lit(Vec3::ONE);
3292
    ///
3293
    /// // Saturate: `y = saturate(x);`
3294
    /// let y = x.saturate();
3295
    /// ```
3296
    #[inline]
3297
    pub fn saturate(self) -> Self {
×
3298
        self.unary_op(UnaryOperator::Saturate)
×
3299
    }
3300

3301
    /// Get the first component of a scalar or vector.
3302
    ///
3303
    /// # Example
3304
    ///
3305
    /// ```
3306
    /// # use bevy_hanabi::*;
3307
    /// # use bevy::math::Vec3;
3308
    /// # let mut w = ExprWriter::new();
3309
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3310
    /// let v = w.lit(Vec3::ONE);
3311
    ///
3312
    /// // f = v.x;`
3313
    /// let f = v.x();
3314
    /// ```
3315
    #[inline]
3316
    pub fn x(self) -> Self {
×
3317
        self.unary_op(UnaryOperator::X)
×
3318
    }
3319

3320
    /// Get the second component of a vector.
3321
    ///
3322
    /// # Example
3323
    ///
3324
    /// ```
3325
    /// # use bevy_hanabi::*;
3326
    /// # use bevy::math::Vec3;
3327
    /// # let mut w = ExprWriter::new();
3328
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3329
    /// let v = w.lit(Vec3::ONE);
3330
    ///
3331
    /// // f = v.y;`
3332
    /// let f = v.y();
3333
    /// ```
3334
    #[inline]
3335
    pub fn y(self) -> Self {
×
3336
        self.unary_op(UnaryOperator::Y)
×
3337
    }
3338

3339
    /// Get the third component of a vector.
3340
    ///
3341
    /// # Example
3342
    ///
3343
    /// ```
3344
    /// # use bevy_hanabi::*;
3345
    /// # use bevy::math::Vec3;
3346
    /// # let mut w = ExprWriter::new();
3347
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3348
    /// let v = w.lit(Vec3::ONE);
3349
    ///
3350
    /// // f = v.z;`
3351
    /// let f = v.z();
3352
    /// ```
3353
    #[inline]
3354
    pub fn z(self) -> Self {
×
3355
        self.unary_op(UnaryOperator::Z)
×
3356
    }
3357

3358
    /// Get the fourth component of a vector.
3359
    ///
3360
    /// # Example
3361
    ///
3362
    /// ```
3363
    /// # use bevy_hanabi::*;
3364
    /// # use bevy::math::Vec3;
3365
    /// # let mut w = ExprWriter::new();
3366
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3367
    /// let v = w.lit(Vec3::ONE);
3368
    ///
3369
    /// // f = v.w;`
3370
    /// let f = v.w();
3371
    /// ```
3372
    #[inline]
3373
    pub fn w(self) -> Self {
×
3374
        self.unary_op(UnaryOperator::W)
×
3375
    }
3376

3377
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
3378
        assert_eq!(self.module, other.module);
5✔
3379
        let left = self.expr;
10✔
3380
        let right = other.expr;
10✔
3381
        let expr = self
15✔
3382
            .module
10✔
3383
            .borrow_mut()
3384
            .add_expr(Expr::Binary { op, left, right });
15✔
3385
        WriterExpr {
3386
            expr,
3387
            module: self.module,
5✔
3388
        }
3389
    }
3390

3391
    /// Add the current expression with another expression.
3392
    ///
3393
    /// This is a binary operator, which applies component-wise to vector
3394
    /// operand expressions.
3395
    ///
3396
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3397
    /// symbol, as an alternative to calling this method directly.
3398
    ///
3399
    /// # Example
3400
    ///
3401
    /// ```
3402
    /// # use bevy_hanabi::*;
3403
    /// # use bevy::math::Vec2;
3404
    /// # let mut w = ExprWriter::new();
3405
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3406
    /// let x = w.lit(Vec2::new(3., -2.));
3407
    ///
3408
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3409
    /// let y = w.lit(Vec2::new(1., 5.));
3410
    ///
3411
    /// // The sum of both vectors `z = x + y;`.
3412
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3413
    ///                   // -OR-
3414
    ///                   // let z = x + y;
3415
    /// ```
3416
    #[allow(clippy::should_implement_trait)]
3417
    #[inline]
3418
    pub fn add(self, other: Self) -> Self {
2✔
3419
        self.binary_op(other, BinaryOperator::Add)
8✔
3420
    }
3421

3422
    /// Apply the "atan2" (inverse tangent with 2 arguments) operator to the
3423
    /// current float scalar or vector expression.
3424
    ///
3425
    /// This is a unary operator, which applies to float scalar or vector
3426
    /// operand expressions to produce a float scalar or vector. It applies
3427
    /// component-wise to vector operand expressions. The return value lies in
3428
    /// the -π ≤ x ≤ π range, and represents a value whose tangent is equal to
3429
    /// y over x (`z = atan2(y, x)` <=> `tan(z) = y / x`).
3430
    ///
3431
    /// # Example
3432
    ///
3433
    /// ```
3434
    /// # use bevy_hanabi::*;
3435
    /// # use bevy::math::Vec3;
3436
    /// # let mut w = ExprWriter::new();
3437
    /// // Two literal expressions `x` and `y`.
3438
    /// let x = w.lit(Vec3::new(1., 0., -1.));
3439
    /// let y = w.lit(Vec3::ONE);
3440
    ///
3441
    /// // Atan: `z = atan2(y, x);`
3442
    /// let z = y.atan2(x);
3443
    /// ```
3444
    #[inline]
3445
    pub fn atan2(self, other: Self) -> Self {
×
3446
        self.binary_op(other, BinaryOperator::Atan2)
×
3447
    }
3448

3449
    /// Calculate the cross product of the current expression by another
3450
    /// expression.
3451
    ///
3452
    /// This is a binary operator, which applies to vector operands of size 3
3453
    /// only, and always produces a vector of the same size.
3454
    ///
3455
    /// # Example
3456
    ///
3457
    /// ```
3458
    /// # use bevy_hanabi::*;
3459
    /// # use bevy::math::Vec3;
3460
    /// # let mut w = ExprWriter::new();
3461
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3462
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3463
    ///
3464
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3465
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3466
    ///
3467
    /// // The cross product of both vectors `z = cross(x, y);`.
3468
    /// let z = x.cross(y);
3469
    /// ```
3470
    #[inline]
3471
    pub fn cross(self, other: Self) -> Self {
×
3472
        self.binary_op(other, BinaryOperator::Cross)
×
3473
    }
3474

3475
    /// Calculate the dot product of the current expression by another
3476
    /// expression.
3477
    ///
3478
    /// This is a binary operator, which applies to vector operands of same size
3479
    /// only, and always produces a floating point scalar.
3480
    ///
3481
    /// # Example
3482
    ///
3483
    /// ```
3484
    /// # use bevy_hanabi::*;
3485
    /// # use bevy::math::Vec2;
3486
    /// # let mut w = ExprWriter::new();
3487
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3488
    /// let x = w.lit(Vec2::new(3., -2.));
3489
    ///
3490
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3491
    /// let y = w.lit(Vec2::new(1., 5.));
3492
    ///
3493
    /// // The dot product of both vectors `z = dot(x, y);`.
3494
    /// let z = x.dot(y);
3495
    /// ```
3496
    #[inline]
3497
    pub fn dot(self, other: Self) -> Self {
×
3498
        self.binary_op(other, BinaryOperator::Dot)
×
3499
    }
3500

3501
    /// Calculate the distance between the current expression and another
3502
    /// expression.
3503
    ///
3504
    /// This is a binary operator.
3505
    ///
3506
    /// # Example
3507
    ///
3508
    /// ```
3509
    /// # use bevy_hanabi::*;
3510
    /// # use bevy::math::Vec3;
3511
    /// # let mut w = ExprWriter::new();
3512
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3513
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3514
    ///
3515
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3516
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3517
    ///
3518
    /// // The distance between the vectors `z = distance(x, y);`.
3519
    /// let z = x.distance(y);
3520
    /// ```
3521
    #[inline]
3522
    pub fn distance(self, other: Self) -> Self {
×
3523
        self.binary_op(other, BinaryOperator::Distance)
×
3524
    }
3525

3526
    /// Divide the current expression by another expression.
3527
    ///
3528
    /// This is a binary operator, which applies component-wise to vector
3529
    /// operand expressions.
3530
    ///
3531
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3532
    /// symbol, as an alternative to calling this method directly.
3533
    ///
3534
    /// # Example
3535
    ///
3536
    /// ```
3537
    /// # use bevy_hanabi::*;
3538
    /// # use bevy::math::Vec2;
3539
    /// # let mut w = ExprWriter::new();
3540
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3541
    /// let x = w.lit(Vec2::new(3., -2.));
3542
    ///
3543
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3544
    /// let y = w.lit(Vec2::new(1., 5.));
3545
    ///
3546
    /// // The quotient of both vectors `z = x / y;`.
3547
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3548
    ///                   // -OR-
3549
    ///                   // let z = x / y;
3550
    /// ```
3551
    #[allow(clippy::should_implement_trait)]
3552
    #[inline]
3553
    pub fn div(self, other: Self) -> Self {
×
3554
        self.binary_op(other, BinaryOperator::Div)
×
3555
    }
3556

3557
    /// Apply the logical operator "greater than or equal" to this expression
3558
    /// and another expression.
3559
    ///
3560
    /// This is a binary operator, which applies component-wise to vector
3561
    /// operand expressions.
3562
    ///
3563
    /// # Example
3564
    ///
3565
    /// ```
3566
    /// # use bevy_hanabi::*;
3567
    /// # use bevy::math::Vec3;
3568
    /// # let mut w = ExprWriter::new();
3569
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3570
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3571
    ///
3572
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3573
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3574
    ///
3575
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3576
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3577
    /// ```
3578
    #[inline]
3579
    pub fn ge(self, other: Self) -> Self {
×
3580
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3581
    }
3582

3583
    /// Apply the logical operator "greater than" to this expression and another
3584
    /// expression.
3585
    ///
3586
    /// This is a binary operator, which applies component-wise to vector
3587
    /// operand expressions.
3588
    ///
3589
    /// # Example
3590
    ///
3591
    /// ```
3592
    /// # use bevy_hanabi::*;
3593
    /// # use bevy::math::Vec3;
3594
    /// # let mut w = ExprWriter::new();
3595
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3596
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3597
    ///
3598
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3599
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3600
    ///
3601
    /// // The boolean result of the greater than operation `z = (x > y);`.
3602
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3603
    /// ```
3604
    #[inline]
3605
    pub fn gt(self, other: Self) -> Self {
×
3606
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3607
    }
3608

3609
    /// Apply the logical operator "less than or equal" to this expression and
3610
    /// another expression.
3611
    ///
3612
    /// This is a binary operator, which applies component-wise to vector
3613
    /// operand expressions.
3614
    ///
3615
    /// # Example
3616
    ///
3617
    /// ```
3618
    /// # use bevy_hanabi::*;
3619
    /// # use bevy::math::Vec3;
3620
    /// # let mut w = ExprWriter::new();
3621
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3622
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3623
    ///
3624
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3625
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3626
    ///
3627
    /// // The boolean result of the less than or equal operation `z = (x <= y);`.
3628
    /// let z = x.le(y); // == vec3<bool>(false, true, true)
3629
    /// ```
3630
    #[inline]
3631
    pub fn le(self, other: Self) -> Self {
×
3632
        self.binary_op(other, BinaryOperator::LessThanOrEqual)
×
3633
    }
3634

3635
    /// Apply the logical operator "less than" to this expression and another
3636
    /// expression.
3637
    ///
3638
    /// This is a binary operator, which applies component-wise to vector
3639
    /// operand expressions.
3640
    ///
3641
    /// # Example
3642
    ///
3643
    /// ```
3644
    /// # use bevy_hanabi::*;
3645
    /// # use bevy::math::Vec3;
3646
    /// # let mut w = ExprWriter::new();
3647
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3648
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3649
    ///
3650
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3651
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3652
    ///
3653
    /// // The boolean result of the less than operation `z = (x < y);`.
3654
    /// let z = x.lt(y); // == vec3<bool>(false, true, false)
3655
    /// ```
3656
    #[inline]
3657
    pub fn lt(self, other: Self) -> Self {
×
3658
        self.binary_op(other, BinaryOperator::LessThan)
×
3659
    }
3660

3661
    /// Take the maximum value of the current expression and another expression.
3662
    ///
3663
    /// This is a binary operator, which applies component-wise to vector
3664
    /// operand expressions.
3665
    ///
3666
    /// # Example
3667
    ///
3668
    /// ```
3669
    /// # use bevy_hanabi::*;
3670
    /// # use bevy::math::Vec2;
3671
    /// # let mut w = ExprWriter::new();
3672
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3673
    /// let x = w.lit(Vec2::new(3., -2.));
3674
    ///
3675
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3676
    /// let y = w.lit(Vec2::new(1., 5.));
3677
    ///
3678
    /// // The maximum of both vectors `z = max(x, y);`.
3679
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3680
    /// ```
3681
    #[inline]
3682
    pub fn max(self, other: Self) -> Self {
1✔
3683
        self.binary_op(other, BinaryOperator::Max)
4✔
3684
    }
3685

3686
    /// Take the minimum value of the current expression and another expression.
3687
    ///
3688
    /// This is a binary operator, which applies component-wise to vector
3689
    /// operand expressions.
3690
    ///
3691
    /// # Example
3692
    ///
3693
    /// ```
3694
    /// # use bevy_hanabi::*;
3695
    /// # use bevy::math::Vec2;
3696
    /// # let mut w = ExprWriter::new();
3697
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3698
    /// let x = w.lit(Vec2::new(3., -2.));
3699
    ///
3700
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3701
    /// let y = w.lit(Vec2::new(1., 5.));
3702
    ///
3703
    /// // The minimum of both vectors `z = min(x, y);`.
3704
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3705
    /// ```
3706
    #[inline]
3707
    pub fn min(self, other: Self) -> Self {
1✔
3708
        self.binary_op(other, BinaryOperator::Min)
4✔
3709
    }
3710

3711
    /// Multiply the current expression with another expression.
3712
    ///
3713
    /// This is a binary operator, which applies component-wise to vector
3714
    /// operand expressions.
3715
    ///
3716
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3717
    /// symbol, as an alternative to calling this method directly.
3718
    ///
3719
    /// # Example
3720
    ///
3721
    /// ```
3722
    /// # use bevy_hanabi::*;
3723
    /// # use bevy::math::Vec2;
3724
    /// # let mut w = ExprWriter::new();
3725
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3726
    /// let x = w.lit(Vec2::new(3., -2.));
3727
    ///
3728
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3729
    /// let y = w.lit(Vec2::new(1., 5.));
3730
    ///
3731
    /// // The product of both vectors `z = x * y;`.
3732
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3733
    ///                   // -OR-
3734
    ///                   // let z = x * y;
3735
    /// ```
3736
    #[allow(clippy::should_implement_trait)]
3737
    #[inline]
3738
    pub fn mul(self, other: Self) -> Self {
1✔
3739
        self.binary_op(other, BinaryOperator::Mul)
4✔
3740
    }
3741

3742
    /// Apply the logical operator "normal" to this expression and another
3743
    /// expression.
3744
    ///
3745
    /// This is a binary operator, which applies component-wise to vector
3746
    /// operand expressions. That is, for vectors, this produces a vector of
3747
    /// random values where each component is normally distributed with a mean
3748
    /// of the corresponding component of the first operand and a standard
3749
    /// deviation of the corresponding component of the second operand.
3750
    ///
3751
    /// # Example
3752
    ///
3753
    /// ```
3754
    /// # use bevy_hanabi::*;
3755
    /// # use bevy::math::Vec3;
3756
    /// # let mut w = ExprWriter::new();
3757
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3758
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3759
    ///
3760
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3761
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3762
    ///
3763
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3764
    /// let z = x.normal(y);
3765
    /// ```
3766
    #[inline]
3767
    pub fn normal(self, other: Self) -> Self {
×
3768
        self.binary_op(other, BinaryOperator::NormalRand)
×
3769
    }
3770

3771
    /// Calculate the remainder of the division of the current expression by
3772
    /// another expression.
3773
    ///
3774
    /// This is a binary operator.
3775
    ///
3776
    /// # Example
3777
    ///
3778
    /// ```
3779
    /// # use bevy_hanabi::*;
3780
    /// # use bevy::math::Vec3;
3781
    /// # let mut w = ExprWriter::new();
3782
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3783
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3784
    ///
3785
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3786
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3787
    ///
3788
    /// // The remainder of the division `z = x % y;`.
3789
    /// let z = x.rem(y);
3790
    /// ```
3791
    #[allow(clippy::should_implement_trait)]
3792
    #[inline]
3793
    pub fn rem(self, other: Self) -> Self {
×
3794
        self.binary_op(other, BinaryOperator::Remainder)
×
3795
    }
3796

3797
    /// Calculate the step of a value with respect to a reference.
3798
    ///
3799
    /// This is a binary operator, which applies component-wise to vector
3800
    /// operand expressions.
3801
    ///
3802
    /// # Example
3803
    ///
3804
    /// ```
3805
    /// # use bevy_hanabi::*;
3806
    /// # use bevy::math::Vec3;
3807
    /// # let mut w = ExprWriter::new();
3808
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3809
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3810
    ///
3811
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3812
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3813
    ///
3814
    /// // The step value
3815
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3816
    /// ```
3817
    #[allow(clippy::should_implement_trait)]
3818
    #[inline]
3819
    pub fn step(self, edge: Self) -> Self {
×
3820
        // Note: order is step(edge, x) but x.step(edge)
3821
        edge.binary_op(self, BinaryOperator::Step)
×
3822
    }
3823

3824
    /// Subtract another expression from the current expression.
3825
    ///
3826
    /// This is a binary operator, which applies component-wise to vector
3827
    /// operand expressions.
3828
    ///
3829
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3830
    /// symbol, as an alternative to calling this method directly.
3831
    ///
3832
    /// # Example
3833
    ///
3834
    /// ```
3835
    /// # use bevy_hanabi::*;
3836
    /// # use bevy::math::Vec2;
3837
    /// # let mut w = ExprWriter::new();
3838
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3839
    /// let x = w.lit(Vec2::new(3., -2.));
3840
    ///
3841
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3842
    /// let y = w.lit(Vec2::new(1., 5.));
3843
    ///
3844
    /// // The difference of both vectors `z = x - y;`.
3845
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3846
    ///                   // -OR-
3847
    ///                   // let z = x - y;
3848
    /// ```
3849
    #[allow(clippy::should_implement_trait)]
3850
    #[inline]
3851
    pub fn sub(self, other: Self) -> Self {
×
3852
        self.binary_op(other, BinaryOperator::Sub)
×
3853
    }
3854

3855
    /// Apply the logical operator "uniform" to this expression and another
3856
    /// expression.
3857
    ///
3858
    /// This is a binary operator, which applies component-wise to vector
3859
    /// operand expressions. That is, for vectors, this produces a vector of
3860
    /// random values where each component is uniformly distributed within the
3861
    /// bounds of the related component of both operands.
3862
    ///
3863
    /// # Example
3864
    ///
3865
    /// ```
3866
    /// # use bevy_hanabi::*;
3867
    /// # use bevy::math::Vec3;
3868
    /// # let mut w = ExprWriter::new();
3869
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3870
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3871
    ///
3872
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3873
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3874
    ///
3875
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3876
    /// let z = x.uniform(y);
3877
    /// ```
3878
    #[inline]
3879
    pub fn uniform(self, other: Self) -> Self {
×
3880
        self.binary_op(other, BinaryOperator::UniformRand)
×
3881
    }
3882

3883
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3884
        assert_eq!(self.module, second.module);
×
3885
        assert_eq!(self.module, third.module);
×
3886
        let first = self.expr;
×
3887
        let second = second.expr;
×
3888
        let third = third.expr;
×
3889
        let expr = self.module.borrow_mut().add_expr(Expr::Ternary {
×
3890
            op,
×
3891
            first,
×
3892
            second,
×
3893
            third,
×
3894
        });
3895
        WriterExpr {
3896
            expr,
3897
            module: self.module,
×
3898
        }
3899
    }
3900

3901
    /// Blending linearly ("mix") two expressions with the fraction provided by
3902
    /// a third expression.
3903
    ///
3904
    /// This is a ternary operator, which applies component-wise to vector
3905
    /// operand expressions.
3906
    ///
3907
    /// # Example
3908
    ///
3909
    /// ```
3910
    /// # use bevy_hanabi::*;
3911
    /// # use bevy::math::Vec2;
3912
    /// # let mut w = ExprWriter::new();
3913
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3914
    /// let x = w.lit(Vec2::new(3., -2.));
3915
    ///
3916
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3917
    /// let y = w.lit(Vec2::new(1., 4.));
3918
    ///
3919
    /// // A fraction `t = 0.5;`.
3920
    /// let t = w.lit(0.25);
3921
    ///
3922
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3923
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3924
    /// ```
3925
    #[inline]
3926
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3927
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3928
    }
3929

3930
    /// Clamp an expression between the bounds defined by two other expressions.
3931
    ///
3932
    /// This is a ternary operator, which applies component-wise to vector
3933
    /// operand expressions.
3934
    ///
3935
    /// # Example
3936
    ///
3937
    /// ```
3938
    /// # use bevy_hanabi::*;
3939
    /// # use bevy::math::Vec2;
3940
    /// # let mut w = ExprWriter::new();
3941
    /// // A literal expression `x = vec2<f32>(1., -2.);`.
3942
    /// let x = w.lit(Vec2::new(1., -2.));
3943
    ///
3944
    /// // A literal expression `lo = vec2<f32>(3., -3.);`.
3945
    /// let lo = w.lit(Vec2::new(3., -3.));
3946
    ///
3947
    /// // A literal expression `hi = vec2<f32>(5., 1.);`.
3948
    /// let hi = w.lit(Vec2::new(5., 1.));
3949
    ///
3950
    /// // Clamp x in [lo:hi]
3951
    /// let z = x.clamp(lo, hi); // == vec2<f32>(3., -2.)
3952
    /// ```
3953
    #[inline]
3954
    pub fn clamp(self, lo: Self, hi: Self) -> Self {
×
3955
        self.ternary_op(lo, hi, TernaryOperator::Clamp)
×
3956
    }
3957

3958
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3959
    /// value taken between the given bounds.
3960
    ///
3961
    /// This is a ternary operator, which applies component-wise to vector
3962
    /// operand expressions.
3963
    ///
3964
    /// # Example
3965
    ///
3966
    /// ```
3967
    /// # use bevy_hanabi::*;
3968
    /// # use bevy::math::Vec2;
3969
    /// # let mut w = ExprWriter::new();
3970
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3971
    /// let low = w.lit(Vec2::new(3., -2.));
3972
    ///
3973
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3974
    /// let high = w.lit(Vec2::new(1., 4.));
3975
    ///
3976
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3977
    /// let x = w.lit(Vec2::new(2., 1.));
3978
    ///
3979
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3980
    /// let t = x.smoothstep(low, high); // == 0.5
3981
    /// ```
3982
    #[inline]
3983
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3984
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3985
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3986
    }
3987

3988
    /// Construct a `Vec2` from two scalars.
3989
    ///
3990
    /// # Example
3991
    ///
3992
    /// ```
3993
    /// # use bevy_hanabi::*;
3994
    /// # let mut w = ExprWriter::new();
3995
    /// let theta = w.add_property("theta", 0.0.into());
3996
    /// // Convert the angular property `theta` to a 2D vector.
3997
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3998
    /// let circle_pos = cos_theta.vec2(sin_theta);
3999
    /// ```
4000
    #[inline]
4001
    pub fn vec2(self, y: Self) -> Self {
×
4002
        self.binary_op(y, BinaryOperator::Vec2)
×
4003
    }
4004

4005
    /// Construct a `Vec3` from two scalars.
4006
    ///
4007
    /// # Example
4008
    ///
4009
    /// ```
4010
    /// # use bevy_hanabi::*;
4011
    /// # let mut w = ExprWriter::new();
4012
    /// let theta = w.add_property("theta", 0.0.into());
4013
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
4014
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
4015
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
4016
    /// ```
4017
    #[inline]
4018
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
4019
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
4020
    }
4021

4022
    /// Construct a `Vec4` from a vector XYZ and a scalar W.
4023
    ///
4024
    /// # Example
4025
    ///
4026
    /// ```
4027
    /// # use bevy_hanabi::*;
4028
    /// # let mut w = ExprWriter::new();
4029
    /// let rgb = w.rand(VectorType::VEC3F);
4030
    /// let a = w.lit(1.);
4031
    /// // Build vec4<f32>(R, G, B, A) and convert to 0xAABBGGRR
4032
    /// let col = rgb.vec4_xyz_w(a).pack4x8unorm();
4033
    /// ```
4034
    #[inline]
4035
    pub fn vec4_xyz_w(self, w: Self) -> Self {
×
4036
        self.binary_op(w, BinaryOperator::Vec4XyzW)
×
4037
    }
4038

4039
    /// Cast an expression to a different type.
4040
    ///
4041
    /// # Example
4042
    ///
4043
    /// ```
4044
    /// # use bevy_hanabi::*;
4045
    /// # use bevy::math::Vec2;
4046
    /// # let mut w = ExprWriter::new();
4047
    /// let x = w.lit(Vec2::new(3., -2.));
4048
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
4049
    /// ```
4050
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
4051
        let target = target.into();
×
4052
        let expr = self
×
4053
            .module
×
4054
            .borrow_mut()
4055
            .add_expr(Expr::Cast(CastExpr::new(self.expr, target)));
×
4056
        WriterExpr {
4057
            expr,
4058
            module: self.module,
×
4059
        }
4060
    }
4061

4062
    /// Finalize an expression chain and return the accumulated expression.
4063
    ///
4064
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
4065
    /// this intermediate expression was built from.
4066
    ///
4067
    /// # Example
4068
    ///
4069
    /// ```
4070
    /// # use bevy_hanabi::*;
4071
    /// # let mut w = ExprWriter::new();
4072
    /// // A literal expression `x = -3.5;`.
4073
    /// let x = w.lit(-3.5);
4074
    ///
4075
    /// // Retrieve the ExprHandle for that expression.
4076
    /// let handle = x.expr();
4077
    /// ```
4078
    #[inline]
4079
    pub fn expr(self) -> ExprHandle {
8✔
4080
        self.expr
8✔
4081
    }
4082
}
4083

4084
impl std::ops::Add<WriterExpr> for WriterExpr {
4085
    type Output = WriterExpr;
4086

4087
    #[inline]
4088
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
4089
        self.add(rhs)
6✔
4090
    }
4091
}
4092

4093
impl std::ops::Sub<WriterExpr> for WriterExpr {
4094
    type Output = WriterExpr;
4095

4096
    #[inline]
4097
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
4098
        self.sub(rhs)
×
4099
    }
4100
}
4101

4102
impl std::ops::Mul<WriterExpr> for WriterExpr {
4103
    type Output = WriterExpr;
4104

4105
    #[inline]
4106
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
4107
        self.mul(rhs)
3✔
4108
    }
4109
}
4110

4111
impl std::ops::Div<WriterExpr> for WriterExpr {
4112
    type Output = WriterExpr;
4113

4114
    #[inline]
4115
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
4116
        self.div(rhs)
×
4117
    }
4118
}
4119

4120
impl std::ops::Rem<WriterExpr> for WriterExpr {
4121
    type Output = WriterExpr;
4122

4123
    #[inline]
4124
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
4125
        self.rem(rhs)
×
4126
    }
4127
}
4128

4129
#[cfg(test)]
4130
mod tests {
4131
    use bevy::{platform::collections::HashSet, prelude::*};
4132
    use ron::ser::PrettyConfig;
4133

4134
    use super::*;
4135
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
4136

4137
    #[test]
4138
    fn module() {
4139
        let mut m = Module::default();
4140

4141
        #[allow(unsafe_code)]
4142
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
4143
        assert!(m.get(unknown).is_none());
4144
        assert!(m.get_mut(unknown).is_none());
4145
        assert!(matches!(
4146
            m.try_get(unknown),
4147
            Err(ExprError::InvalidExprHandleError(_))
4148
        ));
4149
        assert!(matches!(
4150
            m.try_get_mut(unknown),
4151
            Err(ExprError::InvalidExprHandleError(_))
4152
        ));
4153

4154
        let x = m.lit(5.);
4155
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
4156
        assert_eq!(m.get(x), Some(&expected));
4157
        assert_eq!(m.get_mut(x), Some(&mut expected));
4158
        assert_eq!(m.try_get(x), Ok(&expected));
4159
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
4160
    }
4161

4162
    #[test]
4163
    fn local_var() {
4164
        let property_layout = PropertyLayout::default();
4165
        let particle_layout = ParticleLayout::default();
4166
        let mut ctx =
4167
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4168
        let mut h = HashSet::new();
4169
        for _ in 0..100 {
4170
            let v = ctx.make_local_var();
4171
            assert!(h.insert(v));
4172
        }
4173
    }
4174

4175
    #[test]
4176
    fn make_fn() {
4177
        let property_layout = PropertyLayout::default();
4178
        let particle_layout = ParticleLayout::default();
4179
        let mut ctx =
4180
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4181
        let mut module = Module::default();
4182

4183
        // Make a function
4184
        let func_name = "my_func";
4185
        let args = "arg0: i32, arg1: f32";
4186
        assert!(ctx
4187
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
4188
                m.lit(3.);
4189
                let v = ctx.make_local_var();
4190
                assert_eq!(v, "var0");
4191
                let code = String::new();
4192
                Ok(code)
4193
            })
4194
            .is_ok());
4195

4196
        // The local function context doesn't influence the outer caller context
4197
        let v = ctx.make_local_var();
4198
        assert_eq!(v, "var0");
4199

4200
        // However the module is common to the outer caller and the function
4201
        assert!(!module.expressions.is_empty());
4202
    }
4203

4204
    #[test]
4205
    fn property() {
4206
        let mut m = Module::default();
4207

4208
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
4209
        let _other_prop = m.add_property(
4210
            "other_prop",
4211
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
4212
        );
4213

4214
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
4215
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
4216
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
4217
    }
4218

4219
    #[test]
4220
    fn writer() {
4221
        // Get a module and its writer
4222
        let w = ExprWriter::new();
4223
        let my_prop = w.add_property("my_prop", 3.0.into());
4224

4225
        // Build some expression
4226
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
4227
            + w.lit(-4.).min(w.prop(my_prop));
4228
        let x = x.expr();
4229

4230
        // Create an evaluation context
4231
        let property_layout =
4232
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
4233
        let particle_layout = ParticleLayout::default();
4234
        let m = w.finish();
4235
        let mut context =
4236
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4237

4238
        // Evaluate the expression
4239
        let x = m.try_get(x).unwrap();
4240
        let s = x.eval(&m, &mut context).unwrap();
4241
        assert_eq!(
4242
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties[properties_offset].my_prop))"
4243
                .to_string(),
4244
            s
4245
        );
4246
    }
4247

4248
    #[test]
4249
    fn type_error() {
4250
        let l = Value::Scalar(3.5_f32.into());
4251
        let r: Result<Vec2, ExprError> = l.try_into();
4252
        assert!(r.is_err());
4253
        assert!(matches!(r, Err(ExprError::TypeError(_))));
4254
    }
4255

4256
    #[test]
4257
    fn math_expr() {
4258
        let mut m = Module::default();
4259

4260
        let x = m.attr(Attribute::POSITION);
4261
        let y = m.lit(Vec3::ONE);
4262

4263
        let add = m.add(x, y);
4264
        let sub = m.sub(x, y);
4265
        let mul = m.mul(x, y);
4266
        let div = m.div(x, y);
4267
        let rem = m.rem(x, y);
4268
        let lt = m.lt(x, y);
4269
        let le = m.le(x, y);
4270
        let gt = m.gt(x, y);
4271
        let ge = m.ge(x, y);
4272

4273
        let property_layout = PropertyLayout::default();
4274
        let particle_layout = ParticleLayout::default();
4275
        let mut ctx =
4276
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4277

4278
        for (expr, op) in [
4279
            (add, "+"),
4280
            (sub, "-"),
4281
            (mul, "*"),
4282
            (div, "/"),
4283
            (rem, "%"),
4284
            (lt, "<"),
4285
            (le, "<="),
4286
            (gt, ">"),
4287
            (ge, ">="),
4288
        ] {
4289
            let expr = ctx.eval(&m, expr);
4290
            assert!(expr.is_ok());
4291
            let expr = expr.unwrap();
4292
            assert_eq!(
4293
                expr,
4294
                format!(
4295
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
4296
                    Attribute::POSITION.name(),
4297
                    op,
4298
                )
4299
            );
4300
        }
4301
    }
4302

4303
    #[test]
4304
    fn builtin_expr() {
4305
        let mut m = Module::default();
4306

4307
        // Simulation parameters
4308
        let builtin_ops = [
4309
            BuiltInOperator::Time,
4310
            BuiltInOperator::DeltaTime,
4311
            BuiltInOperator::VirtualTime,
4312
            BuiltInOperator::VirtualDeltaTime,
4313
            BuiltInOperator::RealTime,
4314
            BuiltInOperator::RealDeltaTime,
4315
        ];
4316
        for op in builtin_ops {
4317
            let handle = m.builtin(op);
4318

4319
            {
4320
                let expr = m.get(handle);
4321
                assert!(expr.is_some());
4322
                let expr = expr.unwrap();
4323
                assert!(matches!(*expr, Expr::BuiltIn(_)));
4324
                if let Expr::BuiltIn(op) = expr {
4325
                    assert!(builtin_ops.contains(&op.operator));
4326
                }
4327
            }
4328

4329
            let property_layout = PropertyLayout::default();
4330
            let particle_layout = ParticleLayout::default();
4331
            let mut ctx =
4332
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4333

4334
            let expr = ctx.eval(&m, handle);
4335
            assert!(expr.is_ok());
4336
            let expr = expr.unwrap();
4337
            assert_eq!(expr, format!("sim_params.{}", op.name()));
4338
        }
4339

4340
        // Exercise the expression introspection
4341
        for (handle, expr) in m.expressions() {
4342
            assert!(handle.index() < m.expressions.len());
4343
            assert!(matches!(*expr, Expr::BuiltIn(_)));
4344
            if let Expr::BuiltIn(op) = expr {
4345
                assert!(builtin_ops.contains(&op.operator));
4346
            }
4347
        }
4348

4349
        // is_alive
4350
        {
4351
            let value = m.builtin(BuiltInOperator::IsAlive);
4352

4353
            let property_layout = PropertyLayout::default();
4354
            let particle_layout = ParticleLayout::default();
4355
            let mut ctx =
4356
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4357

4358
            let expr = ctx.eval(&m, value);
4359
            assert!(expr.is_ok());
4360
            let expr = expr.unwrap();
4361
            assert_eq!(expr, "is_alive");
4362
        }
4363

4364
        // BuiltInOperator::Rand (which has side effect)
4365
        for (scalar_type, prefix) in [
4366
            (ScalarType::Bool, "b"),
4367
            (ScalarType::Float, "f"),
4368
            (ScalarType::Int, "i"),
4369
            (ScalarType::Uint, "u"),
4370
        ] {
4371
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
4372

4373
            // Scalar form
4374
            {
4375
                let property_layout = PropertyLayout::default();
4376
                let particle_layout = ParticleLayout::default();
4377
                let mut ctx =
4378
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4379

4380
                let expr = ctx.eval(&m, value);
4381
                assert!(expr.is_ok());
4382
                let expr = expr.unwrap();
4383
                assert_eq!(expr, "var0");
4384
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
4385
            }
4386

4387
            // Vector form
4388
            for count in 2..=4 {
4389
                let vec = m.builtin(BuiltInOperator::Rand(
4390
                    VectorType::new(scalar_type, count).into(),
4391
                ));
4392

4393
                let property_layout = PropertyLayout::default();
4394
                let particle_layout = ParticleLayout::default();
4395
                let mut ctx =
4396
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4397

4398
                let expr = ctx.eval(&m, vec);
4399
                assert!(expr.is_ok());
4400
                let expr = expr.unwrap();
4401
                assert_eq!(expr, "var0");
4402
                assert_eq!(
4403
                    ctx.main_code,
4404
                    format!("let var0 = {}rand{}();\n", prefix, count)
4405
                );
4406
            }
4407
        }
4408
    }
4409

4410
    #[test]
4411
    fn unary_expr() {
4412
        let mut m = Module::default();
4413

4414
        let x = m.attr(Attribute::POSITION);
4415
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
4416
        let z = m.lit(BVec3::new(false, true, false));
4417
        let w = m.lit(Vec4::W);
4418
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
4419
        let us = m.lit(0x0u32);
4420
        let uu = m.lit(0x0u32);
4421

4422
        let abs = m.abs(x);
4423
        let acos = m.acos(w);
4424
        let all = m.all(z);
4425
        let any = m.any(z);
4426
        let asin = m.asin(w);
4427
        let atan = m.atan(w);
4428
        let ceil = m.ceil(y);
4429
        let cos = m.cos(y);
4430
        let exp = m.exp(y);
4431
        let exp2 = m.exp2(y);
4432
        let floor = m.floor(y);
4433
        let fract = m.fract(y);
4434
        let inv_sqrt = m.inverse_sqrt(y);
4435
        let length = m.length(y);
4436
        let log = m.log(y);
4437
        let log2 = m.log2(y);
4438
        let norm = m.normalize(y);
4439
        let pack4x8snorm = m.pack4x8snorm(v);
4440
        let pack4x8unorm = m.pack4x8unorm(v);
4441
        let round = m.round(y);
4442
        let saturate = m.saturate(y);
4443
        let sign = m.sign(y);
4444
        let sin = m.sin(y);
4445
        let sqrt = m.sqrt(y);
4446
        let tan = m.tan(y);
4447
        let unpack4x8snorm = m.unpack4x8snorm(us);
4448
        let unpack4x8unorm = m.unpack4x8unorm(uu);
4449
        let comp_x = m.x(w);
4450
        let comp_y = m.y(w);
4451
        let comp_z = m.z(w);
4452
        let comp_w = m.w(w);
4453

4454
        let property_layout = PropertyLayout::default();
4455
        let particle_layout = ParticleLayout::default();
4456
        let mut ctx =
4457
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4458

4459
        for (expr, op, inner) in [
4460
            (
4461
                abs,
4462
                "abs",
4463
                &format!("particle.{}", Attribute::POSITION.name())[..],
4464
            ),
4465
            (acos, "acos", "vec4<f32>(0.,0.,0.,1.)"),
4466
            (all, "all", "vec3<bool>(false,true,false)"),
4467
            (any, "any", "vec3<bool>(false,true,false)"),
4468
            (asin, "asin", "vec4<f32>(0.,0.,0.,1.)"),
4469
            (atan, "atan", "vec4<f32>(0.,0.,0.,1.)"),
4470
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
4471
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
4472
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
4473
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
4474
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
4475
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
4476
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
4477
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
4478
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
4479
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
4480
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
4481
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4482
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4483
            (round, "round", "vec3<f32>(1.,-3.1,6.99)"),
4484
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4485
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4486
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4487
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4488
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4489
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4490
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4491
        ] {
4492
            let expr = ctx.eval(&m, expr);
4493
            assert!(expr.is_ok());
4494
            let expr = expr.unwrap();
4495
            assert_eq!(expr, format!("{}({})", op, inner));
4496
        }
4497

4498
        for (expr, op, inner) in [
4499
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4500
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4501
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4502
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4503
        ] {
4504
            let expr = ctx.eval(&m, expr);
4505
            assert!(expr.is_ok());
4506
            let expr = expr.unwrap();
4507
            assert_eq!(expr, format!("{}.{}", inner, op));
4508
        }
4509
    }
4510

4511
    #[test]
4512
    fn binary_expr() {
4513
        let mut m = Module::default();
4514

4515
        let x = m.attr(Attribute::POSITION);
4516
        let y = m.lit(Vec3::ONE);
4517
        let z = m.lit(1.45);
4518

4519
        let atan2 = m.atan2(x, y);
4520
        let cross = m.cross(x, y);
4521
        let dist = m.distance(x, y);
4522
        let dot = m.dot(x, y);
4523
        let min = m.min(x, y);
4524
        let max = m.max(x, y);
4525
        let step = m.step(x, y);
4526
        let vec4_xyz_w = m.vec4_xyz_w(x, z);
4527

4528
        let property_layout = PropertyLayout::default();
4529
        let particle_layout = ParticleLayout::default();
4530
        let mut ctx =
4531
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4532

4533
        for (expr, op) in [
4534
            (atan2, "atan2"),
4535
            (cross, "cross"),
4536
            (dist, "distance"),
4537
            (dot, "dot"),
4538
            (min, "min"),
4539
            (max, "max"),
4540
            (step, "step"),
4541
        ] {
4542
            let expr = ctx.eval(&m, expr);
4543
            assert!(expr.is_ok());
4544
            let expr = expr.unwrap();
4545
            assert_eq!(
4546
                expr,
4547
                format!(
4548
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4549
                    op,
4550
                    Attribute::POSITION.name(),
4551
                )
4552
            );
4553
        }
4554

4555
        {
4556
            let expr = ctx.eval(&m, vec4_xyz_w);
4557
            assert!(expr.is_ok());
4558
            let expr = expr.unwrap();
4559
            let z = ctx.eval(&m, z).unwrap();
4560
            assert_eq!(
4561
                expr,
4562
                format!("vec4(particle.{}, {})", Attribute::POSITION.name(), z)
4563
            );
4564
        }
4565
    }
4566

4567
    #[test]
4568
    fn ternary_expr() {
4569
        let mut m = Module::default();
4570

4571
        let x = m.attr(Attribute::POSITION);
4572
        let y = m.lit(Vec3::ONE);
4573
        let z = m.lit(Vec3::splat(2.));
4574
        let t = m.lit(0.3);
4575
        let a = m.lit(-4.2);
4576
        let b = m.lit(53.09);
4577

4578
        let mix = m.mix(x, y, t);
4579
        let clamp = m.clamp(x, y, z);
4580
        let smoothstep = m.smoothstep(x, y, x);
4581
        let vecthree = m.vec3(a, b, t);
4582

4583
        let property_layout = PropertyLayout::default();
4584
        let particle_layout = ParticleLayout::default();
4585
        let mut ctx =
4586
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4587

4588
        for (expr, op, third) in [
4589
            (mix, "mix", t),
4590
            (clamp, "clamp", z),
4591
            (smoothstep, "smoothstep", x),
4592
        ] {
4593
            let expr = ctx.eval(&m, expr);
4594
            assert!(expr.is_ok());
4595
            let expr = expr.unwrap();
4596
            let third = ctx.eval(&m, third).unwrap();
4597
            assert_eq!(
4598
                expr,
4599
                format!(
4600
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4601
                    op,
4602
                    Attribute::POSITION.name(),
4603
                    third
4604
                )
4605
            );
4606
        }
4607

4608
        {
4609
            let expr = ctx.eval(&m, vecthree);
4610
            assert!(expr.is_ok());
4611
            let expr = expr.unwrap();
4612
            let a = ctx.eval(&m, a).unwrap();
4613
            let b = ctx.eval(&m, b).unwrap();
4614
            let t = ctx.eval(&m, t).unwrap();
4615
            assert_eq!(expr, format!("vec3({}, {}, {})", a, b, t));
4616
        }
4617
    }
4618

4619
    #[test]
4620
    fn cast_expr() {
4621
        let mut m = Module::default();
4622

4623
        let x = m.attr(Attribute::POSITION);
4624
        let y = m.lit(IVec2::ONE);
4625
        let z = m.lit(0.3);
4626
        let w = m.lit(false);
4627

4628
        let cx = m.cast(x, VectorType::VEC3I);
4629
        let cy = m.cast(y, VectorType::VEC2U);
4630
        let cz = m.cast(z, ScalarType::Int);
4631
        let cw = m.cast(w, ScalarType::Uint);
4632

4633
        let property_layout = PropertyLayout::default();
4634
        let particle_layout = ParticleLayout::default();
4635
        let mut ctx =
4636
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4637

4638
        for (expr, cast, target) in [
4639
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4640
            (y, cy, VectorType::VEC2U.into()),
4641
            (z, cz, ScalarType::Int.into()),
4642
            (w, cw, ScalarType::Uint.into()),
4643
        ] {
4644
            let expr = ctx.eval(&m, expr);
4645
            assert!(expr.is_ok());
4646
            let expr = expr.unwrap();
4647
            let cast = ctx.eval(&m, cast);
4648
            assert!(cast.is_ok());
4649
            let cast = cast.unwrap();
4650
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4651
        }
4652
    }
4653

4654
    #[test]
4655
    fn attribute_pointer() {
4656
        let mut m = Module::default();
4657
        let x = m.attr(Attribute::POSITION);
4658

4659
        let property_layout = PropertyLayout::default();
4660
        let particle_layout = ParticleLayout::default();
4661
        let mut ctx =
4662
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4663

4664
        let res = ctx.eval(&m, x);
4665
        assert!(res.is_ok());
4666
        let xx = res.ok().unwrap();
4667
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4668

4669
        // Use a different context; it's invalid to reuse a mutated context, as the
4670
        // expression cache will have been generated with the wrong context.
4671
        let mut ctx =
4672
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4673
                .with_attribute_pointer();
4674

4675
        let res = ctx.eval(&m, x);
4676
        assert!(res.is_ok());
4677
        let xx = res.ok().unwrap();
4678
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4679
    }
4680

4681
    #[test]
4682
    #[should_panic]
4683
    fn invalid_cast_vector_to_scalar() {
4684
        let mut m = Module::default();
4685
        let x = m.lit(Vec2::ONE);
4686
        let _ = m.cast(x, ScalarType::Float);
4687
    }
4688

4689
    #[test]
4690
    #[should_panic]
4691
    fn invalid_cast_matrix_to_scalar() {
4692
        let mut m = Module::default();
4693
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4694
        let _ = m.cast(x, ScalarType::Float);
4695
    }
4696

4697
    #[test]
4698
    #[should_panic]
4699
    fn invalid_cast_matrix_to_vector() {
4700
        let mut m = Module::default();
4701
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4702
        let _ = m.cast(x, VectorType::VEC4F);
4703
    }
4704

4705
    #[test]
4706
    #[should_panic]
4707
    fn invalid_cast_scalar_to_matrix() {
4708
        let mut m = Module::default();
4709
        let x = m.lit(3.);
4710
        let _ = m.cast(x, MatrixType::MAT3X3F);
4711
    }
4712

4713
    #[test]
4714
    #[should_panic]
4715
    fn invalid_cast_vector_to_matrix() {
4716
        let mut m = Module::default();
4717
        let x = m.lit(Vec3::ZERO);
4718
        let _ = m.cast(x, MatrixType::MAT2X4F);
4719
    }
4720

4721
    #[test]
4722
    fn cast_expr_new() {
4723
        let mut m = Module::default();
4724

4725
        let x = m.attr(Attribute::POSITION);
4726
        let c = CastExpr::new(x, VectorType::VEC3F);
4727
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4728
        assert_eq!(c.is_valid(&m), Some(true));
4729

4730
        let x = m.attr(Attribute::POSITION);
4731
        let c = CastExpr::new(x, ScalarType::Bool);
4732
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4733
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4734

4735
        let p = m.add_property("my_prop", 3.0.into());
4736
        let y = m.prop(p);
4737
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4738
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4739
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4740
    }
4741

4742
    #[test]
4743
    fn side_effect() {
4744
        let mut m = Module::default();
4745

4746
        // Adding the same cloned expression with side effect to itself should yield
4747
        // twice the value, and not two separate evaluations of the expression.
4748
        // CORRECT:
4749
        //   let r = frand();
4750
        //   r + r
4751
        // INCORRECT:
4752
        //   frand() + frand()
4753

4754
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4755
        let r2 = r;
4756
        let r3 = r2;
4757
        let a = m.add(r, r2);
4758
        let b = m.mix(r, r2, r3);
4759
        let c = m.abs(a);
4760

4761
        {
4762
            let property_layout = PropertyLayout::default();
4763
            let particle_layout = ParticleLayout::default();
4764
            let mut ctx =
4765
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4766
            let value = ctx.eval(&m, a).unwrap();
4767
            assert_eq!(value, "(var0) + (var0)");
4768
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4769
        }
4770

4771
        {
4772
            let property_layout = PropertyLayout::default();
4773
            let particle_layout = ParticleLayout::default();
4774
            let mut ctx =
4775
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4776
            let value = ctx.eval(&m, b).unwrap();
4777
            assert_eq!(value, "mix(var0, var0, var0)");
4778
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4779
        }
4780

4781
        {
4782
            let property_layout = PropertyLayout::default();
4783
            let particle_layout = ParticleLayout::default();
4784
            let mut ctx =
4785
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4786
            let value = ctx.eval(&m, c).unwrap();
4787
            assert_eq!(value, "abs((var0) + (var0))");
4788
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4789
        }
4790
    }
4791

4792
    // #[test]
4793
    // fn serde() {
4794
    //     let v = Value::Scalar(3.0_f32.into());
4795
    //     let l: LiteralExpr = v.into();
4796
    //     assert_eq!(Ok(v), l.eval());
4797
    //     let s = ron::to_string(&l).unwrap();
4798
    //     println!("literal: {:?}", s);
4799
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4800
    //     assert_eq!(l_serde, l);
4801

4802
    //     let b: ExprHandle = Box::new(l);
4803
    //     let s = ron::to_string(&b).unwrap();
4804
    //     println!("boxed literal: {:?}", s);
4805
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4806
    //     assert!(b_serde.is_const());
4807
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4808

4809
    //     let v0 = Value::Scalar(3.0_f32.into());
4810
    //     let v1 = Value::Scalar(2.5_f32.into());
4811
    //     let l0: LiteralExpr = v0.into();
4812
    //     let l1: LiteralExpr = v1.into();
4813
    //     let a = l0 + l1;
4814
    //     assert!(a.is_const());
4815
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4816
    //     let s = ron::to_string(&a).unwrap();
4817
    //     println!("add: {:?}", s);
4818
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4819
    //     println!("a_serde: {:?}", a_serde);
4820
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4821
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4822
    // }
4823

4824
    #[test]
4825
    fn expr_handle_serde() {
4826
        let handle = ExprHandle {
4827
            id: NonZeroU32::new(42).unwrap(),
4828
        };
4829

4830
        // ser
4831
        let s = ron::ser::to_string_pretty(&handle, PrettyConfig::default()).unwrap();
4832
        eprintln!("{}", s);
4833

4834
        // de
4835
        {
4836
            let mut de = ron::de::Deserializer::from_str(&s).unwrap();
4837
            let serde_handle = ExprHandle::deserialize(&mut de).unwrap();
4838
            assert_eq!(handle, serde_handle);
4839
        }
4840

4841
        // de -- literatl string
4842
        {
4843
            let mut de = ron::de::Deserializer::from_str("\"#42\"").unwrap();
4844
            let serde_handle = ExprHandle::deserialize(&mut de).unwrap();
4845
            assert_eq!(handle, serde_handle);
4846
        }
4847

4848
        // de -- invalid string
4849
        {
4850
            let mut de = ron::de::Deserializer::from_str("\"invalid\"").unwrap();
4851
            let ret = ExprHandle::deserialize(&mut de);
4852
            assert!(ret.is_err());
4853
        }
4854

4855
        // de -- literal (not supported)
4856
        {
4857
            let mut de = ron::de::Deserializer::from_str("33").unwrap();
4858
            let ret = ExprHandle::deserialize(&mut de);
4859
            assert!(ret.is_err());
4860
        }
4861

4862
        // de -- invalid ID (zero)
4863
        {
4864
            let mut de = ron::de::Deserializer::from_str("\"#0\"").unwrap();
4865
            let ret = ExprHandle::deserialize(&mut de);
4866
            assert!(ret.is_err());
4867
        }
4868

4869
        // de -- invalid ID (negative)
4870
        {
4871
            let mut de = ron::de::Deserializer::from_str("\"#-5\"").unwrap();
4872
            let ret = ExprHandle::deserialize(&mut de);
4873
            assert!(ret.is_err());
4874
        }
4875

4876
        // de -- valid ID (u32::MAX)
4877
        {
4878
            let mut de = ron::de::Deserializer::from_str("\"#4294967295\"").unwrap();
4879
            let serde_handle = ExprHandle::deserialize(&mut de).unwrap();
4880
            assert_eq!(serde_handle.id.get(), u32::MAX);
4881
        }
4882

4883
        // de -- invalid ID (u32::MAX + 1; out of bounds)
4884
        {
4885
            let mut de = ron::de::Deserializer::from_str("\"#4294967296\"").unwrap();
4886
            let ret = ExprHandle::deserialize(&mut de);
4887
            assert!(ret.is_err());
4888
        }
4889
    }
4890
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc