use super::{Decode, DecodeError, Encode, Label, Reader, Sink, ValueError, Writer};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct LedgerPolicy {
required_dimensions: Vec<Label>,
max_value_date_drift_days: Option<u32>,
}
impl LedgerPolicy {
pub fn new(
required_dimensions: impl IntoIterator<Item = Label>,
max_value_date_drift_days: Option<u32>,
) -> Result<Self, ValueError> {
let mut required: Vec<Label> = required_dimensions.into_iter().collect();
if required.len() > super::Dimensions::MAX_AXES {
return Err(ValueError::TooManyDimensions);
}
required.sort();
if required
.windows(2)
.any(|pair| matches!(pair, [a, b] if a == b))
{
return Err(ValueError::Duplicate);
}
Ok(Self {
required_dimensions: required,
max_value_date_drift_days,
})
}
#[must_use]
pub fn required_dimensions(&self) -> &[Label] {
&self.required_dimensions
}
#[must_use]
pub const fn max_value_date_drift_days(&self) -> Option<u32> {
self.max_value_date_drift_days
}
}
impl Encode for LedgerPolicy {
fn encode<S: Sink>(&self, w: &mut Writer<S>) {
w.seq(&self.required_dimensions);
w.opt(self.max_value_date_drift_days.as_ref());
}
}
impl Decode for LedgerPolicy {
fn decode(r: &mut Reader<'_>, field: &'static str) -> Result<Self, DecodeError> {
let count = r.count(field, super::Dimensions::MAX_AXES)?;
let mut required: Vec<Label> = Vec::new();
for _ in 0..count {
let label: Label = r.value(field)?;
if required.last().is_some_and(|last| *last >= label) {
return Err(DecodeError::NonCanonical { field });
}
required.push(label);
}
let drift = r.opt(field, Reader::u32)?;
Ok(Self {
required_dimensions: required,
max_value_date_drift_days: drift,
})
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::{Label, LedgerPolicy};
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename = "LedgerPolicy")]
struct Parts {
required_dimensions: Vec<Label>,
max_value_date_drift_days: Option<u32>,
}
impl serde::Serialize for LedgerPolicy {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
Parts {
required_dimensions: self.required_dimensions.clone(),
max_value_date_drift_days: self.max_value_date_drift_days,
}
.serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for LedgerPolicy {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let parts = Parts::deserialize(deserializer)?;
Self::new(parts.required_dimensions, parts.max_value_date_drift_days)
.map_err(serde::de::Error::custom)
}
}
}