diff --git a/crates/fj-kernel/src/objects/mod.rs b/crates/fj-kernel/src/objects/mod.rs index ab0976fbc..8cfa8facc 100644 --- a/crates/fj-kernel/src/objects/mod.rs +++ b/crates/fj-kernel/src/objects/mod.rs @@ -74,6 +74,7 @@ //! [#1021]: https://github.com/hannobraun/Fornjot/issues/1021 mod full; +mod object; mod stores; pub use self::{ @@ -88,6 +89,7 @@ pub use self::{ surface::Surface, vertex::{GlobalVertex, SurfaceVertex, Vertex}, }, + object::{Bare, BehindHandle, Form, Object, WithHandle}, stores::{ Curves, Cycles, Faces, GlobalCurves, GlobalEdges, GlobalVertices, HalfEdges, Objects, Shells, Sketches, Solids, SurfaceVertices, diff --git a/crates/fj-kernel/src/objects/object.rs b/crates/fj-kernel/src/objects/object.rs new file mode 100644 index 000000000..fd04a2280 --- /dev/null +++ b/crates/fj-kernel/src/objects/object.rs @@ -0,0 +1,137 @@ +use std::any::Any; + +use crate::{ + insert::Insert, + objects::{ + Curve, Cycle, Face, GlobalCurve, GlobalEdge, GlobalVertex, HalfEdge, + Objects, Shell, Sketch, Solid, Surface, SurfaceVertex, Vertex, + }, + storage::Handle, + validate::{Validate, ValidationError}, +}; + +macro_rules! object { + ($($ty:ident, $name:expr, $store:ident;)*) => { + /// An object + /// + /// This enum is generic over the form that the object takes. An + /// `Object` contains bare objects, like `Curve`. An + /// `Object` contains handles, like `Handle`. + #[derive(Clone)] + pub enum Object { + $( + #[doc = concat!("A ", $name)] + $ty(F::Form<$ty>), + )* + } + + impl Object { + /// Convert the `Object` into the requested inner type + pub fn as_inner(&self) -> Option<&F::Form> + where + Self: 'static, + F::Form: Any, + { + match self { + $( + Self::$ty(object) => + (object as &dyn Any).downcast_ref(), + + )* + } + } + } + + impl Object { + /// Insert the object into its respective store + pub fn insert( + self, + objects: &mut Objects, + ) -> Result, ValidationError> + where + $( + crate::objects::$ty: Insert, + ValidationError: From<<$ty as Validate>::Error>, + )* + { + match self { + $( + Self::$ty((handle, object)) => { + objects.$store.insert(handle.clone(), object)?; + Ok(handle.into()) + } + )* + } + } + } + + $( + impl From<$ty> for Object { + fn from(object: $ty) -> Self { + Self::$ty(object) + } + } + + impl From> for Object { + fn from(object: Handle<$ty>) -> Self { + Self::$ty(object) + } + } + + impl From<(Handle<$ty>, $ty)> for Object { + fn from((handle, object): (Handle<$ty>, $ty)) -> Self { + Self::$ty((handle, object)) + } + } + )* + }; +} + +object!( + Curve, "curve", curves; + Cycle, "cycle", cycles; + Face, "face", faces; + GlobalCurve, "global curve", global_curves; + GlobalEdge, "global edge", global_edges; + GlobalVertex, "global vertex", global_vertices; + HalfEdge, "half-edge", half_edges; + Shell, "shell", shells; + Sketch, "sketch", sketches; + Solid, "solid", solids; + Surface, "surface", surfaces; + SurfaceVertex, "surface vertex", surface_vertices; + Vertex, "vertex", vertices; +); + +/// The form that an object can take +/// +/// An object can be bare (see [`Bare`]) or behind a [`Handle`] (see +/// [`BehindHandle`]). +pub trait Form { + /// The form that the object takes + type Form; +} + +/// Implementation of [`Form`] for bare objects +#[derive(Clone)] +pub struct Bare; + +impl Form for Bare { + type Form = T; +} + +/// Implementation of [`Form`] for objects behind a handle +#[derive(Clone)] +pub struct BehindHandle; + +impl Form for BehindHandle { + type Form = Handle; +} + +/// Implementation of [`Form`] for objects that are paired with their handle +#[derive(Clone)] +pub struct WithHandle; + +impl Form for WithHandle { + type Form = (Handle, T); +}