use std::fmt;
use std::str::FromStr;
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DayCount {
Act360,
Act365,
Bd252,
ActActISDA,
D30360Euro,
D30365,
}
impl fmt::Display for DayCount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DayCount::Act360 => write!(f, "Act360"),
DayCount::Act365 => write!(f, "Act365"),
DayCount::Bd252 => write!(f, "Bd252"),
DayCount::ActActISDA => write!(f, "ActActISDA"),
DayCount::D30360Euro => write!(f, "D30360Euro"),
DayCount::D30365 => write!(f, "D30365"),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParseDayCountError;
impl fmt::Display for ParseDayCountError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unknown day count convention string")
}
}
impl FromStr for DayCount {
type Err = ParseDayCountError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Act360" => Ok(DayCount::Act360),
"Act365" => Ok(DayCount::Act365),
"Bd252" => Ok(DayCount::Bd252),
"ActActISDA" => Ok(DayCount::ActActISDA),
"D30360Euro" => Ok(DayCount::D30360Euro),
"D30365" => Ok(DayCount::D30365),
_ => Err(ParseDayCountError),
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AdjustRule {
Following,
ModFollowing,
Preceding,
ModPreceding,
Unadjusted,
HalfMonthModFollowing,
Nearest,
}
impl fmt::Display for AdjustRule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AdjustRule::Following => write!(f, "Following"),
AdjustRule::ModFollowing => write!(f, "ModFollowing"),
AdjustRule::Preceding => write!(f, "Preceding"),
AdjustRule::ModPreceding => write!(f, "ModPreceding"),
AdjustRule::Unadjusted => write!(f, "Unadjusted"),
AdjustRule::HalfMonthModFollowing => write!(f, "HalfMonthModFollowing"),
AdjustRule::Nearest => write!(f, "Nearest"),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParseAdjustRuleError;
impl fmt::Display for ParseAdjustRuleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unknown adjust rule string")
}
}
impl FromStr for AdjustRule {
type Err = ParseAdjustRuleError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Following" => Ok(AdjustRule::Following),
"ModFollowing" => Ok(AdjustRule::ModFollowing),
"Preceding" => Ok(AdjustRule::Preceding),
"ModPreceding" => Ok(AdjustRule::ModPreceding),
"Unadjusted" => Ok(AdjustRule::Unadjusted),
"HalfMonthModFollowing" => Ok(AdjustRule::HalfMonthModFollowing),
"Nearest" => Ok(AdjustRule::Nearest),
_ => Err(ParseAdjustRuleError),
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Frequency {
Zero,
Annual,
Semiannual,
EveryFourthMonth,
Quarterly,
Bimonthly,
Monthly,
EndOfMonth,
EveryFourthWeek,
Biweekly,
Weekly,
Daily,
}
impl fmt::Display for Frequency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Frequency::Zero => write!(f, "Zero"),
Frequency::Annual => write!(f, "Annual"),
Frequency::Semiannual => write!(f, "Semiannual"),
Frequency::EveryFourthMonth => write!(f, "EveryFourthMonth"),
Frequency::Quarterly => write!(f, "Quarterly"),
Frequency::Bimonthly => write!(f, "Bimonthly"),
Frequency::Monthly => write!(f, "Monthly"),
Frequency::EndOfMonth => write!(f, "EndOfMonth"),
Frequency::EveryFourthWeek => write!(f, "EveryFourthWeek"),
Frequency::Biweekly => write!(f, "Biweekly"),
Frequency::Weekly => write!(f, "Weekly"),
Frequency::Daily => write!(f, "Daily"),
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParseFrequencyError;
impl fmt::Display for ParseFrequencyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unknown frequency string")
}
}
impl FromStr for Frequency {
type Err = ParseFrequencyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Zero" => Ok(Frequency::Zero),
"Annual" => Ok(Frequency::Annual),
"Semiannual" => Ok(Frequency::Semiannual),
"EveryFourthMonth" => Ok(Frequency::EveryFourthMonth),
"Quarterly" => Ok(Frequency::Quarterly),
"Bimonthly" => Ok(Frequency::Bimonthly),
"Monthly" => Ok(Frequency::Monthly),
"EndOfMonth" => Ok(Frequency::EndOfMonth),
"EveryFourthWeek" => Ok(Frequency::EveryFourthWeek),
"Biweekly" => Ok(Frequency::Biweekly),
"Weekly" => Ok(Frequency::Weekly),
"Daily" => Ok(Frequency::Daily),
_ => Err(ParseFrequencyError),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_string_parse_test() {
let from_str = DayCount::from_str("ActActISDA");
assert_eq!(DayCount::ActActISDA, from_str.unwrap());
}
#[test]
#[should_panic]
fn incorrect_string_panic_test() {
let _from_str = DayCount::from_str("ActActIsda").unwrap();
}
#[test]
#[should_panic]
fn not_implemented_convention_panic_test() {
let _from_str = DayCount::from_str("D30360ISDA").unwrap();
}
#[test]
fn to_string_test() {
let conv = AdjustRule::HalfMonthModFollowing;
assert_eq!(conv.to_string(), "HalfMonthModFollowing");
}
#[test]
fn eq_trait_test() {
let conv = Frequency::EveryFourthMonth;
assert_eq!(conv, Frequency::EveryFourthMonth);
}
#[test]
fn bd252_roundtrip_test() {
let dc = DayCount::Bd252;
let parsed: DayCount = dc.to_string().parse().unwrap();
assert_eq!(dc, parsed);
}
#[test]
fn all_daycount_roundtrip_test() {
let variants = [
DayCount::Act360,
DayCount::Act365,
DayCount::Bd252,
DayCount::ActActISDA,
DayCount::D30360Euro,
DayCount::D30365,
];
for v in variants {
let parsed: DayCount = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn all_adjustrule_roundtrip_test() {
let variants = [
AdjustRule::Following,
AdjustRule::ModFollowing,
AdjustRule::Preceding,
AdjustRule::ModPreceding,
AdjustRule::Unadjusted,
AdjustRule::HalfMonthModFollowing,
AdjustRule::Nearest,
];
for v in variants {
let parsed: AdjustRule = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
#[test]
fn all_frequency_roundtrip_test() {
let variants = [
Frequency::Zero,
Frequency::Annual,
Frequency::Semiannual,
Frequency::EveryFourthMonth,
Frequency::Quarterly,
Frequency::Bimonthly,
Frequency::Monthly,
Frequency::EndOfMonth,
Frequency::EveryFourthWeek,
Frequency::Biweekly,
Frequency::Weekly,
Frequency::Daily,
];
for v in variants {
let parsed: Frequency = v.to_string().parse().unwrap();
assert_eq!(v, parsed);
}
}
}