proto-types 0.1.0

Rust types generated from the google.protobuf and buf.validate protobuf packages, plus extra helpers for implementing validation with the protocheck crate.
Documentation
use crate::protovalidate::{BytesRules, MapRules, RepeatedRules, StringRules};

pub enum LengthRulesTarget {
  String,
  Bytes,
  RepeatedItems,
  MapPairs,
}

pub enum LengthRulesKind {
  Len,
  LenBytes,
  RepeatedItems,
  MapPairs,
}

pub struct LengthRules {
  pub len: Option<u64>,
  pub min_len: Option<u64>,
  pub max_len: Option<u64>,
  pub target: LengthRulesTarget,
  pub kind: LengthRulesKind,
}

impl LengthRules {
  pub fn name(&self) -> &'static str {
    match self.target {
      LengthRulesTarget::String => "string",
      LengthRulesTarget::Bytes => "bytes",
      LengthRulesTarget::RepeatedItems => "repeated",
      LengthRulesTarget::MapPairs => "maps",
    }
  }

  pub fn has_rule(&self) -> bool {
    self.len.is_some() || self.min_len.is_some() || self.max_len.is_some()
  }

  pub fn unit(&self) -> &str {
    match self.target {
      LengthRulesTarget::String => "character",
      LengthRulesTarget::Bytes => "byte",
      LengthRulesTarget::RepeatedItems => "item",
      LengthRulesTarget::MapPairs => "key-value pair",
    }
  }

  pub fn len_name(&self) -> &str {
    match self.kind {
      LengthRulesKind::Len => "len",
      LengthRulesKind::LenBytes => "len_bytes",
      _ => "",
    }
  }

  pub fn min_len_name(&self) -> &str {
    match self.kind {
      LengthRulesKind::Len => "min_len",
      LengthRulesKind::LenBytes => "min_bytes",
      LengthRulesKind::RepeatedItems => "min_items",
      LengthRulesKind::MapPairs => "min_pairs",
    }
  }

  pub fn max_len_name(&self) -> &str {
    match self.kind {
      LengthRulesKind::Len => "max_len",
      LengthRulesKind::LenBytes => "max_bytes",
      LengthRulesKind::RepeatedItems => "max_items",
      LengthRulesKind::MapPairs => "max_pairs",
    }
  }

  pub fn validate(self) -> Result<LengthRules, String> {
    let len = self.len;
    let min_len = self.min_len;
    let max_len = self.max_len;

    if len.is_some() && (min_len.is_some() || max_len.is_some()) {
      return Err(format!(
        "{} cannot be used with {} or {}",
        self.len_name(),
        self.min_len_name(),
        self.max_len_name()
      ));
    }

    if let Some(min) = min_len
      && let Some(max) = max_len
        && min > max {
          return Err(format!("{} cannot be larger than {}", self.min_len_name(), self.max_len_name()));
        }

    Ok(self)
  }
}

impl RepeatedRules {
  pub fn length_rules(&self) -> Result<LengthRules, String> {
    let min_len = self.min_items;
    let max_len = self.max_items;

    LengthRules {
      len: None,
      min_len,
      max_len,
      target: LengthRulesTarget::RepeatedItems,
      kind: LengthRulesKind::RepeatedItems,
    }
    .validate()
  }
}

impl MapRules {
  pub fn length_rules(&self) -> Result<LengthRules, String> {
    let min_len = self.min_pairs;
    let max_len = self.max_pairs;

    LengthRules {
      len: None,
      min_len,
      max_len,
      target: LengthRulesTarget::MapPairs,
      kind: LengthRulesKind::MapPairs,
    }
    .validate()
  }
}

impl BytesRules {
  pub fn length_rules(&self) -> Result<LengthRules, String> {
    let len = self.len;
    let min_len = self.min_len;
    let max_len = self.max_len;

    LengthRules {
      len,
      min_len,
      max_len,
      target: LengthRulesTarget::Bytes,
      kind: LengthRulesKind::Len,
    }
    .validate()
  }
}

impl StringRules {
  pub fn length_rules(&self) -> Result<LengthRules, String> {
    let len = self.len;
    let min_len = self.min_len;
    let max_len = self.max_len;

    LengthRules {
      len,
      min_len,
      max_len,
      target: LengthRulesTarget::String,
      kind: LengthRulesKind::Len,
    }
    .validate()
  }

  pub fn bytes_length_rules(&self) -> Result<LengthRules, String> {
    let len = self.len_bytes;
    let min_len = self.min_bytes;
    let max_len = self.max_bytes;

    LengthRules {
      len,
      min_len,
      max_len,
      target: LengthRulesTarget::String,
      kind: LengthRulesKind::LenBytes,
    }
    .validate()
  }
}