use crate::Result;
mod sealed {
pub trait Sealed {}
}
pub trait ParseParams: Sized + sealed::Sealed {
fn parse_params(params: &[&str]) -> Result<Self>;
}
macro_rules! impl_parse_params {
($($ty:path),+ $(,)?) => {
$(
impl sealed::Sealed for $ty {}
impl ParseParams for $ty {
fn parse_params(params: &[&str]) -> Result<Self> {
<$ty>::parse_params(params)
}
}
)+
};
}
impl_parse_params! {
crate::netlink::tc::CakeConfig,
crate::netlink::tc::ClsactConfig,
crate::netlink::tc::DrrConfig,
crate::netlink::tc::EtfConfig,
crate::netlink::tc::FqCodelConfig,
crate::netlink::tc::HfscConfig,
crate::netlink::tc::HtbQdiscConfig,
crate::netlink::tc::IngressConfig,
crate::netlink::tc::MqprioConfig,
crate::netlink::tc::NetemConfig,
crate::netlink::tc::PieConfig,
crate::netlink::tc::PlugConfig,
crate::netlink::tc::PrioConfig,
crate::netlink::tc::QfqConfig,
crate::netlink::tc::RedConfig,
crate::netlink::tc::SfqConfig,
crate::netlink::tc::TaprioConfig,
crate::netlink::tc::TbfConfig,
crate::netlink::tc::DrrClassConfig,
crate::netlink::tc::HfscClassConfig,
crate::netlink::tc::HtbClassConfig,
crate::netlink::tc::QfqClassConfig,
crate::netlink::filter::BasicFilter,
crate::netlink::filter::BpfFilter,
crate::netlink::filter::CgroupFilter,
crate::netlink::filter::FlowFilter,
crate::netlink::filter::FlowerFilter,
crate::netlink::filter::FwFilter,
crate::netlink::filter::MatchallFilter,
crate::netlink::filter::RouteFilter,
crate::netlink::filter::U32Filter,
crate::netlink::action::BpfAction,
crate::netlink::action::ConnmarkAction,
crate::netlink::action::CsumAction,
crate::netlink::action::CtAction,
crate::netlink::action::GactAction,
crate::netlink::action::MirredAction,
crate::netlink::action::NatAction,
crate::netlink::action::PeditAction,
crate::netlink::action::PoliceAction,
crate::netlink::action::SampleAction,
crate::netlink::action::SimpleAction,
crate::netlink::action::SkbeditAction,
crate::netlink::action::TunnelKeyAction,
crate::netlink::action::VlanAction,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::netlink::tc::HtbQdiscConfig;
#[test]
fn trait_dispatch_matches_inherent() {
let via_trait = <HtbQdiscConfig as ParseParams>::parse_params(&["default", "10"])
.expect("htb default 10 should parse via trait");
let via_inherent =
HtbQdiscConfig::parse_params(&["default", "10"]).expect("inherent parse");
assert_eq!(via_trait.default_class, via_inherent.default_class);
}
#[test]
fn trait_propagates_strict_errors() {
let err = <HtbQdiscConfig as ParseParams>::parse_params(&["nonsense"])
.expect_err("strict parser must reject unknown tokens");
let msg = err.to_string();
assert!(msg.contains("htb"), "error must be kind-prefixed: {msg}");
}
#[test]
fn generic_dispatch_compiles() {
fn parse<C: ParseParams>(params: &[&str]) -> Result<C> {
C::parse_params(params)
}
let _: HtbQdiscConfig = parse(&["default", "10"]).expect("htb default 10");
}
}