1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{
    objects::{
        Cycle, Face, GlobalEdge, HalfEdge, Region, Shell, Sketch, Solid,
        Surface, Vertex,
    },
    services::Services,
    storage::Handle,
};

use super::{Polygon, TetrahedronShell};

/// Insert an object into its respective store
///
/// This is the only primitive operation that is directly understood by
/// `Service<Objects>`. All other operations are built on top of it.
pub trait Insert: Sized {
    /// The type of `Self`, once it has been inserted
    ///
    /// Usually this is just `Handle<Self>`, but there are some more complex
    /// cases where this type needs to be customized.
    type Inserted;

    /// Insert the object into its respective store
    fn insert(self, services: &mut Services) -> Self::Inserted;
}

macro_rules! impl_insert {
    ($($ty:ty, $store:ident;)*) => {
        $(
            impl Insert for $ty {
                type Inserted = Handle<Self>;

                fn insert(self, services: &mut Services) -> Self::Inserted {
                    let handle = services.objects.$store.reserve();
                    let object = (handle.clone(), self).into();
                    services.insert_object(object);
                    handle
                }
            }
        )*
    };
}

impl_insert!(
    Cycle, cycles;
    Face, faces;
    GlobalEdge, global_edges;
    HalfEdge, half_edges;
    Region, regions;
    Shell, shells;
    Sketch, sketches;
    Solid, solids;
    Surface, surfaces;
    Vertex, vertices;
);

/// Indicate whether an object has been inserted
///
/// Intended to be used as a type parameter bound for structs that need to track
/// whether their contents have been inserted or not.
pub trait IsInserted {
    /// The type of the object for which the insertion status is tracked
    type T<T>;
}

/// Indicate that an object has been inserted
///
/// See [`IsInserted`].
pub struct IsInsertedYes;

impl IsInserted for IsInsertedYes {
    type T<T> = Handle<T>;
}

/// Indicate that an object has not been inserted
///
/// See [`IsInserted`].
pub struct IsInsertedNo;

impl IsInserted for IsInsertedNo {
    type T<T> = T;
}

impl<const D: usize> Insert for Polygon<D, IsInsertedNo> {
    type Inserted = Polygon<D, IsInsertedYes>;

    fn insert(self, services: &mut Services) -> Self::Inserted {
        Polygon {
            face: self.face.insert(services),
            edges: self.edges,
            vertices: self.vertices,
        }
    }
}

impl Insert for TetrahedronShell<IsInsertedNo> {
    type Inserted = TetrahedronShell<IsInsertedYes>;

    fn insert(self, services: &mut Services) -> Self::Inserted {
        TetrahedronShell {
            shell: self.shell.insert(services),
            abc: self.abc,
            bad: self.bad,
            dac: self.dac,
            cbd: self.cbd,
        }
    }
}