diff --git a/crates/fj-host/src/lib.rs b/crates/fj-host/src/lib.rs index f94b23459..910dd342f 100644 --- a/crates/fj-host/src/lib.rs +++ b/crates/fj-host/src/lib.rs @@ -21,6 +21,7 @@ use std::{ collections::{HashMap, HashSet}, ffi::OsStr, io, + ops::{Deref, DerefMut}, path::{Path, PathBuf}, process::Command, sync::mpsc, @@ -279,7 +280,8 @@ impl Watcher { } } -/// Parameters that are passed to a model +/// Parameters that are passed to a model. +#[derive(Debug, Clone, PartialEq)] pub struct Parameters(pub HashMap); impl Parameters { @@ -287,6 +289,31 @@ impl Parameters { pub fn empty() -> Self { Self(HashMap::new()) } + + /// Insert a value into the [`Parameters`] dictionary, implicitly converting + /// the arguments to strings and returning `&mut self` to enable chaining. + pub fn insert( + &mut self, + key: impl Into, + value: impl ToString, + ) -> &mut Self { + self.0.insert(key.into(), value.to_string()); + self + } +} + +impl Deref for Parameters { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Parameters { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } } /// An error that can occur when loading or reloading a model diff --git a/crates/fj/src/angle.rs b/crates/fj/src/angle.rs index 7e8a8794f..9911b959e 100644 --- a/crates/fj/src/angle.rs +++ b/crates/fj/src/angle.rs @@ -6,7 +6,7 @@ use std::f64::consts::{PI, TAU}; const GON_RAD: f64 = PI / 200.; /// An angle -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Angle { // The value of the angle in radians diff --git a/crates/fj/src/group.rs b/crates/fj/src/group.rs index a870d816a..4921cedc8 100644 --- a/crates/fj/src/group.rs +++ b/crates/fj/src/group.rs @@ -11,7 +11,7 @@ use crate::Shape; /// # Limitations /// /// Whether the shapes in the group touch or overlap is not currently checked. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Group { diff --git a/crates/fj/src/lib.rs b/crates/fj/src/lib.rs index 6282b4cbe..74a717750 100644 --- a/crates/fj/src/lib.rs +++ b/crates/fj/src/lib.rs @@ -34,7 +34,7 @@ pub use fj_proc::*; use serde::{Deserialize, Serialize}; /// A shape -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub enum Shape { diff --git a/crates/fj/src/shape_2d.rs b/crates/fj/src/shape_2d.rs index 1cd1e91c9..e1d3a43e4 100644 --- a/crates/fj/src/shape_2d.rs +++ b/crates/fj/src/shape_2d.rs @@ -6,7 +6,7 @@ use std::sync::atomic; use crate::Shape; /// A 2-dimensional shape -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub enum Shape2d { @@ -28,7 +28,7 @@ impl Shape2d { } /// A difference between two shapes -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Difference2d { @@ -73,7 +73,7 @@ impl From for Shape2d { /// Nothing about these edges is checked right now, but algorithms might assume /// that the edges are non-overlapping. If you create a `Sketch` with /// overlapping edges, you're on your own. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Sketch { @@ -118,7 +118,7 @@ impl Sketch { } /// A chain of elements that is part of a [`Sketch`] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub enum Chain { @@ -130,7 +130,7 @@ pub enum Chain { } /// A circle that is part of a [`Sketch`] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Circle { @@ -191,6 +191,11 @@ impl PolyChain { } } + /// Get a reference to the points in this [`PolyChain`]. + fn points(&self) -> &[[f64; 2]] { + unsafe { std::slice::from_raw_parts(self.ptr, self.length) } + } + /// Return the points that define the polygonal chain pub fn to_points(&self) -> Vec<[f64; 2]> { // This is sound. All invariants are automatically kept, as the raw @@ -229,6 +234,12 @@ impl Clone for PolyChain { } } +impl PartialEq for PolyChain { + fn eq(&self, other: &Self) -> bool { + self.points() == other.points() + } +} + impl Drop for PolyChain { fn drop(&mut self) { // Decrement the reference counter diff --git a/crates/fj/src/sweep.rs b/crates/fj/src/sweep.rs index afb6b1ebd..32153a016 100644 --- a/crates/fj/src/sweep.rs +++ b/crates/fj/src/sweep.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::{Shape, Shape2d}; /// A sweep of a 2-dimensional shape along straight path -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Sweep { diff --git a/crates/fj/src/transform.rs b/crates/fj/src/transform.rs index b826626ae..aebc14646 100644 --- a/crates/fj/src/transform.rs +++ b/crates/fj/src/transform.rs @@ -12,7 +12,7 @@ use crate::{Angle, Shape}; /// /// See issue: /// -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(C)] pub struct Transform {