nml2 0.3.1

Convert nmlcc neuro science components into Arbor data formats
Documentation
use crate::error::{Error, Result};

#[derive(Debug, Clone)]
struct Action {
    item: String,
    keep: bool,
    wild: bool,
}

#[derive(Debug, Clone)]
pub struct Filter {
    actions: Vec<Action>,
}

impl Filter {
    pub fn discard_all() -> Self {
        Filter {
            actions: vec![Action {
                item: String::new(),
                keep: false,
                wild: true,
            }],
        }
    }

    pub fn retain_all() -> Self {
        Filter {
            actions: vec![Action {
                item: String::new(),
                keep: true,
                wild: true,
            }],
        }
    }

    pub fn new(filter: &str) -> Result<Self> {
        let mut result = Filter {
            actions: Vec::new(),
        };
        for item in filter.split(',') {
            if let Some(it) = item.strip_prefix('+') {
                if let Some(it) = it.strip_suffix('*') {
                    result.retain_prefix(it);
                } else {
                    result.retain(it);
                }
            } else if let Some(it) = item.strip_prefix('-') {
                if let Some(it) = it.strip_suffix('*') {
                    result.discard_prefix(it);
                } else {
                    result.discard(it);
                }
            } else {
                return Err(Error::Parse {
                    what: format!("Couldn't parse filter '{item}' must be [+-][a-zA-Z0-9_]+*?"),
                });
            }
        }
        Ok(result)
    }

    pub fn retain_prefix(&mut self, it: &str) {
        self.actions.push(Action {
            item: it.to_string(),
            keep: true,
            wild: true,
        });
    }

    pub fn retain(&mut self, it: &str) {
        self.actions.push(Action {
            item: it.to_string(),
            keep: true,
            wild: false,
        });
    }

    pub fn discard_prefix(&mut self, it: &str) {
        self.actions.push(Action {
            item: it.to_string(),
            keep: false,
            wild: true,
        });
    }

    pub fn discard(&mut self, it: &str) {
        self.actions.push(Action {
            item: it.to_string(),
            keep: false,
            wild: false,
        });
    }

    pub fn apply(&self, string: &str) -> bool {
        let mut result = true;
        for Action { item, keep, wild } in &self.actions {
            if (*wild && string.starts_with(item)) || string == item {
                result = *keep;
            }
        }
        result
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn filter() {
        let mut filter = Filter::retain_all();
        assert_eq!(filter.apply("abcd"), true);
        filter.discard_prefix("a");
        assert_eq!(filter.apply("abcd"), false);
        filter.retain_prefix("ab");
        assert_eq!(filter.apply("abcd"), true);
        filter.discard_prefix("abc");
        assert_eq!(filter.apply("abcd"), false);
        filter.retain("abcd");
        assert_eq!(filter.apply("abcd"), true);
        assert_eq!(filter.apply("abcq"), false);
    }
}