use crate::bytes_helper::{u16_from_le_bytes, u32_from_le_bytes};
#[derive(Debug, Clone, PartialEq, serde::Serialize)]
pub struct DateTime {
pub year: u16,
pub month: u16,
pub day: u16,
pub hour: u16,
pub minute: u16,
}
#[rustfmt::skip]
impl Default for DateTime {
fn default() -> Self { Self { year: 0, month: 0, day: 0, hour: 15, minute: 0, } }
}
impl DateTime {
pub fn into_string(self, category: u16) -> String {
match category {
0..=3 | 7 | 8 => format!(
"{:04}-{:02}-{:02} {:02}:{:02}",
self.year, self.month, self.day, self.hour, self.minute
),
_ => format!("{:04}-{:02}-{:02}", self.year, self.month, self.day),
}
}
pub fn to_u32(self) -> u32 {
self.day as u32 + self.month as u32 * 100 + self.year as u32 * 10000
}
}
pub fn datetime(arr: &[u8], category: u16) -> DateTime {
let mut datetime = DateTime::default();
if category < 4 || category == 7 || category == 8 {
let day = u16_from_le_bytes(arr, 0);
let minutes = u16_from_le_bytes(arr, 2);
datetime.year = (day >> 11) + 2004;
datetime.month = day % 2048 / 100;
datetime.day = day % 2048 % 100;
datetime.hour = minutes / 60;
datetime.minute = minutes % 60;
} else {
let day = u32_from_le_bytes(arr, 0);
datetime.year = (day / 10000) as u16;
datetime.month = (day % 10000 / 100) as u16;
datetime.day = (day % 100) as u16;
}
datetime
}
pub fn price(arr: &[u8], pos: &mut usize) -> i32 {
let mut shl = 6;
let mut bit = arr[*pos] as i32;
let mut res = bit & 0x3f;
let sign = (bit & 0x40) == 0;
while (bit & 0x80) != 0 {
*pos += 1;
bit = arr[*pos] as i32;
res += (bit & 0x7f) << shl;
shl += 7;
}
*pos += 1;
if sign {
res
} else {
-res
}
}
pub fn vol_amount(ivol: i32) -> f64 {
let logpoint = ivol >> 24;
let hleax = (ivol >> 16) & 0xff;
let lheax = (ivol >> 8) & 0xff;
let lleax = ivol & 0xff;
let dw_ecx = logpoint * 2 - 0x7f;
let dw_edx = logpoint * 2 - 0x86;
let dw_esi = logpoint * 2 - 0x8e;
let dw_eax = logpoint * 2 - 0x96;
let dbl_xmm6 = if dw_ecx < 0 {
1.0 / 2.0f64.powi(-dw_ecx)
} else {
2.0f64.powi(dw_ecx)
};
let dbl_xmm4 = if hleax > 0x80 {
2.0f64.powi(dw_edx) * 128.0 + (hleax & 0x7f) as f64 * 2.0f64.powi(dw_edx + 1)
} else if dw_edx >= 0 {
2.0f64.powi(dw_edx) * hleax as f64
} else {
(1.0 / 2.0f64.powi(dw_edx)) * hleax as f64
};
let (dbl_xmm3, dbl_xmm1) = if (hleax & 0x80) != 0 {
(
2.0f64.powi(dw_esi + 1) * lheax as f64,
2.0f64.powi(dw_eax + 1) * lleax as f64,
)
} else {
(
2.0f64.powi(dw_esi) * lheax as f64,
2.0f64.powi(dw_eax) * lleax as f64,
)
};
dbl_xmm6 + dbl_xmm4 + dbl_xmm3 + dbl_xmm1
}
#[test]
fn check_datetime_price_vol_amount() {
#[rustfmt::skip]
assert_eq!(datetime(&[235, 100, 52, 1], 9),
DateTime { year: 2021, month: 9, day: 23, hour: 15, minute: 0, });
assert_eq!(price(&[180, 154, 2], &mut 0), 18100);
assert_eq!(price(&[228, 6], &mut 0), -420);
assert_eq!(price(&[156, 3], &mut 0), 220);
assert_eq!(price(&[194, 7], &mut 0), -450);
assert_eq!(vol_amount(1235775464), 1379837.0);
assert_eq!(vol_amount(1326643033), 2465683712.0);
}