Skip to main content

use_orthotope/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// An n-dimensional orthotope represented by positive edge lengths.
5#[derive(Debug, Clone, PartialEq)]
6pub struct Orthotope {
7    edge_lengths: Vec<f64>,
8}
9
10impl Orthotope {
11    /// Creates an orthotope with positive finite edge lengths.
12    #[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    /// Returns the dimension.
26    #[must_use]
27    pub fn dimension(&self) -> usize {
28        self.edge_lengths.len()
29    }
30
31    /// Returns the edge lengths.
32    #[must_use]
33    pub fn edge_lengths(&self) -> &[f64] {
34        &self.edge_lengths
35    }
36
37    /// Returns the hypervolume.
38    #[must_use]
39    pub fn measure(&self) -> f64 {
40        self.edge_lengths.iter().product()
41    }
42}
43
44/// A rectangular cuboid.
45#[derive(Debug, Clone, Copy, PartialEq)]
46pub struct Cuboid {
47    width: f64,
48    height: f64,
49    depth: f64,
50}
51
52impl Cuboid {
53    /// Creates a cuboid with positive finite dimensions.
54    #[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    /// Returns the volume.
74    #[must_use]
75    pub const fn volume(self) -> f64 {
76        self.width * self.height * self.depth
77    }
78}
79
80/// A cube.
81#[derive(Debug, Clone, Copy, PartialEq)]
82pub struct Cube {
83    edge: f64,
84}
85
86impl Cube {
87    /// Creates a cube with a positive finite edge length.
88    #[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    /// Returns the edge length.
98    #[must_use]
99    pub const fn edge(self) -> f64 {
100        self.edge
101    }
102
103    /// Returns the volume.
104    #[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}