use crate::{Age, AgeRange};
#[derive(Copy, Clone, Debug, Deserialize, EnumString, Serialize, PartialEq)]
pub enum AgeClass {
#[serde(rename = "5-12")]
#[strum(serialize = "5-12")]
Class5_12,
#[serde(rename = "13-15")]
#[strum(serialize = "13-15")]
Class13_15,
#[serde(rename = "16-17")]
#[strum(serialize = "16-17")]
Class16_17,
#[serde(rename = "18-19")]
#[strum(serialize = "18-19")]
Class18_19,
#[serde(rename = "20-23")]
#[strum(serialize = "20-23")]
Class20_23,
#[serde(rename = "24-34")]
#[strum(serialize = "24-34")]
Class24_34,
#[serde(rename = "35-39")]
#[strum(serialize = "35-39")]
Class35_39,
#[serde(rename = "40-44")]
#[strum(serialize = "40-44")]
Class40_44,
#[serde(rename = "45-49")]
#[strum(serialize = "45-49")]
Class45_49,
#[serde(rename = "50-54")]
#[strum(serialize = "50-54")]
Class50_54,
#[serde(rename = "55-59")]
#[strum(serialize = "55-59")]
Class55_59,
#[serde(rename = "60-64")]
#[strum(serialize = "60-64")]
Class60_64,
#[serde(rename = "65-69")]
#[strum(serialize = "65-69")]
Class65_69,
#[serde(rename = "70-74")]
#[strum(serialize = "70-74")]
Class70_74,
#[serde(rename = "75-79")]
#[strum(serialize = "75-79")]
Class75_79,
#[serde(rename = "80-999")]
#[strum(serialize = "80-999")]
Class80_999,
#[serde(rename = "")]
#[strum(serialize = "")]
None,
}
impl From<Age> for AgeClass {
fn from(age: Age) -> AgeClass {
let (min, max) = match age {
Age::Exact(n) => (n, n),
Age::Approximate(n) => (n, n + 1),
Age::None => {
return AgeClass::None;
}
};
if max < 30 {
match max {
05..=12 => AgeClass::Class5_12,
13..=15 => AgeClass::Class13_15,
16..=17 => AgeClass::Class16_17,
18..=19 => AgeClass::Class18_19,
20..=23 => AgeClass::Class20_23,
24..=34 => AgeClass::Class24_34,
_ => AgeClass::None,
}
} else {
match min {
24..=34 => AgeClass::Class24_34,
35..=39 => AgeClass::Class35_39,
40..=44 => AgeClass::Class40_44,
45..=49 => AgeClass::Class45_49,
50..=54 => AgeClass::Class50_54,
55..=59 => AgeClass::Class55_59,
60..=64 => AgeClass::Class60_64,
65..=69 => AgeClass::Class65_69,
70..=74 => AgeClass::Class70_74,
75..=79 => AgeClass::Class75_79,
80..=255 => AgeClass::Class80_999,
_ => AgeClass::None,
}
}
}
}
impl From<AgeRange> for AgeClass {
fn from(range: AgeRange) -> AgeClass {
let class_min = AgeClass::from(range.min);
let class_max = AgeClass::from(range.max);
if class_min == class_max {
return class_min;
}
if range.min.is_none() {
return AgeClass::None;
}
if range.distance().unwrap_or(100) <= 4 {
if range.max.to_u8_option().unwrap_or(30) < 30 {
return AgeClass::from(range.max);
}
return AgeClass::from(range.min);
}
AgeClass::None
}
}
#[cfg(test)]
mod tests {
use super::*;
fn range(min: u8, max: u8) -> AgeRange {
AgeRange::from((Age::Exact(min), Age::Exact(max)))
}
#[test]
fn from_approximate() {
assert_eq!(AgeClass::from(Age::Approximate(18)), AgeClass::Class18_19);
assert_eq!(AgeClass::from(Age::Approximate(19)), AgeClass::Class20_23);
assert_eq!(AgeClass::from(Age::Approximate(44)), AgeClass::Class40_44);
assert_eq!(AgeClass::from(Age::Approximate(45)), AgeClass::Class45_49);
}
#[test]
fn fuzzy_ranges() {
assert_eq!(AgeClass::from(range(40, 41)), AgeClass::Class40_44);
assert_eq!(AgeClass::from(range(40, 44)), AgeClass::Class40_44);
assert_eq!(AgeClass::from(range(44, 45)), AgeClass::Class40_44);
assert_eq!(AgeClass::from(range(44, 48)), AgeClass::Class40_44);
}
}