chunkgen 0.2.0

Minecraft world generation library
Documentation
use serde::Deserialize;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(try_from = "RawInclusiveRange")]
pub struct InclusiveRange {
    pub min_inclusive: i32,
    pub max_inclusive: i32,
}

#[derive(Deserialize)]
#[serde(untagged)]
pub enum RawInclusiveRange {
    Point(i32),
    Bounds([i32; 2]),
    Object {
        min_inclusive: i32,
        max_inclusive: i32,
    },
}

impl TryFrom<RawInclusiveRange> for InclusiveRange {
    type Error = &'static str;

    fn try_from(raw: RawInclusiveRange) -> Result<Self, Self::Error> {
        let (min_inclusive, max_inclusive) = match raw {
            RawInclusiveRange::Point(value) => (value, value),
            RawInclusiveRange::Bounds([min_inclusive, max_inclusive])
            | RawInclusiveRange::Object {
                min_inclusive,
                max_inclusive,
            } => (min_inclusive, max_inclusive),
        };

        if min_inclusive > max_inclusive {
            return Err("min_inclusive must be less than or equal to max_inclusive");
        }

        Ok(Self {
            min_inclusive,
            max_inclusive,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn accepts_every_vanilla_interval_form() {
        let point: InclusiveRange = serde_json::from_str("5").expect("test value");
        assert_eq!(point.min_inclusive, 5);
        assert_eq!(point.max_inclusive, 5);

        let bounds: InclusiveRange = serde_json::from_str("[1, 3]").expect("test value");
        assert_eq!(bounds.min_inclusive, 1);
        assert_eq!(bounds.max_inclusive, 3);

        let object: InclusiveRange =
            serde_json::from_str(r#"{"min_inclusive": 2, "max_inclusive": 7}"#)
                .expect("test value");
        assert_eq!(object.min_inclusive, 2);
        assert_eq!(object.max_inclusive, 7);
    }

    #[test]
    fn rejects_inverted_bounds() {
        assert!(serde_json::from_str::<InclusiveRange>("[9, 2]").is_err());
    }
}