use serde::Serialize;
use zerocopy::{BigEndian, Immutable, IntoBytes, Unaligned, U16, U32};
use super::CurveData;
#[derive(Serialize)]
pub struct CurveType {
#[serde(skip_serializing_if = "Option::is_none")]
points: Option<Vec<u16>>,
#[serde(skip_serializing_if = "Option::is_none")]
gamma: Option<f64>,
}
impl From<&CurveData> for CurveType {
fn from(curve: &CurveData) -> Self {
let Some(payload) = curve.0.get(12..) else {
return CurveType {
points: None,
gamma: None,
};
};
debug_assert_eq!(
payload.len() % 2,
0,
"curveType: payload length {} is not a multiple of 2 (malformed tag)",
payload.len()
);
let data: Vec<u16> = {
payload
.chunks_exact(2)
.map(|chunk| u16::from_be_bytes(chunk.try_into().unwrap()))
.collect()
};
if data.len() == 1 {
let value = data[0] as f64 / 256.0;
CurveType {
points: None,
gamma: Some(crate::round_to_precision(value, 4)),
}
} else {
CurveType {
points: Some(data),
gamma: None,
}
}
}
}
#[derive(IntoBytes, Unaligned, Immutable)]
#[repr(C, packed)]
struct WriteLayout<const N: usize> {
signature: [u8; 4],
reserved: [u8; 4],
count: U32<BigEndian>,
data: [U16<BigEndian>; N],
}
impl<const N: usize> WriteLayout<N> {
pub fn new(data: [u16; N]) -> Self {
let data: [U16<BigEndian>; N] = data.map(U16::<BigEndian>::new);
Self {
signature: super::DataSignature::CurveData.into(),
reserved: [0; 4],
count: U32::<BigEndian>::new(data.len() as u32),
data,
}
}
}
impl CurveData {
pub fn set_data<const N: usize>(&mut self, data: [u16; N]) {
let data_bytes = WriteLayout::new(data);
self.0 = data_bytes.as_bytes().to_vec();
}
pub fn set_gamma(&mut self, gamma: f64) {
let value = (gamma * 256.0).round() as u16;
self.set_data([value]);
}
}