protoschema 0.1.9

📐 Programmatically define protobuf contracts using flexible, modular and reusable elements
Documentation
use bon::Builder;

use crate::{
  validators::{cel::CelRule, validate_lists, Ignore, OptionValueList},
  OptionValue, ProtoOption,
};

/// Used by the [`any`](crate::any) macro to define validation rules.
#[derive(Clone, Debug, Builder)]
pub struct AnyValidator<'a> {
  /// Only the type_urls defined in this list will be considered valid for this field.
  #[builder(into)]
  pub in_: Option<&'a [&'a str]>,
  /// The type_urls defined in this list will be considered invalid for this field.
  #[builder(into)]
  pub not_in: Option<&'a [&'a str]>,
  /// Adds custom validation using one or more [`CelRule`]s to this field.
  #[builder(into)]
  pub cel: Option<Box<[CelRule]>>,
  /// Marks the field as invalid if unset.
  #[builder(with = || true)]
  pub required: Option<bool>,
  #[builder(setters(vis = "", name = ignore))]
  pub ignore: Option<Ignore>,
}

impl_ignore!(AnyValidatorBuilder);

impl<'a, S: any_validator_builder::State> From<AnyValidatorBuilder<'a, S>> for ProtoOption {
  #[track_caller]
  fn from(value: AnyValidatorBuilder<'a, S>) -> Self {
    value.build().into()
  }
}

impl<'a> From<AnyValidator<'a>> for ProtoOption {
  #[track_caller]
  fn from(validator: AnyValidator<'a>) -> Self {
    let name = "(buf.validate.field)";

    let mut values: OptionValueList = Vec::new();

    validate_lists(validator.in_, validator.not_in).unwrap_or_else(|invalid| {
      panic!(
        "The following values are present inside of 'in' and 'not_in': {:?}",
        invalid
      )
    });

    insert_option!(validator, values, in_, [string]);
    insert_option!(validator, values, not_in, [string]);

    let mut option_value: OptionValueList = vec![(
      "any".into(),
      OptionValue::Message(values.into_boxed_slice()),
    )];

    insert_cel_rule!(validator, option_value);
    insert_option!(validator, option_value, required, bool);

    ProtoOption {
      name,
      value: OptionValue::Message(option_value.into_boxed_slice()).into(),
    }
  }
}

#[doc(hidden)]
#[track_caller]
pub fn build_any_validator_option<F, S>(config_fn: F) -> ProtoOption
where
  F: FnOnce(AnyValidatorBuilder) -> AnyValidatorBuilder<S>,
  S: any_validator_builder::IsComplete,
{
  let builder = AnyValidator::builder();
  let validator = config_fn(builder).build();
  validator.into()
}