use crate::enums::{AttributionType, LifeDomain};
use crate::types::Timestamp;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AntecedentType {
Ability,
Benevolence,
Integrity,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AntecedentDirection {
Positive,
Negative,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TrustAntecedent {
timestamp: Timestamp,
antecedent_type: AntecedentType,
direction: AntecedentDirection,
magnitude: f32,
context: String,
life_domain: Option<LifeDomain>,
attribution: Option<AttributionType>,
}
impl TrustAntecedent {
#[must_use]
pub fn new(
timestamp: Timestamp,
antecedent_type: AntecedentType,
direction: AntecedentDirection,
magnitude: f32,
context: impl Into<String>,
) -> Self {
TrustAntecedent {
timestamp,
antecedent_type,
direction,
magnitude: magnitude.clamp(0.0, 1.0),
context: context.into(),
life_domain: None,
attribution: None,
}
}
#[must_use]
pub fn with_life_domain(mut self, domain: LifeDomain) -> Self {
self.life_domain = Some(domain);
self
}
#[must_use]
pub fn with_attribution(mut self, attribution: AttributionType) -> Self {
self.attribution = Some(attribution);
self
}
#[must_use]
pub fn timestamp(&self) -> Timestamp {
self.timestamp
}
#[must_use]
pub fn antecedent_type(&self) -> AntecedentType {
self.antecedent_type
}
#[must_use]
pub fn direction(&self) -> AntecedentDirection {
self.direction
}
#[must_use]
pub fn magnitude(&self) -> f32 {
self.magnitude
}
#[must_use]
pub fn context(&self) -> &str {
&self.context
}
#[must_use]
pub fn life_domain(&self) -> Option<LifeDomain> {
self.life_domain
}
#[must_use]
pub fn attribution(&self) -> Option<AttributionType> {
self.attribution
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trust_antecedent_accessors_return_fields() {
let ts = Timestamp::from_ymd_hms(2024, 1, 1, 0, 0, 0);
let antecedent = TrustAntecedent::new(
ts,
AntecedentType::Integrity,
AntecedentDirection::Negative,
0.6,
"betrayal",
);
assert_eq!(antecedent.timestamp(), ts);
assert_eq!(antecedent.antecedent_type(), AntecedentType::Integrity);
assert_eq!(antecedent.direction(), AntecedentDirection::Negative);
assert!((antecedent.magnitude() - 0.6).abs() < f32::EPSILON);
assert_eq!(antecedent.context(), "betrayal");
assert!(antecedent.life_domain().is_none());
assert!(antecedent.attribution().is_none());
}
#[test]
fn trust_antecedent_clamps_magnitude() {
let ts = Timestamp::from_ymd_hms(2024, 1, 1, 0, 0, 0);
let antecedent = TrustAntecedent::new(
ts,
AntecedentType::Ability,
AntecedentDirection::Positive,
1.5,
"achievement",
);
assert!((antecedent.magnitude() - 1.0).abs() < f32::EPSILON);
}
#[test]
fn with_life_domain_sets_domain_for_ability() {
let ts = Timestamp::from_ymd_hms(2024, 1, 1, 0, 0, 0);
let antecedent = TrustAntecedent::new(
ts,
AntecedentType::Ability,
AntecedentDirection::Positive,
0.5,
"good_advice",
)
.with_life_domain(LifeDomain::Health);
assert_eq!(antecedent.life_domain(), Some(LifeDomain::Health));
}
#[test]
fn with_attribution_sets_attribution() {
let ts = Timestamp::from_ymd_hms(2024, 1, 1, 0, 0, 0);
let antecedent = TrustAntecedent::new(
ts,
AntecedentType::Integrity,
AntecedentDirection::Negative,
0.4,
"misled",
)
.with_attribution(AttributionType::Integrity);
assert_eq!(antecedent.attribution(), Some(AttributionType::Integrity));
}
#[test]
fn life_domain_works_on_non_ability_antecedents() {
let ts = Timestamp::from_ymd_hms(2024, 1, 1, 0, 0, 0);
let antecedent = TrustAntecedent::new(
ts,
AntecedentType::Benevolence,
AntecedentDirection::Positive,
0.5,
"support",
)
.with_life_domain(LifeDomain::Work);
assert_eq!(antecedent.life_domain(), Some(LifeDomain::Work));
}
}