use crate::date::BirthDate;
use crate::error::NumerologyError;
use crate::name::{distinct_present, missing_digits, most_frequent, NameAnalysis};
use crate::reduction::{debt_of, digit_sum, reduce, CalculatedNumber, KarmicDebt, CABALISTIC_MASTERS};
use crate::System;
fn analysis(name: &str) -> Result<NameAnalysis, NumerologyError> {
NameAnalysis::new(name, System::Cabalistic)
}
pub fn motivation_number(name: &str) -> Result<CalculatedNumber, NumerologyError> {
Ok(reduce(analysis(name)?.vowel_sum(), CABALISTIC_MASTERS))
}
pub fn impression_number(name: &str) -> Result<CalculatedNumber, NumerologyError> {
Ok(reduce(analysis(name)?.consonant_sum(), &[]))
}
pub fn expression_number(name: &str) -> Result<CalculatedNumber, NumerologyError> {
Ok(reduce(analysis(name)?.total_sum(), CABALISTIC_MASTERS))
}
pub fn hidden_talent_number(name: &str) -> Result<CalculatedNumber, NumerologyError> {
Ok(reduce(analysis(name)?.initials_sum(), CABALISTIC_MASTERS))
}
#[must_use]
pub fn destiny_number(birth: BirthDate) -> CalculatedNumber {
reduce(birth.digit_total(), CABALISTIC_MASTERS)
}
#[must_use]
pub fn birth_day_number(birth: BirthDate) -> CalculatedNumber {
reduce(birth.day, CABALISTIC_MASTERS)
}
#[must_use]
pub fn psychic_number(birth: BirthDate) -> CalculatedNumber {
reduce(birth.day, CABALISTIC_MASTERS)
}
pub fn mission_number(name: &str, birth: BirthDate) -> Result<CalculatedNumber, NumerologyError> {
let expression = expression_number(name)?;
let destiny = destiny_number(birth);
Ok(reduce(expression.value + destiny.value, CABALISTIC_MASTERS))
}
pub fn karmic_lessons(name: &str) -> Result<Vec<u8>, NumerologyError> {
Ok(missing_digits(&analysis(name)?.digit_frequency(), 9))
}
pub fn hidden_tendencies(name: &str) -> Result<Vec<u8>, NumerologyError> {
Ok(most_frequent(&analysis(name)?.digit_frequency()))
}
pub fn subconscious_response(name: &str) -> Result<u32, NumerologyError> {
Ok(distinct_present(&analysis(name)?.digit_frequency()))
}
pub fn karmic_debts(name: &str, birth: BirthDate) -> Result<Vec<KarmicDebt>, NumerologyError> {
let positions = [
("motivation", motivation_number(name)?),
("impression", impression_number(name)?),
("expression", expression_number(name)?),
("destiny", destiny_number(birth)),
("mission", mission_number(name, birth)?),
("birthday", birth_day_number(birth)),
];
let mut debts = Vec::new();
for (position, cn) in positions {
if let Some(debt) = debt_of(&cn) {
debts.push(KarmicDebt { position, debt });
}
}
Ok(debts)
}
#[must_use]
pub fn personal_year(birth: BirthDate, year: u32) -> CalculatedNumber {
reduce(
digit_sum(birth.day) + digit_sum(birth.month) + digit_sum(year),
CABALISTIC_MASTERS,
)
}
#[must_use]
pub fn personal_month(birth: BirthDate, year: u32, month: u32) -> CalculatedNumber {
reduce(personal_year(birth, year).value + digit_sum(month), CABALISTIC_MASTERS)
}
#[must_use]
pub fn personal_day(birth: BirthDate, year: u32, month: u32, day: u32) -> CalculatedNumber {
reduce(
personal_month(birth, year, month).value + digit_sum(day),
CABALISTIC_MASTERS,
)
}
#[cfg(test)]
mod tests {
use super::*;
const NAME: &str = "Barbara Liskov";
fn birth() -> BirthDate {
BirthDate::new(1939, 11, 7).unwrap()
}
#[test]
fn name_numbers() {
let motivation = motivation_number(NAME).unwrap();
assert_eq!(motivation.value, 11);
assert!(motivation.is_master);
assert_eq!(impression_number(NAME).unwrap().value, 4);
assert_eq!(expression_number(NAME).unwrap().value, 6);
assert_eq!(hidden_talent_number(NAME).unwrap().value, 5);
}
#[test]
fn date_numbers() {
assert_eq!(destiny_number(birth()).value, 4);
assert_eq!(birth_day_number(birth()).value, 7);
assert_eq!(psychic_number(birth()).value, 7);
assert_eq!(mission_number(NAME, birth()).unwrap().value, 1);
}
#[test]
fn impression_never_keeps_masters() {
let cn = impression_number(NAME).unwrap();
assert_eq!(cn.value, 4);
assert!(!cn.is_master);
}
#[test]
fn karmic_and_tendency() {
assert_eq!(karmic_lessons(NAME).unwrap(), vec![4, 5, 8, 9]);
assert_eq!(hidden_tendencies(NAME).unwrap(), vec![2]);
assert_eq!(subconscious_response(NAME).unwrap(), 5);
}
#[test]
fn digit_nine_is_always_a_karmic_lesson() {
assert!(karmic_lessons("Grace Hopper").unwrap().contains(&9));
}
#[test]
fn karmic_debt_detected_on_expression() {
let debts = karmic_debts("Grace Hopper", BirthDate::new(1906, 12, 9).unwrap()).unwrap();
assert_eq!(debts.len(), 1);
assert_eq!(debts[0].position, "expression");
assert_eq!(debts[0].debt, 13);
}
#[test]
fn clean_name_has_no_karmic_debts() {
assert!(karmic_debts(NAME, birth()).unwrap().is_empty());
}
#[test]
fn personal_cycles_preserve_masters() {
assert_eq!(personal_year(birth(), 2020).value, 4);
let katherine = BirthDate::new(1918, 8, 26).unwrap();
let day = personal_day(katherine, 2020, 3, 15);
assert_eq!(day.value, 11);
assert!(day.is_master);
}
#[test]
fn empty_name_errors() {
assert_eq!(expression_number("123"), Err(NumerologyError::EmptyName));
}
}