use crate::fix_values::CheckSum;
use crate::tagvalue::DecodeError;
use crate::FixValue;
use std::convert::TryInto;
pub const MIN_FIX_MESSAGE_LEN_IN_BYTES: usize = 20;
pub const FIELD_CHECKSUM_LEN_IN_BYTES: usize = 7;
pub fn checksum_digits(message: &[u8]) -> [u8; 3] {
debug_assert!(message.len() >= MIN_FIX_MESSAGE_LEN_IN_BYTES);
message[message.len() - 4..message.len() - 1]
.try_into()
.unwrap()
}
pub fn verify_checksum(headerless_msg: &[u8]) -> Result<(), DecodeError> {
let msg_contents = &headerless_msg[..headerless_msg.len() - FIELD_CHECKSUM_LEN_IN_BYTES];
let nominal_checksum = CheckSum::deserialize_lossy(&checksum_digits(headerless_msg)[..])
.map_err(|_| DecodeError::CheckSum)?;
let actual_checksum = CheckSum::compute(msg_contents);
if nominal_checksum == actual_checksum {
Ok(())
} else {
Err(DecodeError::CheckSum)
}
}
pub fn verify_body_length(
data: &[u8],
start_of_body: usize,
nominal_body_length: usize,
) -> Result<(), DecodeError> {
let body_length = data
.len()
.wrapping_sub(FIELD_CHECKSUM_LEN_IN_BYTES)
.wrapping_sub(start_of_body);
let end_of_body = data.len() - FIELD_CHECKSUM_LEN_IN_BYTES;
if start_of_body > end_of_body || nominal_body_length != body_length {
Err(DecodeError::Invalid)
} else {
debug_assert!(body_length < data.len());
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn correct_retrieval_of_checksum_digits() {
assert_eq!(
&checksum_digits(b"8=FIX.4.4|9=1337|35=?|...|10=000|"),
b"000"
);
assert_eq!(
&checksum_digits(b"8=FIX.4.4|9=1337|35=?|...|10=ABC|"),
b"ABC"
);
}
}