Skip to main content

use_sphere/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::f64::consts::PI;
5
6/// A three-dimensional Euclidean sphere represented by radius.
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct Sphere {
9    radius: f64,
10}
11
12impl Sphere {
13    /// Creates a sphere with a positive finite radius.
14    #[must_use]
15    pub const fn new(radius: f64) -> Option<Self> {
16        if radius.is_finite() && radius > 0.0 {
17            Some(Self { radius })
18        } else {
19            None
20        }
21    }
22
23    /// Returns the radius.
24    #[must_use]
25    pub const fn radius(self) -> f64 {
26        self.radius
27    }
28
29    /// Returns the diameter.
30    #[must_use]
31    pub const fn diameter(self) -> f64 {
32        self.radius * 2.0
33    }
34
35    /// Returns the surface area.
36    #[must_use]
37    pub fn surface_area(self) -> f64 {
38        4.0 * PI * self.radius * self.radius
39    }
40
41    /// Returns the enclosed volume.
42    #[must_use]
43    pub fn volume(self) -> f64 {
44        (4.0 / 3.0) * PI * self.radius * self.radius * self.radius
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use core::f64::consts::PI;
51
52    use super::Sphere;
53
54    fn approx_eq(left: f64, right: f64) -> bool {
55        (left - right).abs() < 1.0e-10
56    }
57
58    #[test]
59    fn computes_sphere_measurements() {
60        let sphere = Sphere::new(3.0).expect("valid sphere");
61
62        assert_eq!(sphere.radius(), 3.0);
63        assert_eq!(sphere.diameter(), 6.0);
64        assert!(approx_eq(sphere.surface_area(), 36.0 * PI));
65        assert!(approx_eq(sphere.volume(), 36.0 * PI));
66        assert_eq!(Sphere::new(0.0), None);
67    }
68}