rapier2d/
utils.rs

1//! Miscellaneous utilities.
2
3use crate::math::Real;
4use na::{
5    Matrix1, Matrix2, Matrix3, RowVector2, Scalar, SimdRealField, UnitComplex, UnitQuaternion,
6    Vector1, Vector2, Vector3,
7};
8use parry::utils::SdpMatrix3;
9use std::ops::IndexMut;
10
11#[cfg(feature = "simd-is-enabled")]
12use crate::{
13    math::{SIMD_WIDTH, SimdReal},
14    num::Zero,
15};
16
17/// The trait for real numbers used by Rapier.
18///
19/// This includes `f32`, `f64` and their related SIMD types.
20pub trait SimdRealCopy: SimdRealField<Element = Real> + Copy {}
21impl SimdRealCopy for Real {}
22#[cfg(feature = "simd-is-enabled")]
23impl SimdRealCopy for SimdReal {}
24
25const INV_EPSILON: Real = 1.0e-20;
26
27pub(crate) fn inv(val: Real) -> Real {
28    if (-INV_EPSILON..=INV_EPSILON).contains(&val) {
29        0.0
30    } else {
31        1.0 / val
32    }
33}
34
35pub(crate) fn simd_inv<N: SimdRealCopy>(val: N) -> N {
36    let eps = N::splat(INV_EPSILON);
37    N::zero().select(val.simd_gt(-eps) & val.simd_lt(eps), N::one() / val)
38}
39
40/// Trait to copy the sign of each component of one scalar/vector/matrix to another.
41pub trait SimdSign<Rhs>: Sized {
42    // See SIMD implementations of copy_sign there: https://stackoverflow.com/a/57872652
43    /// Copy the sign of each component of `self` to the corresponding component of `to`.
44    fn copy_sign_to(self, to: Rhs) -> Rhs;
45}
46
47impl SimdSign<Real> for Real {
48    fn copy_sign_to(self, to: Self) -> Self {
49        const MINUS_ZERO: Real = -0.0;
50        let signbit = MINUS_ZERO.to_bits();
51        Real::from_bits((signbit & self.to_bits()) | ((!signbit) & to.to_bits()))
52    }
53}
54
55impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector2<N>> for N {
56    fn copy_sign_to(self, to: Vector2<N>) -> Vector2<N> {
57        Vector2::new(self.copy_sign_to(to.x), self.copy_sign_to(to.y))
58    }
59}
60
61impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector3<N>> for N {
62    fn copy_sign_to(self, to: Vector3<N>) -> Vector3<N> {
63        Vector3::new(
64            self.copy_sign_to(to.x),
65            self.copy_sign_to(to.y),
66            self.copy_sign_to(to.z),
67        )
68    }
69}
70
71impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector2<N>> for Vector2<N> {
72    fn copy_sign_to(self, to: Vector2<N>) -> Vector2<N> {
73        Vector2::new(self.x.copy_sign_to(to.x), self.y.copy_sign_to(to.y))
74    }
75}
76
77impl<N: Scalar + Copy + SimdSign<N>> SimdSign<Vector3<N>> for Vector3<N> {
78    fn copy_sign_to(self, to: Vector3<N>) -> Vector3<N> {
79        Vector3::new(
80            self.x.copy_sign_to(to.x),
81            self.y.copy_sign_to(to.y),
82            self.z.copy_sign_to(to.z),
83        )
84    }
85}
86
87#[cfg(feature = "simd-is-enabled")]
88impl SimdSign<SimdReal> for SimdReal {
89    fn copy_sign_to(self, to: SimdReal) -> SimdReal {
90        to.simd_copysign(self)
91    }
92}
93
94/// Trait to compute the orthonormal basis of a vector.
95pub trait SimdBasis: Sized {
96    /// The type of the array of orthonormal vectors.
97    type Basis;
98    /// Computes the vectors which, when combined with `self`, form an orthonormal basis.
99    fn orthonormal_basis(self) -> Self::Basis;
100    /// Computes a vector orthogonal to `self` with a unit length (if `self` has a unit length).
101    fn orthonormal_vector(self) -> Self;
102}
103
104impl<N: SimdRealCopy> SimdBasis for Vector2<N> {
105    type Basis = [Vector2<N>; 1];
106    fn orthonormal_basis(self) -> [Vector2<N>; 1] {
107        [Vector2::new(-self.y, self.x)]
108    }
109    fn orthonormal_vector(self) -> Vector2<N> {
110        Vector2::new(-self.y, self.x)
111    }
112}
113
114impl<N: SimdRealCopy + SimdSign<N>> SimdBasis for Vector3<N> {
115    type Basis = [Vector3<N>; 2];
116    // Robust and branchless implementation from Pixar:
117    // https://graphics.pixar.com/library/OrthonormalB/paper.pdf
118    fn orthonormal_basis(self) -> [Vector3<N>; 2] {
119        let sign = self.z.copy_sign_to(N::one());
120        let a = -N::one() / (sign + self.z);
121        let b = self.x * self.y * a;
122
123        [
124            Vector3::new(
125                N::one() + sign * self.x * self.x * a,
126                sign * b,
127                -sign * self.x,
128            ),
129            Vector3::new(b, sign + self.y * self.y * a, -self.y),
130        ]
131    }
132
133    fn orthonormal_vector(self) -> Vector3<N> {
134        let sign = self.z.copy_sign_to(N::one());
135        let a = -N::one() / (sign + self.z);
136        let b = self.x * self.y * a;
137        Vector3::new(b, sign + self.y * self.y * a, -self.y)
138    }
139}
140
141pub(crate) trait SimdCrossMatrix: Sized {
142    type CrossMat;
143    type CrossMatTr;
144
145    fn gcross_matrix(self) -> Self::CrossMat;
146    fn gcross_matrix_tr(self) -> Self::CrossMatTr;
147}
148
149impl<N: SimdRealCopy> SimdCrossMatrix for Vector3<N> {
150    type CrossMat = Matrix3<N>;
151    type CrossMatTr = Matrix3<N>;
152
153    #[inline]
154    #[rustfmt::skip]
155    fn gcross_matrix(self) -> Self::CrossMat {
156        Matrix3::new(
157            N::zero(), -self.z, self.y,
158            self.z, N::zero(), -self.x,
159            -self.y, self.x, N::zero(),
160        )
161    }
162
163    #[inline]
164    #[rustfmt::skip]
165    fn gcross_matrix_tr(self) -> Self::CrossMatTr {
166        Matrix3::new(
167            N::zero(), self.z, -self.y,
168            -self.z, N::zero(), self.x,
169            self.y, -self.x, N::zero(),
170        )
171    }
172}
173
174impl<N: SimdRealCopy> SimdCrossMatrix for Vector2<N> {
175    type CrossMat = RowVector2<N>;
176    type CrossMatTr = Vector2<N>;
177
178    #[inline]
179    fn gcross_matrix(self) -> Self::CrossMat {
180        RowVector2::new(-self.y, self.x)
181    }
182    #[inline]
183    fn gcross_matrix_tr(self) -> Self::CrossMatTr {
184        Vector2::new(-self.y, self.x)
185    }
186}
187impl SimdCrossMatrix for Real {
188    type CrossMat = Matrix2<Real>;
189    type CrossMatTr = Matrix2<Real>;
190
191    #[inline]
192    fn gcross_matrix(self) -> Matrix2<Real> {
193        Matrix2::new(0.0, -self, self, 0.0)
194    }
195
196    #[inline]
197    fn gcross_matrix_tr(self) -> Matrix2<Real> {
198        Matrix2::new(0.0, self, -self, 0.0)
199    }
200}
201
202#[cfg(feature = "simd-is-enabled")]
203impl SimdCrossMatrix for SimdReal {
204    type CrossMat = Matrix2<SimdReal>;
205    type CrossMatTr = Matrix2<SimdReal>;
206
207    #[inline]
208    fn gcross_matrix(self) -> Matrix2<SimdReal> {
209        Matrix2::new(SimdReal::zero(), -self, self, SimdReal::zero())
210    }
211
212    #[inline]
213    fn gcross_matrix_tr(self) -> Matrix2<SimdReal> {
214        Matrix2::new(SimdReal::zero(), self, -self, SimdReal::zero())
215    }
216}
217
218pub(crate) trait SimdCross<Rhs>: Sized {
219    type Result;
220    fn gcross(&self, rhs: Rhs) -> Self::Result;
221}
222
223impl SimdCross<Vector3<Real>> for Vector3<Real> {
224    type Result = Self;
225
226    fn gcross(&self, rhs: Vector3<Real>) -> Self::Result {
227        self.cross(&rhs)
228    }
229}
230
231impl SimdCross<Vector2<Real>> for Vector2<Real> {
232    type Result = Real;
233
234    fn gcross(&self, rhs: Vector2<Real>) -> Self::Result {
235        self.x * rhs.y - self.y * rhs.x
236    }
237}
238
239impl SimdCross<Vector2<Real>> for Real {
240    type Result = Vector2<Real>;
241
242    fn gcross(&self, rhs: Vector2<Real>) -> Self::Result {
243        Vector2::new(-rhs.y * *self, rhs.x * *self)
244    }
245}
246
247pub(crate) trait SimdDot<Rhs>: Sized {
248    type Result;
249    fn gdot(&self, rhs: Rhs) -> Self::Result;
250}
251
252impl<N: SimdRealCopy> SimdDot<Vector3<N>> for Vector3<N> {
253    type Result = N;
254
255    fn gdot(&self, rhs: Vector3<N>) -> Self::Result {
256        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
257    }
258}
259
260impl<N: SimdRealCopy> SimdDot<Vector2<N>> for Vector2<N> {
261    type Result = N;
262
263    fn gdot(&self, rhs: Vector2<N>) -> Self::Result {
264        self.x * rhs.x + self.y * rhs.y
265    }
266}
267
268impl<N: SimdRealCopy> SimdDot<Vector1<N>> for N {
269    type Result = N;
270
271    fn gdot(&self, rhs: Vector1<N>) -> Self::Result {
272        *self * rhs.x
273    }
274}
275
276impl<N: SimdRealCopy> SimdDot<N> for N {
277    type Result = N;
278
279    fn gdot(&self, rhs: N) -> Self::Result {
280        *self * rhs
281    }
282}
283
284impl<N: SimdRealCopy> SimdDot<N> for Vector1<N> {
285    type Result = N;
286
287    fn gdot(&self, rhs: N) -> Self::Result {
288        self.x * rhs
289    }
290}
291
292#[cfg(feature = "simd-is-enabled")]
293impl SimdCross<Vector3<SimdReal>> for Vector3<SimdReal> {
294    type Result = Vector3<SimdReal>;
295
296    fn gcross(&self, rhs: Self) -> Self::Result {
297        self.cross(&rhs)
298    }
299}
300
301#[cfg(feature = "simd-is-enabled")]
302impl SimdCross<Vector2<SimdReal>> for SimdReal {
303    type Result = Vector2<SimdReal>;
304
305    fn gcross(&self, rhs: Vector2<SimdReal>) -> Self::Result {
306        Vector2::new(-rhs.y * *self, rhs.x * *self)
307    }
308}
309
310#[cfg(feature = "simd-is-enabled")]
311impl SimdCross<Vector2<SimdReal>> for Vector2<SimdReal> {
312    type Result = SimdReal;
313
314    fn gcross(&self, rhs: Self) -> Self::Result {
315        let yx = Vector2::new(rhs.y, rhs.x);
316        let prod = self.component_mul(&yx);
317        prod.x - prod.y
318    }
319}
320
321/// Trait implemented by quaternions.
322pub trait SimdQuat<N> {
323    /// The result of quaternion differentiation.
324    type Result;
325
326    /// Compute the differential of `inv(q1) * q2`.
327    fn diff_conj1_2(&self, rhs: &Self) -> Self::Result;
328}
329
330impl<N: SimdRealCopy> SimdQuat<N> for UnitComplex<N> {
331    type Result = Matrix1<N>;
332
333    fn diff_conj1_2(&self, rhs: &Self) -> Self::Result {
334        let two: N = N::splat(2.0);
335        Matrix1::new((self.im * rhs.im + self.re * rhs.re) * two)
336    }
337}
338
339impl<N: SimdRealCopy> SimdQuat<N> for UnitQuaternion<N> {
340    type Result = Matrix3<N>;
341
342    fn diff_conj1_2(&self, rhs: &Self) -> Self::Result {
343        let half = N::splat(0.5);
344        let v1 = self.imag();
345        let v2 = rhs.imag();
346        let w1 = self.w;
347        let w2 = rhs.w;
348
349        // TODO: this can probably be optimized a lot by unrolling the ops.
350        (v1 * v2.transpose() + Matrix3::from_diagonal_element(w1 * w2)
351            - (v1 * w2 + v2 * w1).cross_matrix()
352            + v1.cross_matrix() * v2.cross_matrix())
353            * half
354    }
355}
356
357pub(crate) trait SimdAngularInertia<N> {
358    type AngVector;
359    type AngMatrix;
360    fn inverse(&self) -> Self;
361    fn transform_vector(&self, pt: Self::AngVector) -> Self::AngVector;
362    fn into_matrix(self) -> Self::AngMatrix;
363}
364
365impl<N: SimdRealCopy> SimdAngularInertia<N> for N {
366    type AngVector = N;
367    type AngMatrix = N;
368
369    fn inverse(&self) -> Self {
370        simd_inv(*self)
371    }
372
373    fn transform_vector(&self, pt: N) -> N {
374        pt * *self
375    }
376
377    fn into_matrix(self) -> Self::AngMatrix {
378        self
379    }
380}
381
382impl<N: SimdRealCopy> SimdAngularInertia<N> for SdpMatrix3<N> {
383    type AngVector = Vector3<N>;
384    type AngMatrix = Matrix3<N>;
385
386    fn inverse(&self) -> Self {
387        let minor_m12_m23 = self.m22 * self.m33 - self.m23 * self.m23;
388        let minor_m11_m23 = self.m12 * self.m33 - self.m13 * self.m23;
389        let minor_m11_m22 = self.m12 * self.m23 - self.m13 * self.m22;
390
391        let determinant =
392            self.m11 * minor_m12_m23 - self.m12 * minor_m11_m23 + self.m13 * minor_m11_m22;
393
394        if determinant.is_zero() {
395            Self::zero()
396        } else {
397            SdpMatrix3 {
398                m11: minor_m12_m23 / determinant,
399                m12: -minor_m11_m23 / determinant,
400                m13: minor_m11_m22 / determinant,
401                m22: (self.m11 * self.m33 - self.m13 * self.m13) / determinant,
402                m23: (self.m13 * self.m12 - self.m23 * self.m11) / determinant,
403                m33: (self.m11 * self.m22 - self.m12 * self.m12) / determinant,
404            }
405        }
406    }
407
408    fn transform_vector(&self, v: Vector3<N>) -> Vector3<N> {
409        let x = self.m11 * v.x + self.m12 * v.y + self.m13 * v.z;
410        let y = self.m12 * v.x + self.m22 * v.y + self.m23 * v.z;
411        let z = self.m13 * v.x + self.m23 * v.y + self.m33 * v.z;
412        Vector3::new(x, y, z)
413    }
414
415    #[rustfmt::skip]
416    fn into_matrix(self) -> Matrix3<N> {
417        Matrix3::new(
418            self.m11, self.m12, self.m13,
419            self.m12, self.m22, self.m23,
420            self.m13, self.m23, self.m33,
421        )
422    }
423}
424
425// This is an RAII structure that enables flushing denormal numbers
426// to zero, and automatically resetting previous flags once it is dropped.
427#[derive(Clone, Debug, PartialEq, Eq)]
428pub(crate) struct FlushToZeroDenormalsAreZeroFlags {
429    original_flags: u32,
430}
431
432impl FlushToZeroDenormalsAreZeroFlags {
433    #[cfg(not(all(
434        not(feature = "enhanced-determinism"),
435        any(target_arch = "x86_64", target_arch = "x86"),
436        target_feature = "sse"
437    )))]
438    pub fn flush_denormal_to_zero() -> Self {
439        Self { original_flags: 0 }
440    }
441
442    #[cfg(all(
443        not(feature = "enhanced-determinism"),
444        any(target_arch = "x86", target_arch = "x86_64"),
445        target_feature = "sse"
446    ))]
447    #[allow(deprecated)] // will address that later.
448    pub fn flush_denormal_to_zero() -> Self {
449        unsafe {
450            #[cfg(target_arch = "x86")]
451            use std::arch::x86::{_MM_FLUSH_ZERO_ON, _mm_getcsr, _mm_setcsr};
452            #[cfg(target_arch = "x86_64")]
453            use std::arch::x86_64::{_MM_FLUSH_ZERO_ON, _mm_getcsr, _mm_setcsr};
454
455            // Flush denormals & underflows to zero as this as a significant impact on the solver's performances.
456            // To enable this we need to set the bit 15 (given by _MM_FLUSH_ZERO_ON) and the bit 6 (for denormals-are-zero).
457            // See https://software.intel.com/content/www/us/en/develop/articles/x87-and-sse-floating-point-assists-in-ia-32-flush-to-zero-ftz-and-denormals-are-zero-daz.html
458            let original_flags = _mm_getcsr();
459            _mm_setcsr(original_flags | _MM_FLUSH_ZERO_ON | (1 << 6));
460            Self { original_flags }
461        }
462    }
463}
464
465#[cfg(all(
466    not(feature = "enhanced-determinism"),
467    any(target_arch = "x86", target_arch = "x86_64"),
468    target_feature = "sse"
469))]
470impl Drop for FlushToZeroDenormalsAreZeroFlags {
471    #[allow(deprecated)] // will address that later.
472    fn drop(&mut self) {
473        #[cfg(target_arch = "x86")]
474        unsafe {
475            std::arch::x86::_mm_setcsr(self.original_flags)
476        }
477        #[cfg(target_arch = "x86_64")]
478        unsafe {
479            std::arch::x86_64::_mm_setcsr(self.original_flags)
480        }
481    }
482}
483
484/// This is an RAII structure that disables floating point exceptions while
485/// it is alive, so that operations which generate NaNs and infinite values
486/// intentionally will not trip an exception when debugging problematic
487/// code that is generating NaNs and infinite values erroneously.
488#[derive(Clone, Debug, PartialEq, Eq)]
489pub(crate) struct DisableFloatingPointExceptionsFlags {
490    #[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
491    // We can't get a precise size for this, because it's of type
492    // `fenv_t`, which is a definition that doesn't exist in rust
493    // (not even in the libc crate, as of the time of writing.)
494    // But since the state is intended to be stored on the stack,
495    // 256 bytes should be more than enough.
496    original_flags: [u8; 256],
497}
498
499#[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
500extern "C" {
501    fn feholdexcept(env: *mut std::ffi::c_void);
502    fn fesetenv(env: *const std::ffi::c_void);
503}
504
505impl DisableFloatingPointExceptionsFlags {
506    #[cfg(not(feature = "debug-disable-legitimate-fe-exceptions"))]
507    #[allow(dead_code)]
508    /// Disables floating point exceptions as long as this object is not dropped.
509    pub fn disable_floating_point_exceptions() -> Self {
510        Self {}
511    }
512
513    #[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
514    /// Disables floating point exceptions as long as this object is not dropped.
515    pub fn disable_floating_point_exceptions() -> Self {
516        unsafe {
517            let mut original_flags = [0; 256];
518            feholdexcept(original_flags.as_mut_ptr() as *mut _);
519            Self { original_flags }
520        }
521    }
522}
523
524#[cfg(feature = "debug-disable-legitimate-fe-exceptions")]
525impl Drop for DisableFloatingPointExceptionsFlags {
526    fn drop(&mut self) {
527        unsafe {
528            fesetenv(self.original_flags.as_ptr() as *const _);
529        }
530    }
531}
532
533pub(crate) fn select_other<T: PartialEq>(pair: (T, T), elt: T) -> T {
534    if pair.0 == elt { pair.1 } else { pair.0 }
535}
536
537/// Methods for simultaneously indexing a container with two distinct indices.
538pub trait IndexMut2<I>: IndexMut<I> {
539    /// Gets mutable references to two distinct elements of the container.
540    ///
541    /// Panics if `i == j`.
542    fn index_mut2(&mut self, i: usize, j: usize) -> (&mut Self::Output, &mut Self::Output);
543
544    /// Gets a mutable reference to one element, and immutable reference to a second one.
545    ///
546    /// Panics if `i == j`.
547    #[inline]
548    fn index_mut_const(&mut self, i: usize, j: usize) -> (&mut Self::Output, &Self::Output) {
549        let (a, b) = self.index_mut2(i, j);
550        (a, &*b)
551    }
552}
553
554impl<T> IndexMut2<usize> for Vec<T> {
555    #[inline]
556    fn index_mut2(&mut self, i: usize, j: usize) -> (&mut T, &mut T) {
557        assert!(i != j, "Unable to index the same element twice.");
558        assert!(i < self.len() && j < self.len(), "Index out of bounds.");
559
560        unsafe {
561            let a = &mut *(self.get_unchecked_mut(i) as *mut _);
562            let b = &mut *(self.get_unchecked_mut(j) as *mut _);
563            (a, b)
564        }
565    }
566}
567
568impl<T> IndexMut2<usize> for [T] {
569    #[inline]
570    fn index_mut2(&mut self, i: usize, j: usize) -> (&mut T, &mut T) {
571        assert!(i != j, "Unable to index the same element twice.");
572        assert!(i < self.len() && j < self.len(), "Index out of bounds.");
573
574        unsafe {
575            let a = &mut *(self.get_unchecked_mut(i) as *mut _);
576            let b = &mut *(self.get_unchecked_mut(j) as *mut _);
577            (a, b)
578        }
579    }
580}
581
582/// Calculate the difference with smallest absolute value between the two given values.
583pub fn smallest_abs_diff_between_sin_angles<N: SimdRealCopy>(a: N, b: N) -> N {
584    // Select the smallest path among the two angles to reach the target.
585    let s_err = a - b;
586    let sgn = s_err.simd_signum();
587    let s_err_complement = s_err - sgn * N::splat(2.0);
588    let s_err_is_smallest = s_err.simd_abs().simd_lt(s_err_complement.simd_abs());
589    s_err.select(s_err_is_smallest, s_err_complement)
590}
591
592/// Calculate the difference with smallest absolute value between the two given angles.
593pub fn smallest_abs_diff_between_angles<N: SimdRealCopy>(a: N, b: N) -> N {
594    // Select the smallest path among the two angles to reach the target.
595    let s_err = a - b;
596    let sgn = s_err.simd_signum();
597    let s_err_complement = s_err - sgn * N::simd_two_pi();
598    let s_err_is_smallest = s_err.simd_abs().simd_lt(s_err_complement.simd_abs());
599    s_err.select(s_err_is_smallest, s_err_complement)
600}
601
602#[cfg(feature = "simd-nightly")]
603#[inline(always)]
604pub(crate) fn transmute_to_wide(val: [std::simd::f32x4; SIMD_WIDTH]) -> [wide::f32x4; SIMD_WIDTH] {
605    unsafe { std::mem::transmute(val) }
606}
607
608#[cfg(feature = "simd-stable")]
609#[inline(always)]
610pub(crate) fn transmute_to_wide(val: [wide::f32x4; SIMD_WIDTH]) -> [wide::f32x4; SIMD_WIDTH] {
611    val
612}
613
614/// Helpers around serialization.
615#[cfg(feature = "serde-serialize")]
616pub mod serde {
617    use serde::{Deserialize, Serialize};
618    use std::iter::FromIterator;
619
620    /// Serializes to a `Vec<(K, V)>`.
621    ///
622    /// Useful for [`std::collections::HashMap`] with a non-string key,
623    /// which is unsupported by [`serde_json`](https://docs.rs/serde_json/).
624    pub fn serialize_to_vec_tuple<
625        'a,
626        S: serde::Serializer,
627        T: IntoIterator<Item = (&'a K, &'a V)>,
628        K: Serialize + 'a,
629        V: Serialize + 'a,
630    >(
631        target: T,
632        s: S,
633    ) -> Result<S::Ok, S::Error> {
634        let container: Vec<_> = target.into_iter().collect();
635        serde::Serialize::serialize(&container, s)
636    }
637
638    /// Deserializes from a `Vec<(K, V)>`.
639    ///
640    /// Useful for [`std::collections::HashMap`] with a non-string key,
641    /// which is unsupported by [`serde_json`](https://docs.rs/serde_json/).
642    pub fn deserialize_from_vec_tuple<
643        'de,
644        D: serde::Deserializer<'de>,
645        T: FromIterator<(K, V)>,
646        K: Deserialize<'de>,
647        V: Deserialize<'de>,
648    >(
649        d: D,
650    ) -> Result<T, D::Error> {
651        let hashmap_as_vec: Vec<(K, V)> = Deserialize::deserialize(d)?;
652        Ok(T::from_iter(hashmap_as_vec))
653    }
654
655    #[cfg(test)]
656    mod test {
657        use std::collections::HashMap;
658
659        /// This test uses serde_json because json doesn't support non string
660        /// keys in hashmaps, which requires a custom serialization.
661        #[test]
662        fn serde_json_hashmap() {
663            #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
664            struct Test {
665                #[cfg_attr(
666                    feature = "serde-serialize",
667                    serde(
668                        serialize_with = "crate::utils::serde::serialize_to_vec_tuple",
669                        deserialize_with = "crate::utils::serde::deserialize_from_vec_tuple"
670                    )
671                )]
672                pub map: HashMap<usize, String>,
673            }
674
675            let s = Test {
676                map: [(42, "Forty-Two".to_string())].into(),
677            };
678            let j = serde_json::to_string(&s).unwrap();
679            assert_eq!(&j, "{\"map\":[[42,\"Forty-Two\"]]}");
680            let p: Test = serde_json::from_str(&j).unwrap();
681            assert_eq!(&p, &s);
682        }
683    }
684}