1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4#[derive(Debug, Clone, PartialEq)]
6pub struct Orthotope {
7 edge_lengths: Vec<f64>,
8}
9
10impl Orthotope {
11 #[must_use]
13 pub fn new(edge_lengths: Vec<f64>) -> Option<Self> {
14 if !edge_lengths.is_empty()
15 && edge_lengths
16 .iter()
17 .all(|length| length.is_finite() && *length > 0.0)
18 {
19 Some(Self { edge_lengths })
20 } else {
21 None
22 }
23 }
24
25 #[must_use]
27 pub fn dimension(&self) -> usize {
28 self.edge_lengths.len()
29 }
30
31 #[must_use]
33 pub fn edge_lengths(&self) -> &[f64] {
34 &self.edge_lengths
35 }
36
37 #[must_use]
39 pub fn measure(&self) -> f64 {
40 self.edge_lengths.iter().product()
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq)]
46pub struct Cuboid {
47 width: f64,
48 height: f64,
49 depth: f64,
50}
51
52impl Cuboid {
53 #[must_use]
55 pub const fn new(width: f64, height: f64, depth: f64) -> Option<Self> {
56 if width.is_finite()
57 && height.is_finite()
58 && depth.is_finite()
59 && width > 0.0
60 && height > 0.0
61 && depth > 0.0
62 {
63 Some(Self {
64 width,
65 height,
66 depth,
67 })
68 } else {
69 None
70 }
71 }
72
73 #[must_use]
75 pub const fn volume(self) -> f64 {
76 self.width * self.height * self.depth
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq)]
82pub struct Cube {
83 edge: f64,
84}
85
86impl Cube {
87 #[must_use]
89 pub const fn new(edge: f64) -> Option<Self> {
90 if edge.is_finite() && edge > 0.0 {
91 Some(Self { edge })
92 } else {
93 None
94 }
95 }
96
97 #[must_use]
99 pub const fn edge(self) -> f64 {
100 self.edge
101 }
102
103 #[must_use]
105 pub const fn volume(self) -> f64 {
106 self.edge * self.edge * self.edge
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::{Cube, Cuboid, Orthotope};
113
114 #[test]
115 fn computes_orthotope_measures() {
116 let orthotope = Orthotope::new(vec![2.0, 3.0, 4.0]).expect("valid orthotope");
117 let cuboid = Cuboid::new(2.0, 3.0, 4.0).expect("valid cuboid");
118 let cube = Cube::new(3.0).expect("valid cube");
119
120 assert_eq!(orthotope.dimension(), 3);
121 assert_eq!(orthotope.measure(), 24.0);
122 assert_eq!(cuboid.volume(), 24.0);
123 assert_eq!(cube.edge(), 3.0);
124 assert_eq!(cube.volume(), 27.0);
125 }
126}