use crate::cabalistic::expression_number;
use crate::error::NumerologyError;
use crate::pyramid::{life_triangle, ArcaneCode, LifeTriangle};
use crate::reduction::CalculatedNumber;
pub const DEFAULT_LIFE_SPAN: u32 = 90;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SignatureAnalysis {
pub expression: CalculatedNumber,
pub triangle: LifeTriangle,
pub dominant: Option<ArcaneCode>,
pub regent: u8,
}
impl SignatureAnalysis {
#[must_use]
pub fn arcane_duration_years(&self, life_span: u32) -> f64 {
if self.triangle.arcana.is_empty() {
return 0.0;
}
f64::from(life_span) / self.triangle.arcana.len() as f64
}
}
pub fn analyze_signature(signature: &str, age: u32, life_span: u32) -> Result<SignatureAnalysis, NumerologyError> {
let expression = expression_number(signature)?;
let triangle = life_triangle(signature)?;
let dominant = triangle.dominant(age, life_span);
let regent = triangle.regent;
Ok(SignatureAnalysis {
expression,
triangle,
dominant,
regent,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn analyzes_signature_like_a_name() {
let analysis = analyze_signature("Barbara Liskov", 55, DEFAULT_LIFE_SPAN).unwrap();
assert_eq!(analysis.expression.value, 6);
assert_eq!(analysis.regent, 7);
assert_eq!(analysis.dominant.map(ArcaneCode::code), Some(31));
assert!((analysis.arcane_duration_years(DEFAULT_LIFE_SPAN) - 7.5).abs() < 1e-9);
}
#[test]
fn short_signature_errors() {
assert!(analyze_signature("A", 30, DEFAULT_LIFE_SPAN).is_err());
}
}