fastly 0.12.0

Fastly Compute API
Documentation
use serde::{Deserialize, Deserializer, Serialize};

/// LookupMatch is the result of an ACL lookup which found
/// a matching prefix.
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct LookupMatch {
    /// Matching prefix in CIDR format.
    pub(crate) prefix: String,
    /// Associated prefix's action.
    pub(crate) action: MatchAction,
}

impl LookupMatch {
    /// Deserialize the given response body into a 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)
    }

    /// Returns the matching prefix.
    pub fn prefix(&self) -> &str {
        return &self.prefix;
    }

    /// Returns the associated prefix action.
    pub fn action(&self) -> &MatchAction {
        return &self.action;
    }

    /// Returns true if action is `Allow`.
    pub fn is_allow(&self) -> bool {
        return self.action == MatchAction::Allow;
    }

    /// Returns true if action is `Block`.
    pub fn is_block(&self) -> bool {
        return self.action == MatchAction::Block;
    }

    /// Returns true if action is `Other` and matches the given value.
    pub fn is_other(&self, other: String) -> bool {
        return self.action == MatchAction::Other(other);
    }
}

/// MatchAction represents an action associated with an ACL prefix.
#[derive(Debug, Serialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum MatchAction {
    /// Allow prefix.
    Allow,
    /// Block prefix.
    Block,
    /// Unexpected or new action.
    Other(String),
}

// JSON representations of the following MatchActions.
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()),
        },
    );
}