use std::cell::Cell;
use crate::patterns::observable::{Observable, Observer};
use crate::shared::SharedMut;
pub struct Settings<D> {
evaluation_date: Cell<Option<D>>,
eval_date_observable: Observable,
include_reference_date_events: Cell<bool>,
include_todays_cash_flows: Cell<Option<bool>>,
enforces_todays_historic_fixings: Cell<bool>,
}
impl<D> Default for Settings<D> {
fn default() -> Self {
Settings {
evaluation_date: Cell::new(None),
eval_date_observable: Observable::new(),
include_reference_date_events: Cell::new(false),
include_todays_cash_flows: Cell::new(None),
enforces_todays_historic_fixings: Cell::new(false),
}
}
}
impl<D> Settings<D> {
pub fn new() -> Self {
Settings::default()
}
pub fn evaluation_date(&self) -> Option<D>
where
D: Copy,
{
self.evaluation_date.get()
}
pub fn set_evaluation_date(&self, date: D)
where
D: Copy + PartialEq,
{
if self.evaluation_date.get() != Some(date) {
self.evaluation_date.set(Some(date));
self.eval_date_observable.notify_observers();
}
}
pub fn reset_evaluation_date(&self) {
if self.evaluation_date.replace(None).is_some() {
self.eval_date_observable.notify_observers();
}
}
pub fn register_eval_date_observer(&self, observer: &SharedMut<dyn Observer>) -> bool {
self.eval_date_observable.register_observer(observer)
}
pub fn include_reference_date_events(&self) -> bool {
self.include_reference_date_events.get()
}
pub fn set_include_reference_date_events(&self, value: bool) {
self.include_reference_date_events.set(value);
}
pub fn include_todays_cash_flows(&self) -> Option<bool> {
self.include_todays_cash_flows.get()
}
pub fn set_include_todays_cash_flows(&self, value: Option<bool>) {
self.include_todays_cash_flows.set(value);
}
pub fn enforces_todays_historic_fixings(&self) -> bool {
self.enforces_todays_historic_fixings.get()
}
pub fn set_enforces_todays_historic_fixings(&self, value: bool) {
self.enforces_todays_historic_fixings.set(value);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::shared::{Shared, SharedMut, shared, shared_mut};
#[derive(Default)]
struct Flag {
up: bool,
}
impl Observer for Flag {
fn update(&mut self) {
self.up = true;
}
}
#[test]
fn notifies_only_on_actual_date_change() {
let settings: Settings<i64> = Settings::new();
let d1 = 44238_i64; let d2 = 44239_i64;
settings.set_evaluation_date(d1);
let flag = shared_mut(Flag::default());
settings.register_eval_date_observer(&(flag.clone() as SharedMut<dyn Observer>));
settings.set_evaluation_date(d1);
assert!(!flag.borrow().up);
settings.set_evaluation_date(d2);
assert!(flag.borrow().up);
assert_eq!(settings.evaluation_date(), Some(d2));
}
#[test]
fn reset_returns_to_floating_and_notifies_once() {
let settings: Settings<i64> = Settings::new();
settings.set_evaluation_date(44238_i64);
let flag = shared_mut(Flag::default());
settings.register_eval_date_observer(&(flag.clone() as SharedMut<dyn Observer>));
settings.reset_evaluation_date();
assert!(flag.borrow().up);
assert_eq!(settings.evaluation_date(), None);
flag.borrow_mut().up = false;
settings.reset_evaluation_date();
assert!(!flag.borrow().up);
}
#[test]
fn flags_round_trip() {
let settings: Settings<i64> = Settings::new();
assert!(!settings.include_reference_date_events());
assert_eq!(settings.include_todays_cash_flows(), None);
assert!(!settings.enforces_todays_historic_fixings());
settings.set_include_reference_date_events(true);
settings.set_include_todays_cash_flows(Some(true));
settings.set_enforces_todays_historic_fixings(true);
assert!(settings.include_reference_date_events());
assert_eq!(settings.include_todays_cash_flows(), Some(true));
assert!(settings.enforces_todays_historic_fixings());
}
struct Reader {
settings: Shared<Settings<i64>>,
seen: Option<i64>,
}
impl Observer for Reader {
fn update(&mut self) {
self.seen = self.settings.evaluation_date();
}
}
#[test]
fn observer_may_read_the_evaluation_date_during_notification() {
let settings = shared(Settings::<i64>::new());
let reader = shared_mut(Reader {
settings: Shared::clone(&settings),
seen: None,
});
settings.register_eval_date_observer(&(reader.clone() as SharedMut<dyn Observer>));
settings.set_evaluation_date(44239_i64);
assert_eq!(reader.borrow().seen, Some(44239));
settings.reset_evaluation_date();
assert_eq!(reader.borrow().seen, None);
}
}