brepkit_topology/shell.rs
1//! Shell — a connected set of faces forming a surface boundary.
2
3use crate::TopologyError;
4use crate::arena;
5use crate::face::FaceId;
6
7/// Typed handle for a [`Shell`] stored in an [`Arena`](crate::Arena).
8pub type ShellId = arena::Id<Shell>;
9
10/// A topological shell: a connected set of faces.
11///
12/// A closed shell bounds a volume (solid). An open shell represents
13/// a sheet or partial boundary.
14#[derive(Debug, Clone)]
15pub struct Shell {
16 /// The faces that make up this shell.
17 faces: Vec<FaceId>,
18}
19
20impl Shell {
21 /// Creates a new shell from a non-empty list of faces.
22 ///
23 /// # Errors
24 ///
25 /// Returns [`TopologyError::Empty`] if `faces` is empty.
26 pub fn new(faces: Vec<FaceId>) -> Result<Self, TopologyError> {
27 if faces.is_empty() {
28 return Err(TopologyError::Empty { entity: "shell" });
29 }
30 Ok(Self { faces })
31 }
32
33 /// Creates a faceless shell backing an empty-result sentinel.
34 ///
35 /// A regular shell rejects an empty face list because an ordinary
36 /// surface boundary must enclose something. The empty shell exists
37 /// only so a boolean whose algebraic outcome is the empty set
38 /// (e.g. the intersection of disjoint solids) can be represented as
39 /// a valid, queryable solid handle reporting zero faces and zero
40 /// volume — distinct from a malformed-input error.
41 #[must_use]
42 pub const fn empty() -> Self {
43 Self { faces: Vec::new() }
44 }
45
46 /// Returns `true` when this shell has no faces (the empty-result
47 /// sentinel — see [`Shell::empty`]).
48 #[must_use]
49 pub fn is_empty(&self) -> bool {
50 self.faces.is_empty()
51 }
52
53 /// Returns the faces of this shell.
54 #[must_use]
55 pub fn faces(&self) -> &[FaceId] {
56 &self.faces
57 }
58
59 /// Returns mutable access to the faces of this shell.
60 ///
61 /// Allows in-place mutation (reorder, replace) but not removal.
62 /// The shell must always contain at least one face.
63 pub fn faces_mut(&mut self) -> &mut [FaceId] {
64 &mut self.faces
65 }
66}