#[serde_with::serde_as]
#[derive(Clone,Debug,Default,serde::Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(remote="Self")]
#[serde(rename_all="kebab-case")]
pub struct Rule {
#[serde(rename="match")] pub match_: crate::Match,
#[serde_as(as="Option<serde_with::FromInto<crate::SerdeDuration>>")] pub last_activity_min: Option<std::time::Duration>,
#[serde_as(as="Option<serde_with::FromInto<crate::SerdeDuration>>")] pub seed_time_min: Option<std::time::Duration>,
pub categories_allowed: Option<std::collections::HashSet<String>>,
pub include_in_score: Option<bool>,
pub pin: Option<bool>,
pub pin_reason: Option<String>,
pub seeder_count_min: Option<u64>,
pub state_allowed: Option<std::collections::HashSet<crate::TorrentState>>,
}
impl<'de> serde::Deserialize<'de> for Rule {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let rule = Rule::deserialize(deserializer)?;
rule.validate().map_err(serde::de::Error::custom)?;
Ok(rule)
}
}
impl Rule {
fn validate(&self) -> anyhow::Result<()> {
if let Some(reason) = &self.pin_reason {
anyhow::ensure!(
self.pin.is_some(),
"pin-reason {reason:?} is set but pin is not. A pin-reason is only meaningful on a rule that sets pin.");
}
Ok(())
}
}