avian3d/collider_tree/
proxy_key.rs

1use core::hint::unreachable_unchecked;
2
3use bevy::{ecs::component::Component, reflect::Reflect};
4
5use crate::prelude::RigidBody;
6
7/// A key for a proxy in a [`ColliderTree`], encoding both
8/// the [`ProxyId`] and the [`ColliderTreeType`].
9///
10/// The tree type is stored in the lower 2 bits of the key,
11/// leaving 30 bits for the [`ProxyId`].
12///
13/// [`ColliderTree`]: crate::collider_tree::ColliderTree
14#[derive(Component, Clone, Copy, Debug, PartialEq, Eq, Hash, Reflect)]
15pub struct ColliderTreeProxyKey(u32);
16
17impl ColliderTreeProxyKey {
18    /// A placeholder proxy key used before the proxy is actually created.
19    pub const PLACEHOLDER: Self = ColliderTreeProxyKey(u32::MAX);
20
21    /// Creates a new [`ColliderTreeProxyKey`] from the given [`ProxyId`] and tree type.
22    #[inline]
23    pub const fn new(id: ProxyId, tree_type: ColliderTreeType) -> Self {
24        // Encode the tree type in the lower 2 bits.
25        ColliderTreeProxyKey((id.id() << 2) | (tree_type as u32))
26    }
27
28    /// Returns the [`ProxyId`] of the proxy.
29    #[inline]
30    pub const fn id(&self) -> ProxyId {
31        ProxyId::new(self.0 >> 2)
32    }
33
34    /// Returns the [`ColliderTreeType`] of the proxy.
35    #[inline]
36    pub const fn tree_type(&self) -> ColliderTreeType {
37        match self.0 & 0b11 {
38            0 => ColliderTreeType::Dynamic,
39            1 => ColliderTreeType::Kinematic,
40            2 => ColliderTreeType::Static,
41            3 => ColliderTreeType::Standalone,
42            // Safety: Bitwise AND with 0b11 can only yield 0, 1, 2, or 3.
43            _ => unsafe { unreachable_unchecked() },
44        }
45    }
46
47    /// Returns the rigid body type associated with the proxy.
48    ///
49    /// If the proxy is a standalone collider with no body, returns `None`.
50    #[inline]
51    pub const fn body(&self) -> Option<RigidBody> {
52        match self.0 & 0b11 {
53            0 => Some(RigidBody::Dynamic),
54            1 => Some(RigidBody::Kinematic),
55            2 => Some(RigidBody::Static),
56            3 => None,
57            // Safety: Bitwise AND with 0b11 can only yield 0, 1, 2, or 3.
58            _ => unsafe { unreachable_unchecked() },
59        }
60    }
61
62    /// Returns `true` if the proxy belongs to a dynamic body.
63    #[inline]
64    pub const fn is_dynamic(&self) -> bool {
65        if let Some(body) = self.body() {
66            body as u32 == RigidBody::Dynamic as u32
67        } else {
68            false
69        }
70    }
71
72    /// Returns `true` if the proxy belongs to a kinematic body.
73    #[inline]
74    pub const fn is_kinematic(&self) -> bool {
75        if let Some(body) = self.body() {
76            body as u32 == RigidBody::Kinematic as u32
77        } else {
78            false
79        }
80    }
81
82    /// Returns `true` if the proxy belongs to a static body.
83    #[inline]
84    pub const fn is_static(&self) -> bool {
85        if let Some(body) = self.body() {
86            body as u32 == RigidBody::Static as u32
87        } else {
88            false
89        }
90    }
91
92    /// Returns `true` if the proxy is a standalone collider with no body.
93    #[inline]
94    pub const fn is_standalone(&self) -> bool {
95        self.body().is_none()
96    }
97}
98
99/// A stable identifier for a proxy in a [`ColliderTree`].
100///
101/// [`ColliderTree`]: crate::collider_tree::ColliderTree
102#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Reflect)]
103pub struct ProxyId(u32);
104
105impl ProxyId {
106    /// A placeholder proxy ID used before the proxy is actually created.
107    pub const PLACEHOLDER: Self = ProxyId(u32::MAX >> 2);
108
109    /// Creates a new [`ProxyId`] from the given `u32` identifier.
110    ///
111    /// Only the lower 30 bits should be used for the ID.
112    ///
113    /// # Panics
114    ///
115    /// Panics if either of the upper 2 bits are set and `debug_assertions` are enabled.
116    #[inline]
117    pub const fn new(id: u32) -> Self {
118        debug_assert!(id < (1 << 30), "ProxyId can only use lower 30 bits");
119        ProxyId(id)
120    }
121
122    /// Returns the proxy ID as a `u32`.
123    #[inline]
124    pub const fn id(&self) -> u32 {
125        self.0
126    }
127
128    /// Returns the proxy ID as a `usize`.
129    #[inline]
130    pub const fn index(&self) -> usize {
131        self.0 as usize
132    }
133}
134
135impl From<u32> for ProxyId {
136    #[inline]
137    fn from(id: u32) -> Self {
138        ProxyId::new(id)
139    }
140}
141
142impl From<ProxyId> for u32 {
143    #[inline]
144    fn from(proxy_id: ProxyId) -> Self {
145        proxy_id.id()
146    }
147}
148
149impl PartialOrd for ProxyId {
150    #[inline]
151    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
152        Some(self.cmp(other))
153    }
154}
155
156impl Ord for ProxyId {
157    #[inline]
158    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
159        self.0.cmp(&other.0)
160    }
161}
162
163/// The type of a collider tree, corresponding to the rigid body type.
164#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Reflect)]
165pub enum ColliderTreeType {
166    /// A tree for dynamic bodies.
167    Dynamic = 0,
168    /// A tree for kinematic bodies.
169    Kinematic = 1,
170    /// A tree for static bodies.
171    Static = 2,
172    /// A tree for standalone colliders with no associated rigid body.
173    Standalone = 3,
174}
175
176impl ColliderTreeType {
177    /// An array of all possible [`ColliderTreeType`]s.
178    pub const ALL: [ColliderTreeType; 4] = [
179        ColliderTreeType::Dynamic,
180        ColliderTreeType::Kinematic,
181        ColliderTreeType::Static,
182        ColliderTreeType::Standalone,
183    ];
184
185    /// Creates a new [`ColliderTreeType`] from the given optional rigid body type.
186    ///
187    /// `None` corresponds to standalone colliders with no body.
188    #[inline]
189    pub const fn from_body(body: Option<RigidBody>) -> Self {
190        match body {
191            Some(RigidBody::Dynamic) => ColliderTreeType::Dynamic,
192            Some(RigidBody::Kinematic) => ColliderTreeType::Kinematic,
193            Some(RigidBody::Static) => ColliderTreeType::Static,
194            None => ColliderTreeType::Standalone,
195        }
196    }
197
198    /// Returns `true` if the tree type is for dynamic bodies.
199    #[inline]
200    pub const fn is_dynamic(&self) -> bool {
201        matches!(self, ColliderTreeType::Dynamic)
202    }
203
204    /// Returns `true` if the tree type is for kinematic bodies.
205    #[inline]
206    pub const fn is_kinematic(&self) -> bool {
207        matches!(self, ColliderTreeType::Kinematic)
208    }
209
210    /// Returns `true` if the tree type is for static bodies.
211    #[inline]
212    pub const fn is_static(&self) -> bool {
213        matches!(self, ColliderTreeType::Static)
214    }
215
216    /// Returns `true` if the tree type is for standalone colliders with no body.
217    #[inline]
218    pub const fn is_standalone(&self) -> bool {
219        matches!(self, ColliderTreeType::Standalone)
220    }
221}
222
223impl From<Option<RigidBody>> for ColliderTreeType {
224    #[inline]
225    fn from(body: Option<RigidBody>) -> Self {
226        match body {
227            Some(RigidBody::Dynamic) => ColliderTreeType::Dynamic,
228            Some(RigidBody::Kinematic) => ColliderTreeType::Kinematic,
229            Some(RigidBody::Static) => ColliderTreeType::Static,
230            None => ColliderTreeType::Standalone,
231        }
232    }
233}
234
235impl From<ColliderTreeType> for Option<RigidBody> {
236    #[inline]
237    fn from(tree_type: ColliderTreeType) -> Self {
238        match tree_type {
239            ColliderTreeType::Dynamic => Some(RigidBody::Dynamic),
240            ColliderTreeType::Kinematic => Some(RigidBody::Kinematic),
241            ColliderTreeType::Static => Some(RigidBody::Static),
242            ColliderTreeType::Standalone => None,
243        }
244    }
245}
246
247impl From<RigidBody> for ColliderTreeType {
248    #[inline]
249    fn from(body: RigidBody) -> Self {
250        match body {
251            RigidBody::Dynamic => ColliderTreeType::Dynamic,
252            RigidBody::Kinematic => ColliderTreeType::Kinematic,
253            RigidBody::Static => ColliderTreeType::Static,
254        }
255    }
256}