blather 0.12.0

A talkative line-based protocol
Documentation
use crate::err::{Error, ParamError};

fn is_topic_leading_char(c: char) -> bool {
  c.is_alphabetic()
}

fn is_topic_char(c: char) -> bool {
  c.is_alphanumeric() || c == '_' || c == '-'
}

/// Make sure that topic string is valid.
pub fn validate_topic(topic: &str) -> Result<(), Error> {
  let mut chars = topic.chars();
  match chars.next() {
    Some(c) => {
      if !is_topic_leading_char(c) {
        return Err(Error::BadFormat(
          "Invalid leading topic character".to_string()
        ));
      }
    }
    None => return Err(Error::BadFormat("Empty or broken topic".to_string()))
  }

  if chars.any(|c| !is_topic_char(c)) {
    return Err(Error::BadFormat("Invalid topic character".to_string()));
  }
  Ok(())
}


fn is_key_char(c: char) -> bool {
  c.is_alphanumeric() || c.is_ascii_punctuation()
}

/// Make sure that a parameter key is valid.
pub fn validate_param_key(key: &str) -> Result<(), Error> {
  if key.is_empty() {
    return Err(Error::Param(ParamError::Key("empty".into())));
  }

  let mut chars = key.chars();
  if chars.any(|c| !is_key_char(c)) {
    return Err(Error::Param(ParamError::Key("invalid character".into())));
  }
  Ok(())
}

/// Make sure that a parameter value is valid.
pub fn validate_param_value(val: &str) -> Result<(), Error> {
  (!val.contains('\n')).then_some(()).ok_or_else(|| {
    Error::Param(ParamError::Value("contains newline".into()))
  })?;
  Ok(())
}


#[cfg(test)]
mod tests {
  use super::{validate_param_value, validate_topic, Error};

  #[test]
  fn ok_topic_1() {
    assert!(validate_topic("Foobar").is_ok());
  }

  #[test]
  fn empty_topic() {
    let Err(Error::BadFormat(msg)) = validate_topic("") else {
      panic!("Unexpectedly not Error::BadFormat");
    };
    assert_eq!(msg, "Empty or broken topic");
  }

  #[test]
  fn broken_topic_1() {
    let Err(Error::BadFormat(msg)) = validate_topic("foo bar") else {
      panic!("Unexpectedly not Error::BadFormat");
    };
    assert_eq!(msg, "Invalid topic character");
  }

  #[test]
  fn broken_topic_2() {
    let Err(Error::BadFormat(msg)) = validate_topic(" foobar") else {
      panic!("Unexpectedly not Error::BadFormat");
    };
    assert_eq!(msg, "Invalid leading topic character");
  }

  #[test]
  fn okval() {
    validate_param_value("hello world").unwrap();
  }

  #[test]
  #[should_panic(expected = "Param(Value(\"contains newline\"))")]
  fn val_newline() {
    validate_param_value("hello\nworld").unwrap();
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :