use crate::FieldId;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FixedPoint {
pub min_q: i64,
pub max_q: i64,
pub scale: u32,
}
impl FixedPoint {
#[must_use]
pub const fn new(min_q: i64, max_q: i64, scale: u32) -> Self {
Self {
min_q,
max_q,
scale,
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FieldCodec {
Bool,
UInt { bits: u8 },
SInt { bits: u8 },
VarUInt,
VarSInt,
FixedPoint(FixedPoint),
}
impl FieldCodec {
#[must_use]
pub const fn bool() -> Self {
Self::Bool
}
#[must_use]
pub const fn uint(bits: u8) -> Self {
Self::UInt { bits }
}
#[must_use]
pub const fn sint(bits: u8) -> Self {
Self::SInt { bits }
}
#[must_use]
pub const fn var_uint() -> Self {
Self::VarUInt
}
#[must_use]
pub const fn var_sint() -> Self {
Self::VarSInt
}
#[must_use]
pub const fn fixed_point(min_q: i64, max_q: i64, scale: u32) -> Self {
Self::FixedPoint(FixedPoint::new(min_q, max_q, scale))
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChangePolicy {
Always,
Threshold { threshold_q: u32 },
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FieldDef {
pub id: FieldId,
pub codec: FieldCodec,
pub change: ChangePolicy,
}
impl FieldDef {
#[must_use]
pub const fn new(id: FieldId, codec: FieldCodec) -> Self {
Self {
id,
codec,
change: ChangePolicy::Always,
}
}
#[must_use]
pub const fn with_threshold(id: FieldId, codec: FieldCodec, threshold_q: u32) -> Self {
Self {
id,
codec,
change: ChangePolicy::Threshold { threshold_q },
}
}
#[must_use]
pub const fn change(mut self, change: ChangePolicy) -> Self {
self.change = change;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::FieldId;
#[test]
fn fixed_point_construction() {
let fp = FixedPoint::new(-100, 200, 100);
assert_eq!(fp.min_q, -100);
assert_eq!(fp.max_q, 200);
assert_eq!(fp.scale, 100);
}
#[test]
fn field_codec_variants() {
assert!(matches!(FieldCodec::bool(), FieldCodec::Bool));
assert!(matches!(FieldCodec::uint(8), FieldCodec::UInt { bits: 8 }));
assert!(matches!(FieldCodec::sint(8), FieldCodec::SInt { bits: 8 }));
assert!(matches!(FieldCodec::var_uint(), FieldCodec::VarUInt));
assert!(matches!(FieldCodec::var_sint(), FieldCodec::VarSInt));
assert!(matches!(
FieldCodec::fixed_point(-10, 10, 100),
FieldCodec::FixedPoint(_)
));
}
#[test]
fn field_def_default_change_policy() {
let id = FieldId::new(1).unwrap();
let field = FieldDef::new(id, FieldCodec::bool());
assert_eq!(field.change, ChangePolicy::Always);
}
#[test]
fn field_def_threshold_policy() {
let id = FieldId::new(2).unwrap();
let field = FieldDef::with_threshold(id, FieldCodec::uint(12), 5);
assert_eq!(field.change, ChangePolicy::Threshold { threshold_q: 5 });
}
#[test]
fn field_def_change_override() {
let id = FieldId::new(3).unwrap();
let field = FieldDef::new(id, FieldCodec::uint(8))
.change(ChangePolicy::Threshold { threshold_q: 2 });
assert_eq!(field.change, ChangePolicy::Threshold { threshold_q: 2 });
}
}