use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[non_exhaustive]
pub enum PiagetStage {
Sensorimotor,
Preoperational,
ConcreteOperational,
FormalOperational,
}
impl PiagetStage {
#[inline]
#[must_use]
pub fn typical_age_range(self) -> (f64, f64) {
match self {
Self::Sensorimotor => (0.0, 2.0),
Self::Preoperational => (2.0, 7.0),
Self::ConcreteOperational => (7.0, 11.0),
Self::FormalOperational => (11.0, 18.0),
}
}
#[must_use]
pub fn from_age(age: f64) -> Option<Self> {
if age < 0.0 || !age.is_finite() {
return None;
}
if age < 2.0 {
Some(Self::Sensorimotor)
} else if age < 7.0 {
Some(Self::Preoperational)
} else if age < 11.0 {
Some(Self::ConcreteOperational)
} else {
Some(Self::FormalOperational)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[non_exhaustive]
pub enum EriksonStage {
TrustVsMistrust,
AutonomyVsShame,
InitiativeVsGuilt,
IndustryVsInferiority,
IdentityVsRoleConfusion,
IntimacyVsIsolation,
GenerativityVsStagnation,
IntegrityVsDespair,
}
impl EriksonStage {
#[inline]
#[must_use]
pub fn typical_age_range(self) -> (f64, f64) {
match self {
Self::TrustVsMistrust => (0.0, 1.5),
Self::AutonomyVsShame => (1.5, 3.0),
Self::InitiativeVsGuilt => (3.0, 5.0),
Self::IndustryVsInferiority => (5.0, 12.0),
Self::IdentityVsRoleConfusion => (12.0, 18.0),
Self::IntimacyVsIsolation => (18.0, 40.0),
Self::GenerativityVsStagnation => (40.0, 65.0),
Self::IntegrityVsDespair => (65.0, 100.0),
}
}
#[must_use]
pub fn from_age(age: f64) -> Option<Self> {
if age < 0.0 || !age.is_finite() {
return None;
}
if age < 1.5 {
Some(Self::TrustVsMistrust)
} else if age < 3.0 {
Some(Self::AutonomyVsShame)
} else if age < 5.0 {
Some(Self::InitiativeVsGuilt)
} else if age < 12.0 {
Some(Self::IndustryVsInferiority)
} else if age < 18.0 {
Some(Self::IdentityVsRoleConfusion)
} else if age < 40.0 {
Some(Self::IntimacyVsIsolation)
} else if age < 65.0 {
Some(Self::GenerativityVsStagnation)
} else {
Some(Self::IntegrityVsDespair)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_piaget_from_age() {
assert_eq!(PiagetStage::from_age(0.5), Some(PiagetStage::Sensorimotor));
assert_eq!(
PiagetStage::from_age(4.0),
Some(PiagetStage::Preoperational)
);
assert_eq!(
PiagetStage::from_age(9.0),
Some(PiagetStage::ConcreteOperational)
);
assert_eq!(
PiagetStage::from_age(15.0),
Some(PiagetStage::FormalOperational)
);
}
#[test]
fn test_piaget_invalid_age() {
assert_eq!(PiagetStage::from_age(-1.0), None);
assert_eq!(PiagetStage::from_age(f64::NAN), None);
}
#[test]
fn test_piaget_age_range() {
let (min, max) = PiagetStage::Sensorimotor.typical_age_range();
assert!((min - 0.0).abs() < 1e-10);
assert!((max - 2.0).abs() < 1e-10);
}
#[test]
fn test_erikson_from_age_all_stages() {
assert_eq!(
EriksonStage::from_age(0.5),
Some(EriksonStage::TrustVsMistrust)
);
assert_eq!(
EriksonStage::from_age(2.0),
Some(EriksonStage::AutonomyVsShame)
);
assert_eq!(
EriksonStage::from_age(4.0),
Some(EriksonStage::InitiativeVsGuilt)
);
assert_eq!(
EriksonStage::from_age(8.0),
Some(EriksonStage::IndustryVsInferiority)
);
assert_eq!(
EriksonStage::from_age(15.0),
Some(EriksonStage::IdentityVsRoleConfusion)
);
assert_eq!(
EriksonStage::from_age(25.0),
Some(EriksonStage::IntimacyVsIsolation)
);
assert_eq!(
EriksonStage::from_age(50.0),
Some(EriksonStage::GenerativityVsStagnation)
);
assert_eq!(
EriksonStage::from_age(70.0),
Some(EriksonStage::IntegrityVsDespair)
);
}
#[test]
fn test_erikson_invalid_age() {
assert_eq!(EriksonStage::from_age(-1.0), None);
assert_eq!(EriksonStage::from_age(f64::NAN), None);
}
#[test]
fn test_erikson_age_ranges() {
let (min, max) = EriksonStage::TrustVsMistrust.typical_age_range();
assert!((min - 0.0).abs() < 1e-10);
assert!((max - 1.5).abs() < 1e-10);
let (min, max) = EriksonStage::IntegrityVsDespair.typical_age_range();
assert!((min - 65.0).abs() < 1e-10);
assert!((max - 100.0).abs() < 1e-10);
}
#[test]
fn test_piaget_age_ranges_all() {
let (_, max) = PiagetStage::Preoperational.typical_age_range();
assert!((max - 7.0).abs() < 1e-10);
let (min, _) = PiagetStage::FormalOperational.typical_age_range();
assert!((min - 11.0).abs() < 1e-10);
}
#[test]
fn test_piaget_serde_roundtrip() {
let stage = PiagetStage::ConcreteOperational;
let json = serde_json::to_string(&stage).unwrap();
let back: PiagetStage = serde_json::from_str(&json).unwrap();
assert_eq!(stage, back);
}
#[test]
fn test_erikson_serde_roundtrip() {
let stage = EriksonStage::IdentityVsRoleConfusion;
let json = serde_json::to_string(&stage).unwrap();
let back: EriksonStage = serde_json::from_str(&json).unwrap();
assert_eq!(stage, back);
}
}