concentric_circles 0.1.0

Efficient generation and iteration of concentric circle perimeters using Bresenham's algorithm.
Documentation
use crate::FusedIterator;

/// an iterator for scaling values from type `u32` to type `u8`.
#[derive(Debug, Clone)]
pub struct ScalingU32 {
    denominator: core::num::NonZeroU32,
    iter: core::ops::Range<u32>,
}

impl ScalingU32 {
    /// Creates a new `ScalingU32` iterator.
    ///
    /// # Arguments
    ///
    /// * `num` - The number of points to scale. Must be in the range `1..=16843009`.
    ///
    /// # Returns
    ///
    /// A `ScalingU32` iterator that scales values from `0` to `num` (inclusive) to `u8`.
    /// If `num` is zero or exceeds the maximum allowed value, an empty iterator is returned.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use concentric_circles::ScalingU32;
    ///
    /// let scaling = ScalingU32::new(8);
    ///
    /// assert_eq!(scaling.collect::<Vec<_>>(),
    ///     vec![0, 31, 63, 95, 127, 159, 191, 223, 255]);
    /// ```
    #[inline]
    pub fn new(num: u32) -> Self {
        if num == 0 || num > 16843009 {
            Self {
                denominator: core::num::NonZeroU32::new(1).unwrap(),
                iter: 0..0,
            }
        } else {
            Self::new_unchecked(num)
        }
    }

    /// Creates a new `ScalingU32` iterator without checking the bounds.
    ///
    /// # Arguments
    ///
    /// * `num` - The number of points to scale.
    ///
    /// # Returns
    ///
    /// A `ScalingU32` iterator that scales values from `0` to `num` (inclusive) to `u8`.
    ///
    /// # Panics
    ///
    /// Panics if `num` is zero or exceeds the maximum allowed value.
    ///
    /// # Safety
    ///
    /// This method does not check that `num` is within valid bounds (except for zero).
    /// The caller must ensure that `num` is greater than zero and does not exceed the maximum allowed value.
    /// For a safe alternative that returns an empty iterator on invalid input, use [`ScalingU32::new`].
    ///
    /// # Example
    ///
    /// ```rust
    /// use concentric_circles::ScalingU32;
    ///
    /// let scaling = ScalingU32::new_unchecked(7);
    ///
    /// assert_eq!(scaling.collect::<Vec<_>>(),
    ///     vec![0, 36, 72, 109, 145, 182, 218, 255]);
    /// ```
    #[inline]
    pub fn new_unchecked(num: u32) -> Self {
        Self {
            denominator: core::num::NonZeroU32::new(num).expect("`num` must be greater than zero"),
            iter: 0..num + 1,
        }
    }
}

impl Iterator for ScalingU32 {
    type Item = u8;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        Some(((self.iter.next()? * 255) / self.denominator) as u8)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl FusedIterator for ScalingU32 {}

impl DoubleEndedIterator for ScalingU32 {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        Some(((self.iter.next_back()? * 255) / self.denominator) as u8)
    }
}