use serde::{Deserialize, Deserializer, Serialize};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct LookupMatch {
pub(crate) prefix: String,
pub(crate) action: MatchAction,
}
impl LookupMatch {
pub fn from_body_handle<R>(body_handle: R) -> Result<Self, serde_json::error::Error>
where
R: std::io::Read,
{
serde_json::from_reader(body_handle)
}
pub fn prefix(&self) -> &str {
return &self.prefix;
}
pub fn action(&self) -> &MatchAction {
return &self.action;
}
pub fn is_allow(&self) -> bool {
return self.action == MatchAction::Allow;
}
pub fn is_block(&self) -> bool {
return self.action == MatchAction::Block;
}
pub fn is_other(&self, other: String) -> bool {
return self.action == MatchAction::Other(other);
}
}
#[derive(Debug, Serialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum MatchAction {
Allow,
Block,
Other(String),
}
const ALLOW_JSON: &str = "ALLOW";
const BLOCK_JSON: &str = "BLOCK";
impl<'de> Deserialize<'de> for MatchAction {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let action = String::deserialize(de)?;
Ok(match action.as_str() {
ALLOW_JSON => Self::Allow,
BLOCK_JSON => Self::Block,
_ => Self::Other(action),
})
}
}
#[test]
fn can_decode_lookup_match() {
let assert_decodes_to = |input: &str, want: LookupMatch| {
let got = LookupMatch::from_body_handle(input.as_bytes()).expect("can decode from JSON");
assert_eq!(got, want);
};
assert_decodes_to(
r#"
{"prefix": "::face/64", "action": "ALLOW"}
"#,
LookupMatch {
prefix: "::face/64".to_string(),
action: MatchAction::Allow,
},
);
assert_decodes_to(
r#"
{"prefix": "1.2.3.4/24", "action": "BLOCK"}
"#,
LookupMatch {
prefix: "1.2.3.4/24".to_string(),
action: MatchAction::Block,
},
);
assert_decodes_to(
r#"
{"prefix": "::/24", "action": "MAYBE"}
"#,
LookupMatch {
prefix: "::/24".to_string(),
action: MatchAction::Other("MAYBE".to_string()),
},
);
}