use super::swift_utils::parse_amount;
use crate::errors::ParseError;
use crate::traits::SwiftField;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
pub struct Field37H {
pub rate_indicator: char,
pub is_negative: Option<bool>,
pub rate: f64,
}
impl SwiftField for Field37H {
fn parse(input: &str) -> crate::Result<Self>
where
Self: Sized,
{
let mut remaining = input;
if remaining.is_empty() {
return Err(ParseError::InvalidFormat {
message: "Field37H requires rate indicator".to_string(),
});
}
let rate_indicator = remaining.chars().next().unwrap();
if rate_indicator != 'C' && rate_indicator != 'D' {
return Err(ParseError::InvalidFormat {
message: "Field37H rate indicator must be 'C' or 'D'".to_string(),
});
}
remaining = &remaining[1..];
let is_negative = if remaining.starts_with('N') {
remaining = &remaining[1..];
Some(true)
} else {
None
};
if remaining.is_empty() {
return Err(ParseError::InvalidFormat {
message: "Field37H requires rate value".to_string(),
});
}
let rate = if is_negative.is_some() {
-parse_amount(remaining)?
} else {
parse_amount(remaining)?
};
Ok(Field37H {
rate_indicator,
is_negative,
rate,
})
}
fn to_swift_string(&self) -> String {
let negative_indicator = if self.is_negative.is_some() { "N" } else { "" };
let rate_str = format!("{:.4}", self.rate.abs()).replace('.', ",");
format!(
":37H:{}{}{}",
self.rate_indicator, negative_indicator, rate_str
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_field37h_parse() {
let field = Field37H::parse("C2,5000").unwrap();
assert_eq!(field.rate_indicator, 'C');
assert_eq!(field.is_negative, None);
assert_eq!(field.rate, 2.5);
let field = Field37H::parse("D3,7500").unwrap();
assert_eq!(field.rate_indicator, 'D');
assert_eq!(field.is_negative, None);
assert_eq!(field.rate, 3.75);
let field = Field37H::parse("CN0,2500").unwrap();
assert_eq!(field.rate_indicator, 'C');
assert_eq!(field.is_negative, Some(true));
assert_eq!(field.rate, -0.25);
}
#[test]
fn test_field37h_to_swift_string() {
let field = Field37H {
rate_indicator: 'C',
is_negative: None,
rate: 2.5,
};
assert_eq!(field.to_swift_string(), ":37H:C2,5000");
let field = Field37H {
rate_indicator: 'D',
is_negative: None,
rate: 3.75,
};
assert_eq!(field.to_swift_string(), ":37H:D3,7500");
let field = Field37H {
rate_indicator: 'C',
is_negative: Some(true),
rate: -0.25,
};
assert_eq!(field.to_swift_string(), ":37H:CN0,2500");
}
#[test]
fn test_field37h_parse_invalid() {
assert!(Field37H::parse("X2,5000").is_err());
assert!(Field37H::parse("C").is_err());
assert!(Field37H::parse("Cabc").is_err());
assert!(Field37H::parse("").is_err());
}
}