servo-webxr-api 0.1.0

A safe Rust API that provides a way to interact with virtual reality and augmented reality devices and integration with OpenXR. The API is inspired by the WebXR Device API (https://www.w3.org/TR/webxr/) but adapted to Rust design patterns.
Documentation
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use euclid::RigidTransform3D;
use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Serialize};

use crate::Native;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct HandSpace;

#[derive(Clone, Debug, Default, Serialize, Deserialize, MallocSizeOf)]
pub struct Hand<J> {
    pub wrist: Option<J>,
    pub thumb_metacarpal: Option<J>,
    pub thumb_phalanx_proximal: Option<J>,
    pub thumb_phalanx_distal: Option<J>,
    pub thumb_phalanx_tip: Option<J>,
    pub index: Finger<J>,
    pub middle: Finger<J>,
    pub ring: Finger<J>,
    pub little: Finger<J>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, MallocSizeOf)]
pub struct Finger<J> {
    pub metacarpal: Option<J>,
    pub phalanx_proximal: Option<J>,
    pub phalanx_intermediate: Option<J>,
    pub phalanx_distal: Option<J>,
    pub phalanx_tip: Option<J>,
}

#[derive(Clone, Copy, Debug, Serialize, Deserialize, MallocSizeOf)]
pub struct JointFrame {
    pub pose: RigidTransform3D<f32, HandSpace, Native>,
    pub radius: f32,
}

impl Default for JointFrame {
    fn default() -> Self {
        Self {
            pose: RigidTransform3D::identity(),
            radius: 0.,
        }
    }
}

impl<J> Hand<J> {
    pub fn map<R>(&self, map: impl (Fn(&Option<J>, Joint) -> Option<R>) + Copy) -> Hand<R> {
        Hand {
            wrist: map(&self.wrist, Joint::Wrist),
            thumb_metacarpal: map(&self.thumb_metacarpal, Joint::ThumbMetacarpal),
            thumb_phalanx_proximal: map(&self.thumb_phalanx_proximal, Joint::ThumbPhalanxProximal),
            thumb_phalanx_distal: map(&self.thumb_phalanx_distal, Joint::ThumbPhalanxDistal),
            thumb_phalanx_tip: map(&self.thumb_phalanx_tip, Joint::ThumbPhalanxTip),
            index: self.index.map(|f, j| map(f, Joint::Index(j))),
            middle: self.middle.map(|f, j| map(f, Joint::Middle(j))),
            ring: self.ring.map(|f, j| map(f, Joint::Ring(j))),
            little: self.little.map(|f, j| map(f, Joint::Little(j))),
        }
    }

    pub fn get(&self, joint: Joint) -> Option<&J> {
        match joint {
            Joint::Wrist => self.wrist.as_ref(),
            Joint::ThumbMetacarpal => self.thumb_metacarpal.as_ref(),
            Joint::ThumbPhalanxProximal => self.thumb_phalanx_proximal.as_ref(),
            Joint::ThumbPhalanxDistal => self.thumb_phalanx_distal.as_ref(),
            Joint::ThumbPhalanxTip => self.thumb_phalanx_tip.as_ref(),
            Joint::Index(f) => self.index.get(f),
            Joint::Middle(f) => self.middle.get(f),
            Joint::Ring(f) => self.ring.get(f),
            Joint::Little(f) => self.little.get(f),
        }
    }
}

impl<J> Finger<J> {
    pub fn map<R>(&self, map: impl (Fn(&Option<J>, FingerJoint) -> Option<R>) + Copy) -> Finger<R> {
        Finger {
            metacarpal: map(&self.metacarpal, FingerJoint::Metacarpal),
            phalanx_proximal: map(&self.phalanx_proximal, FingerJoint::PhalanxProximal),
            phalanx_intermediate: map(&self.phalanx_intermediate, FingerJoint::PhalanxIntermediate),
            phalanx_distal: map(&self.phalanx_distal, FingerJoint::PhalanxDistal),
            phalanx_tip: map(&self.phalanx_tip, FingerJoint::PhalanxTip),
        }
    }

    pub fn get(&self, joint: FingerJoint) -> Option<&J> {
        match joint {
            FingerJoint::Metacarpal => self.metacarpal.as_ref(),
            FingerJoint::PhalanxProximal => self.phalanx_proximal.as_ref(),
            FingerJoint::PhalanxIntermediate => self.phalanx_intermediate.as_ref(),
            FingerJoint::PhalanxDistal => self.phalanx_distal.as_ref(),
            FingerJoint::PhalanxTip => self.phalanx_tip.as_ref(),
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum FingerJoint {
    Metacarpal,
    PhalanxProximal,
    PhalanxIntermediate,
    PhalanxDistal,
    PhalanxTip,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Joint {
    Wrist,
    ThumbMetacarpal,
    ThumbPhalanxProximal,
    ThumbPhalanxDistal,
    ThumbPhalanxTip,
    Index(FingerJoint),
    Middle(FingerJoint),
    Ring(FingerJoint),
    Little(FingerJoint),
}