pub use arc_of_circle::ArcOfCircle;
pub use circle::Circle;
pub use cubic::Cubic;
pub use distance::Distance;
pub use line_segment::LineSegment;
pub use normal::Normal;
pub use point::Point;
pub use workplane::Workplane;
mod arc_of_circle;
mod circle;
mod cubic;
mod distance;
mod line_segment;
mod normal;
mod point;
mod workplane;
use serde::{Deserialize, Serialize};
use std::{
any::{type_name, Any},
fmt::Debug,
marker::PhantomData,
};
use crate::{
bindings::{
Slvs_Entity, Slvs_hEntity, SLVS_E_ARC_OF_CIRCLE, SLVS_E_CIRCLE, SLVS_E_CUBIC,
SLVS_E_DISTANCE, SLVS_E_LINE_SEGMENT, SLVS_E_NORMAL_IN_2D, SLVS_E_NORMAL_IN_3D,
SLVS_E_POINT_IN_2D, SLVS_E_POINT_IN_3D, SLVS_E_WORKPLANE,
},
element::{AsAny, AsGroup, AsHandle, AsSlvsType, FromSystem},
};
pub trait AsEntityHandle: AsAny + AsHandle {
fn type_name(&self) -> &'static str;
}
impl AsAny for Box<dyn AsEntityHandle> {
fn as_any(&self) -> &dyn Any {
self.as_ref().as_any()
}
}
impl AsHandle for Box<dyn AsEntityHandle> {
fn handle(&self) -> u32 {
self.as_ref().handle()
}
}
impl AsEntityHandle for Box<dyn AsEntityHandle> {
fn type_name(&self) -> &'static str {
self.as_ref().type_name()
}
}
impl Debug for Box<dyn AsEntityHandle> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EntityHandle")
.field("handle", &self.handle())
.field("type", &self.type_name())
.finish()
}
}
impl From<Slvs_Entity> for Box<dyn AsEntityHandle> {
fn from(value: Slvs_Entity) -> Self {
match value.type_ as _ {
SLVS_E_ARC_OF_CIRCLE => {
Box::new(EntityHandle::<ArcOfCircle>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_CIRCLE => {
Box::new(EntityHandle::<Circle>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_CUBIC => {
Box::new(EntityHandle::<Cubic>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_DISTANCE => {
Box::new(EntityHandle::<Distance>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_LINE_SEGMENT => {
Box::new(EntityHandle::<LineSegment>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_NORMAL_IN_2D | SLVS_E_NORMAL_IN_3D => {
Box::new(EntityHandle::<Normal>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_POINT_IN_2D | SLVS_E_POINT_IN_3D => {
Box::new(EntityHandle::<Point>::new(value.h)) as Box<dyn AsEntityHandle>
}
SLVS_E_WORKPLANE => {
Box::new(EntityHandle::<Workplane>::new(value.h)) as Box<dyn AsEntityHandle>
}
_ => panic!("Unknown Slvs_Entity type value {}", value.type_),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EntityHandle<E: AsEntityData> {
pub handle: u32,
pub(super) phantom: PhantomData<E>,
}
impl<E: AsEntityData> EntityHandle<E> {
pub(crate) fn new(handle: u32) -> Self {
Self {
handle,
phantom: PhantomData,
}
}
}
impl<E: AsEntityData + 'static> AsAny for EntityHandle<E> {
fn as_any(&self) -> &dyn Any {
self
}
}
impl<E: AsEntityData> AsHandle for EntityHandle<E> {
fn handle(&self) -> u32 {
self.handle
}
}
impl<E: AsEntityData + 'static> AsEntityHandle for EntityHandle<E> {
fn type_name(&self) -> &'static str {
type_name::<E>()
}
}
impl<E: AsEntityData + Copy + 'static> TryFrom<&Box<dyn AsEntityHandle>> for EntityHandle<E> {
type Error = &'static str;
fn try_from(value: &Box<dyn AsEntityHandle>) -> Result<Self, Self::Error> {
if let Some(entity_handle) = value.as_any().downcast_ref::<EntityHandle<E>>() {
Ok(*entity_handle)
} else {
Err("Can only downcast boxed value into same type")
}
}
}
impl<E: AsEntityData> From<Slvs_Entity> for EntityHandle<E> {
fn from(value: Slvs_Entity) -> Self {
EntityHandle::new(value.h)
}
}
pub trait AsArc: AsEntityData {}
impl AsArc for ArcOfCircle {}
impl AsArc for Circle {}
pub trait AsCurve: AsEntityData {}
impl AsCurve for ArcOfCircle {}
impl AsCurve for Cubic {}
pub trait AsProjectionTarget: AsEntityData {}
impl AsProjectionTarget for LineSegment {}
impl AsProjectionTarget for Normal {}
pub trait AsEntityData: private::Sealed + AsGroup + AsSlvsType + FromSystem {
#[doc(hidden)]
fn workplane(&self) -> Option<Slvs_hEntity> {
None
}
#[doc(hidden)]
fn points(&self) -> Option<[Slvs_hEntity; 4]> {
None
}
#[doc(hidden)]
fn normal(&self) -> Option<Slvs_hEntity> {
None
}
#[doc(hidden)]
fn distance(&self) -> Option<Slvs_hEntity> {
None
}
#[doc(hidden)]
fn param_vals(&self) -> [Option<f64>; 4] {
[None, None, None, None]
}
}
mod private {
use super::AsEntityData;
pub trait Sealed {}
impl<E: AsEntityData> Sealed for E {}
}