use crate::state::{
AttachmentStyle, Disposition, EntityModelConfig, Hexaco, MentalHealth, Mood, Needs,
PersonCharacteristics, SocialCognition, StateValue,
};
use crate::types::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IndividualState {
hexaco: Hexaco,
mood: Mood,
recent_moral_violation_flag: StateValue,
needs: Needs,
social_cognition: SocialCognition,
attachment: AttachmentStyle,
mental_health: MentalHealth,
disposition: Disposition,
person_characteristics: PersonCharacteristics,
config: EntityModelConfig,
}
impl IndividualState {
#[must_use]
pub fn new() -> Self {
IndividualState {
hexaco: Hexaco::default(),
mood: Mood::default(),
recent_moral_violation_flag: StateValue::new(0.0)
.with_decay_half_life(Duration::hours(24)),
needs: Needs::default(),
social_cognition: SocialCognition::default(),
attachment: AttachmentStyle::default(),
mental_health: MentalHealth::default(),
disposition: Disposition::default(),
person_characteristics: PersonCharacteristics::default(),
config: EntityModelConfig::default(),
}
}
#[must_use]
pub fn with_hexaco(mut self, hexaco: Hexaco) -> Self {
self.hexaco = hexaco;
self
}
#[must_use]
pub fn with_mood(mut self, mood: Mood) -> Self {
self.mood = mood;
self
}
#[must_use]
pub fn with_needs(mut self, needs: Needs) -> Self {
self.needs = needs;
self
}
#[must_use]
pub fn with_social_cognition(mut self, social_cognition: SocialCognition) -> Self {
self.social_cognition = social_cognition;
self
}
#[must_use]
pub fn with_attachment(mut self, attachment: AttachmentStyle) -> Self {
self.attachment = attachment;
self
}
#[must_use]
pub fn with_mental_health(mut self, mental_health: MentalHealth) -> Self {
self.mental_health = mental_health;
self
}
#[must_use]
pub fn with_disposition(mut self, disposition: Disposition) -> Self {
self.disposition = disposition;
self
}
#[must_use]
pub fn with_person_characteristics(mut self, pc: PersonCharacteristics) -> Self {
self.person_characteristics = pc;
self
}
#[must_use]
pub fn with_config(mut self, config: EntityModelConfig) -> Self {
self.config = config;
self
}
#[must_use]
pub fn hexaco(&self) -> &Hexaco {
&self.hexaco
}
#[must_use]
pub fn mood(&self) -> &Mood {
&self.mood
}
#[must_use]
pub fn recent_moral_violation_flag(&self) -> f32 {
self.recent_moral_violation_flag.effective()
}
#[must_use]
pub fn needs(&self) -> &Needs {
&self.needs
}
#[must_use]
pub fn social_cognition(&self) -> &SocialCognition {
&self.social_cognition
}
#[must_use]
pub fn attachment(&self) -> &AttachmentStyle {
&self.attachment
}
#[must_use]
pub fn mental_health(&self) -> &MentalHealth {
&self.mental_health
}
#[must_use]
pub fn disposition(&self) -> &Disposition {
&self.disposition
}
#[must_use]
pub fn person_characteristics(&self) -> &PersonCharacteristics {
&self.person_characteristics
}
#[must_use]
pub fn config(&self) -> &EntityModelConfig {
&self.config
}
pub fn hexaco_mut(&mut self) -> &mut Hexaco {
&mut self.hexaco
}
pub fn mood_mut(&mut self) -> &mut Mood {
&mut self.mood
}
pub fn set_recent_moral_violation_flag(&mut self, value: f32) {
self.recent_moral_violation_flag
.set_delta(value.clamp(0.0, 1.0));
}
pub fn needs_mut(&mut self) -> &mut Needs {
&mut self.needs
}
pub fn social_cognition_mut(&mut self) -> &mut SocialCognition {
&mut self.social_cognition
}
pub fn attachment_mut(&mut self) -> &mut AttachmentStyle {
&mut self.attachment
}
pub fn mental_health_mut(&mut self) -> &mut MentalHealth {
&mut self.mental_health
}
pub fn disposition_mut(&mut self) -> &mut Disposition {
&mut self.disposition
}
pub fn person_characteristics_mut(&mut self) -> &mut PersonCharacteristics {
&mut self.person_characteristics
}
pub fn config_mut(&mut self) -> &mut EntityModelConfig {
&mut self.config
}
pub fn apply_decay(&mut self, elapsed: Duration) {
self.mood.apply_decay(elapsed);
self.recent_moral_violation_flag.apply_decay(elapsed);
self.needs.apply_decay(elapsed);
self.social_cognition.apply_decay(elapsed);
self.attachment.apply_decay(elapsed);
self.mental_health.apply_decay(elapsed);
self.disposition.apply_decay(elapsed);
self.person_characteristics.apply_decay(elapsed);
}
pub fn reset_all_deltas(&mut self) {
self.mood.reset_deltas();
self.recent_moral_violation_flag.reset_delta();
self.needs.reset_deltas();
self.social_cognition.reset_deltas();
self.attachment.reset_deltas();
self.mental_health.reset_deltas();
self.disposition.reset_deltas();
self.person_characteristics.reset_deltas();
}
#[must_use]
pub fn compute_thwarted_belongingness(&self) -> f32 {
self.mental_health
.compute_thwarted_belongingness(&self.social_cognition)
}
#[must_use]
pub fn compute_perceived_burdensomeness(&self) -> f32 {
self.mental_health
.compute_perceived_burdensomeness(&self.social_cognition)
}
#[must_use]
pub fn compute_suicidal_desire(&self) -> f32 {
self.mental_health
.compute_suicidal_desire(&self.social_cognition)
}
#[must_use]
pub fn compute_attempt_risk(&self) -> f32 {
self.mental_health
.compute_attempt_risk(&self.social_cognition)
}
#[must_use]
pub fn its_convergence(&self) -> crate::state::ITSConvergence {
self.mental_health.its_convergence(&self.social_cognition)
}
#[must_use]
pub fn its_risk_level(&self) -> crate::state::ITSRiskLevel {
self.mental_health.its_risk_level(&self.social_cognition)
}
}
impl Default for IndividualState {
fn default() -> Self {
IndividualState::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::enums::PersonalityProfile;
#[test]
fn individual_state_composes_all_components() {
let state = IndividualState::new();
let _ = state.hexaco();
let _ = state.mood();
let _ = state.recent_moral_violation_flag();
let _ = state.needs();
let _ = state.mental_health();
let _ = state.disposition();
let _ = state.person_characteristics();
let _ = state.attachment();
let _ = state.config();
}
#[test]
fn new_creates_default_components() {
let state = IndividualState::new();
assert!(state.mood().valence_effective().abs() < 0.1);
assert!(state.recent_moral_violation_flag().abs() < f32::EPSILON);
assert!(state.social_cognition().loneliness_effective() < 0.5);
assert!(state.mental_health().depression_effective() < 0.3);
assert!(state.disposition().empathy_effective() > 0.5);
assert!(state.attachment().anxiety_effective() < 0.5);
assert!(state.attachment().avoidance_effective() < 0.5);
}
#[test]
fn builder_methods_set_components() {
let hexaco = Hexaco::from_profile(PersonalityProfile::Leader);
let mood = Mood::new().with_valence_base(0.5);
let state = IndividualState::new()
.with_hexaco(hexaco.clone())
.with_mood(mood.clone());
assert_eq!(state.hexaco(), &hexaco);
assert_eq!(state.mood(), &mood);
}
#[test]
fn builder_sets_social_cognition() {
let social = SocialCognition::default();
let state = IndividualState::new().with_social_cognition(social.clone());
assert_eq!(state.social_cognition(), &social);
}
#[test]
fn mutable_references_work() {
let mut state = IndividualState::new();
state.mood_mut().add_valence_delta(0.3);
assert!((state.mood().valence_delta() - 0.3).abs() < f32::EPSILON);
state.needs_mut().add_stress_delta(0.2);
assert!((state.needs().stress().delta() - 0.2).abs() < f32::EPSILON);
}
#[test]
fn apply_decay_affects_all_decaying_components() {
let mut state = IndividualState::new();
state.mood_mut().add_valence_delta(0.8);
state.needs_mut().add_stress_delta(0.8);
state.disposition_mut().add_grievance_delta(0.8);
state.attachment_mut().add_anxiety_delta(0.8);
state.apply_decay(Duration::weeks(1));
assert!(state.mood().valence_delta() < 0.1);
assert!(state.needs().stress().delta() < 0.1);
assert!(state.disposition().grievance().delta() < 0.5);
assert!(state.attachment().anxiety().delta() < 0.8);
}
#[test]
fn apply_decay_does_not_affect_acquired_capability() {
let mut state = IndividualState::new();
state.mental_health_mut().add_acquired_capability_delta(0.5);
state.apply_decay(Duration::years(10));
assert!((state.mental_health().acquired_capability().delta() - 0.5).abs() < f32::EPSILON);
}
#[test]
fn recent_moral_violation_flag_decays_over_a_day() {
let mut state = IndividualState::new();
state.set_recent_moral_violation_flag(1.0);
state.apply_decay(Duration::hours(24));
let flag = state.recent_moral_violation_flag();
assert!((flag - 0.5).abs() < 0.01);
}
#[test]
fn reset_all_deltas_clears_components() {
let mut state = IndividualState::new();
state.mood_mut().add_valence_delta(0.5);
state.social_cognition_mut().add_loneliness_delta(0.3);
state.disposition_mut().add_aggression_delta(0.2);
state.attachment_mut().add_avoidance_delta(0.2);
state.reset_all_deltas();
assert!(state.mood().valence_delta().abs() < f32::EPSILON);
assert!(state.social_cognition().loneliness().delta().abs() < f32::EPSILON);
assert!(state.disposition().aggression().delta().abs() < f32::EPSILON);
assert!(state.attachment().avoidance().delta().abs() < f32::EPSILON);
}
#[test]
fn its_convenience_methods_work() {
let mut state = IndividualState::new();
state.social_cognition_mut().loneliness_mut().set_base(0.9);
state
.social_cognition_mut()
.perceived_reciprocal_caring_mut()
.set_base(0.1);
state
.social_cognition_mut()
.perceived_liability_mut()
.set_base(0.9);
state.social_cognition_mut().self_hate_mut().set_base(0.9);
state
.mental_health_mut()
.interpersonal_hopelessness_mut()
.set_base(0.7);
state
.mental_health_mut()
.acquired_capability_mut()
.set_base(0.8);
let tb = state.compute_thwarted_belongingness();
let pb = state.compute_perceived_burdensomeness();
assert!(tb > 0.6);
assert!(pb > 0.7);
let desire = state.compute_suicidal_desire();
let risk = state.compute_attempt_risk();
assert!(desire > 0.0);
assert!(risk > 0.0);
}
#[test]
fn its_convergence_and_risk_level_use_current_state() {
let mut state = IndividualState::new();
state.social_cognition_mut().loneliness_mut().set_base(0.9);
state
.social_cognition_mut()
.perceived_reciprocal_caring_mut()
.set_base(0.1);
state
.social_cognition_mut()
.perceived_liability_mut()
.set_base(0.9);
state.social_cognition_mut().self_hate_mut().set_base(0.9);
state
.mental_health_mut()
.interpersonal_hopelessness_mut()
.set_base(0.7);
state
.mental_health_mut()
.acquired_capability_mut()
.set_base(0.8);
let convergence = state.its_convergence();
let risk_level = state.its_risk_level();
assert!(convergence.all_factors_present);
assert_eq!(risk_level, crate::state::ITSRiskLevel::HighestRisk);
}
#[test]
fn default_is_new() {
let state = IndividualState::default();
assert!(state.social_cognition().loneliness_effective() < 0.5);
}
#[test]
fn clone_and_equality() {
let state1 = IndividualState::new();
let state2 = state1.clone();
assert_eq!(state1, state2);
}
#[test]
fn debug_format() {
let state = IndividualState::new();
let debug = format!("{:?}", state);
assert!(debug.contains("IndividualState"));
}
#[test]
fn config_builder_and_accessor() {
let config = EntityModelConfig::animal_simple();
let state = IndividualState::new().with_config(config.clone());
assert_eq!(state.config(), &config);
}
#[test]
fn config_mutable() {
let mut state = IndividualState::new();
state.config_mut().set_time_scale(2.0);
assert!((state.config().time_scale() - 2.0).abs() < f32::EPSILON);
}
#[test]
fn all_builder_methods() {
let hexaco = Hexaco::default();
let mood = Mood::default();
let needs = Needs::default();
let mental_health = MentalHealth::default();
let disposition = Disposition::default();
let pc = PersonCharacteristics::default();
let attachment = AttachmentStyle::default();
let config = EntityModelConfig::default();
let state = IndividualState::new()
.with_hexaco(hexaco.clone())
.with_mood(mood.clone())
.with_needs(needs.clone())
.with_mental_health(mental_health.clone())
.with_disposition(disposition.clone())
.with_person_characteristics(pc.clone())
.with_attachment(attachment.clone())
.with_config(config.clone());
assert_eq!(state.hexaco(), &hexaco);
assert_eq!(state.mood(), &mood);
assert_eq!(state.needs(), &needs);
assert_eq!(state.mental_health(), &mental_health);
assert_eq!(state.disposition(), &disposition);
assert_eq!(state.person_characteristics(), &pc);
assert_eq!(state.attachment(), &attachment);
assert_eq!(state.config(), &config);
}
#[test]
fn all_mutable_refs() {
let mut state = IndividualState::new();
state.hexaco_mut().set_openness(0.5);
state.disposition_mut().add_empathy_delta(0.1);
state
.person_characteristics_mut()
.social_capital_mut()
.add_delta(0.2);
state.attachment_mut().add_anxiety_delta(0.1);
assert!((state.hexaco().openness() - 0.5).abs() < f32::EPSILON);
assert!((state.disposition().empathy().delta() - 0.1).abs() < f32::EPSILON);
assert!(
(state.person_characteristics().social_capital().delta() - 0.2).abs() < f32::EPSILON
);
assert!((state.attachment().anxiety().delta() - 0.1).abs() < f32::EPSILON);
}
#[test]
fn recent_moral_violation_flag_clamps_bounds() {
let mut state = IndividualState::new();
state.set_recent_moral_violation_flag(1.5);
assert!((state.recent_moral_violation_flag() - 1.0).abs() < f32::EPSILON);
state.set_recent_moral_violation_flag(-0.5);
assert!((state.recent_moral_violation_flag() - 0.0).abs() < f32::EPSILON);
}
}