diff --git a/README.md b/README.md index 34eab4d..d8452c6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Virtual Trackball Orbiting via the Exponential Map [Documentation]: https://docs.rs/trackball/badge.svg [Downloads]: https://img.shields.io/crates/d/trackball.svg [Version]: https://img.shields.io/crates/v/trackball.svg -[Rust]: https://img.shields.io/badge/rust-stable-brightgreen.svg +[Rust]: https://img.shields.io/badge/rust-v1.70-brightgreen.svg [License]: https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg This is an alternative trackball technique using exponential map and parallel transport to diff --git a/RELEASES.md b/RELEASES.md index 0de1f77..3aa3d11 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,9 @@ +# Version 0.11.2 (2023-08-16) + + * Make some types `Copy`. + * Fix `rkyv` by implementing `Archive` for `Self`. + * Enable `rkyv` for `docsrs` again. + # Version 0.11.1 (2023-08-09) * Fix scale boundary in `Scope::scale()` mode. diff --git a/src/bound.rs b/src/bound.rs index f4758f7..33f3d45 100644 --- a/src/bound.rs +++ b/src/bound.rs @@ -5,12 +5,8 @@ use nalgebra::{Isometry3, Point3, RealField, UnitQuaternion, Vector3}; /// Orthogonal boundary conditions implementing [`Clamp`]. /// /// Implements [`Default`] and can be created with `Bound::default()`. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] pub struct Bound { /// Isometry in world space of bound inversely transforming target and eye positions. pub transform: Isometry3, @@ -124,3 +120,31 @@ impl Clamp for Bound { None } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Bound { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Bound { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Bound { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +} diff --git a/src/clamp.rs b/src/clamp.rs index 2219e6a..66c492c 100644 --- a/src/clamp.rs +++ b/src/clamp.rs @@ -66,7 +66,7 @@ pub trait Clamp: Send + Sync + Debug + 'static { let pitch_axis = frame.pitch_axis(); // Old target position in eye space. let old_target = frame.target() - eye; - let mut min_delta = delta.clone(); + let mut min_delta = *delta; let mut loops = 0; loop { let frame = min_delta.transform(frame); @@ -133,7 +133,7 @@ pub trait Clamp: Send + Sync + Debug + 'static { let old_rot_inverse = frame.view().rotation.inverse(); // Old eye position in camera space. let old_eye = old_rot_inverse * (frame.eye() - target); - let mut min_delta = delta.clone(); + let mut min_delta = *delta; let mut loops = 0; loop { let mut bound = false; @@ -181,7 +181,7 @@ pub trait Clamp: Send + Sync + Debug + 'static { let old_target = frame.target(); let old_rot_inverse = frame.view().rotation.inverse(); let old_eye = frame.eye(); - let mut min_delta = delta.clone(); + let mut min_delta = *delta; let mut loops = 0; loop { let frame = min_delta.transform(old_frame); @@ -212,7 +212,7 @@ pub trait Clamp: Send + Sync + Debug + 'static { } &Delta::Scale { mut rat, pos } => { let old_zat = frame.distance(); - let mut min_delta = delta.clone(); + let mut min_delta = *delta; let mut loops = 0; loop { let frame = min_delta.transform(frame); diff --git a/src/delta.rs b/src/delta.rs index 47a229a..2aa389e 100644 --- a/src/delta.rs +++ b/src/delta.rs @@ -3,12 +3,8 @@ use nalgebra::{Point3, RealField, Unit, UnitQuaternion, Vector3}; use simba::scalar::SubsetOf; /// Delta transform from initial to final [`Frame`]. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] pub enum Delta { /// Yields frame as identity transform (default). Frame, @@ -54,7 +50,7 @@ impl Delta { /// Transforms from initial to final frame. #[must_use] pub fn transform(&self, frame: &Frame) -> Frame { - let mut frame = frame.clone(); + let mut frame = *frame; match self { Self::Frame => {} Self::First { @@ -104,7 +100,7 @@ impl Delta { /// * `t`: The interpolation parameter between 0 and 1. #[must_use] pub fn lerp_slerp(&self, t: N) -> Self { - match self.clone() { + match *self { Self::Frame => Self::Frame, Self::First { pitch, @@ -161,3 +157,31 @@ impl Default for Delta { Self::Frame } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Delta { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Delta { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Delta { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +} diff --git a/src/fixed.rs b/src/fixed.rs index 341071e..62d0002 100644 --- a/src/fixed.rs +++ b/src/fixed.rs @@ -6,12 +6,8 @@ use simba::scalar::SubsetOf; /// * Implements [`Default`] and can be created with `Fixed::default()` returning /// `Fixed::Ver(N::frac_pi_4())`. /// * Implements `From` and can be created with `N::into()` returning `Fixed::Ver()`. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] pub enum Fixed { /// Fixed horizontal field of view aka Vert- scaling. Hor(N), @@ -108,3 +104,31 @@ impl Fixed { } } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Fixed { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Fixed { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Fixed { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +} diff --git a/src/frame.rs b/src/frame.rs index 47c09fb..5a835eb 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -3,12 +3,8 @@ use nalgebra::{Isometry3, Point3, RealField, Unit, UnitQuaternion, Vector3}; use simba::scalar::SubsetOf; /// Frame wrt camera eye and target. -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] pub struct Frame { /// Target position in world space. pos: Point3, @@ -248,3 +244,31 @@ where && self.zat.ulps_eq(&other.zat, epsilon, max_ulps) } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Frame { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Frame { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Frame { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +} diff --git a/src/image.rs b/src/image.rs index a0e8a0a..b629aba 100644 --- a/src/image.rs +++ b/src/image.rs @@ -3,12 +3,8 @@ use nalgebra::{convert, zero, Isometry3, Matrix4, Point2, Point3, RealField, Vec use simba::scalar::SubsetOf; /// Image as projection of [`Scope`] wrt [`Frame`]. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] pub struct Image { /// Current position in screen space of hovering input or pointing device. pos: Point2, @@ -44,8 +40,8 @@ impl Image { pos: Point2::origin(), max, upp: zero(), - frame: frame.clone(), - scope: scope.clone(), + frame: *frame, + scope: *scope, view_iso: Isometry3::identity(), view_mat: zero(), proj_mat: zero(), @@ -236,3 +232,31 @@ impl Image { } } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Image { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Image { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Image { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +} diff --git a/src/lib.rs b/src/lib.rs index e922243..f324cf3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,8 @@ //! } //! ``` +#![cfg_attr(any(feature = "rkyv", feature = "cc"), deny(unsafe_code))] +#![cfg_attr(not(any(feature = "rkyv", feature = "cc")), forbid(unsafe_code))] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![forbid(missing_docs)] #![deny(rustdoc::broken_intra_doc_links)] diff --git a/src/orbit.rs b/src/orbit.rs index 556d6a2..9f5d24f 100644 --- a/src/orbit.rs +++ b/src/orbit.rs @@ -125,6 +125,7 @@ impl Orbit { .vec .map(|(ray, len)| ray.into_inner().push(len)) .unwrap_or_default(); + #[allow(unsafe_code)] unsafe { trackball_orbit_f( rot.as_vector_mut().as_mut_ptr(), @@ -182,6 +183,7 @@ impl Orbit { .vec .map(|(ray, len)| ray.into_inner().push(len)) .unwrap_or_default(); + #[allow(unsafe_code)] unsafe { trackball_orbit_d( rot.as_vector_mut().as_mut_ptr(), diff --git a/src/plane.rs b/src/plane.rs index 00eabd2..325d068 100644 --- a/src/plane.rs +++ b/src/plane.rs @@ -7,10 +7,6 @@ use simba::scalar::SubsetOf; /// Realizes plane equation `a*x+b*y+c*z+d=0` with unit normal `[x, y, z]` and signed bias `d`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] #[repr(C)] pub struct Plane { /// Plane unit normal. @@ -212,3 +208,31 @@ where && self.bias.ulps_eq(&other.bias, epsilon, max_ulps) } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Plane { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Plane { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Plane { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +} diff --git a/src/scope.rs b/src/scope.rs index c6dae82..d9d3f5f 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -5,12 +5,8 @@ use simba::scalar::SubsetOf; /// Scope defining enclosing viewing frustum. /// /// Implements [`Default`] and can be created with `Scope::default()`. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr( - feature = "rkyv", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] pub struct Scope { /// Fixed quantity wrt field of view. /// @@ -149,3 +145,31 @@ impl Scope { } } } + +#[cfg(feature = "rkyv")] +impl rkyv::Archive for Scope { + type Archived = Self; + type Resolver = (); + + #[inline] + #[allow(unsafe_code)] + unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) { + out.write(rkyv::to_archived!(*self as Self)); + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Serialize for Scope { + #[inline] + fn serialize(&self, _: &mut Ser) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv")] +impl rkyv::Deserialize for Scope { + #[inline] + fn deserialize(&self, _: &mut De) -> Result { + Ok(rkyv::from_archived!(*self)) + } +}