glop 0.2.5

Glue Language for OPerations
Documentation
use std::collections::HashSet;
use std::ops::Deref;

#[derive(Serialize, Deserialize)]
#[derive(Clone)]
pub struct Glop {
    pub matches: Vec<Match>,
}

#[derive(Serialize, Deserialize)]
#[derive(Clone)]
pub struct Match {
    pub conditions: Vec<Condition>,
    pub actions: Vec<Action>,
    pub acting_role: Option<String>,
}

pub fn acting_roles(conditions: &Vec<Condition>) -> HashSet<String> {
    conditions.iter()
        .map(|c| {
            if let &Condition::Message { topic: _, src_role: _, ref acting_role } = c {
                if let &Some(ref role) = acting_role {
                    return Some(role.to_string());
                }
            }
            None
        })
        .filter(|maybe_role| if let &Some(_) = maybe_role {
            true
        } else {
            false
        })
        .map(|maybe_role| maybe_role.unwrap().to_string())
        .collect()
}

pub type Identifier = Vec<String>;

#[derive(Serialize, Deserialize)]
#[derive(Clone)]
pub enum Condition {
    Cmp(Identifier, CmpOpcode, String),
    IsSet(Identifier),
    IsUnset(Identifier),
    Message {
        topic: String,
        src_role: Option<String>,
        acting_role: Option<String>,
    },
}

#[derive(Serialize, Deserialize)]
#[derive(Clone)]
pub enum CmpOpcode {
    Equal,
    NotEqual,
}

#[derive(Serialize, Deserialize)]
#[derive(Clone)]
pub enum Action {
    SetVar(Identifier, String),
    UnsetVar(Identifier),
    Script(String),
    Match(Match),
}

use std::fmt;

impl fmt::Display for Action {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Action::SetVar(ref k, ref v) => write!(f, "var set {} {};", FmtIdentifier(k), v),
            &Action::UnsetVar(ref k) => write!(f, "var unset {};", FmtIdentifier(k)),
            &Action::Script(ref v) => write!(f, r#"script {}!#"#, v),
            &Action::Match(ref v) => write!(f, "{}", v),
        }
    }
}

struct FmtActions<'a>(&'a Vec<Action>);

impl<'a> Deref for FmtActions<'a> {
    type Target = Vec<Action>;

    fn deref(&self) -> &Vec<Action> {
        self.0
    }
}

impl<'a> fmt::Display for FmtActions<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for i in self.iter() {
            try!(writeln!(f, "    {}", i));
        }
        Ok(())
    }
}

impl fmt::Display for CmpOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &CmpOpcode::Equal => write!(f, "=="),
            &CmpOpcode::NotEqual => write!(f, "!="),
        }
    }
}

impl fmt::Display for Condition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Condition::Cmp(ref l, ref op, ref r) => write!(f, "{} {} {}", FmtIdentifier(l), op, r),
            &Condition::IsSet(ref k) => write!(f, "is_set {}", FmtIdentifier(k)),
            &Condition::IsUnset(ref k) => write!(f, "is_unset {}", FmtIdentifier(k)),
            &Condition::Message { ref topic, ref src_role, ref acting_role } => {
                write!(f, "message {}", topic)?;
                if let &Some(ref role) = src_role {
                    write!(f, " from {}", role)?;
                }
                if let &Some(ref role) = acting_role {
                    write!(f, " as {}", role)?;
                }
                Ok(())
            }
        }
    }
}

struct FmtConditions<'a>(&'a Vec<Condition>);

impl<'a> Deref for FmtConditions<'a> {
    type Target = Vec<Condition>;

    fn deref(&self) -> &Vec<Condition> {
        self.0
    }
}

impl<'a> fmt::Display for FmtConditions<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let n = self.len();
        for i in 0..n {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{}", self[i]));
        }
        Ok(())
    }
}

impl fmt::Display for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f,
                 "when ({}) {{\n{}}}",
                 FmtConditions(&self.conditions),
                 FmtActions(&self.actions))
    }
}

impl fmt::Display for Glop {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for m in &self.matches {
            try!(writeln!(f, "{}", m));
        }
        Ok(())
    }
}

struct FmtIdentifier<'a>(&'a Identifier);

impl<'a> fmt::Display for FmtIdentifier<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0.join("."))
    }
}