/*
Copyright 2020-2023, Savanni D'Gerinel <savanni@luminescent-dreams.com>

This file is part of the Luminescent Dreams Tools.

Luminescent Dreams Tools is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Luminescent Dreams Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Lumeto. If not, see <https://www.gnu.org/licenses/>.
*/

// NOTE: this module is a candidate for extraction into its own crate, or should be replaced with
// an existing crate.

/// Specify an interval across the data type T
pub struct Interval<T> {
    start: T,
    start_incl: bool,
    end: T,
    end_incl: bool,
}

impl<T> Interval<T>
where
    T: Clone + Ord,
{
    /// Create a new interval from the start value to the end value, specifying inclusivity on
    /// either end of the interval.
    pub fn new(start: T, start_incl: bool, end: T, end_incl: bool) -> Interval<T> {
        Interval {
            start,
            start_incl,
            end,
            end_incl,
        }
    }

    /// Create an interval that matches *exactly* the specified value.
    pub fn exact(val: T) -> Interval<T> {
        Interval {
            start: val.clone(),
            start_incl: true,
            end: val,
            end_incl: true,
        }
    }

    /// Test whether a value is included in the specified interval.
    pub fn contains(&self, val: T) -> bool {
        match (self.start_incl, self.end_incl) {
            (true, true) => self.start <= val && val <= self.end,
            (true, false) => self.start <= val && val < self.end,
            (false, true) => self.start < val && val <= self.end,
            (false, false) => self.start < val && val < self.end,
        }
    }
}
