Skip to main content

protocheck_core/validators/
bytes.rs

1use bytes::Bytes;
2use paste::paste;
3#[cfg(feature = "regex")]
4use regex::Regex;
5
6use super::well_known_strings::{is_valid_ip, is_valid_ipv4, is_valid_ipv6};
7use crate::{
8  field_data::FieldContext,
9  protovalidate::Violation,
10  validators::static_data::{base_violations::create_violation, bytes_violations::*},
11};
12
13macro_rules! create_bytes_violation {
14  ($check:ident, $field_context:ident, $violation_name:ident, $error_message:expr) => {
15    create_violation!(
16      bytes,
17      $check,
18      $field_context,
19      $violation_name,
20      $error_message
21    )
22  };
23}
24
25macro_rules! well_known_rule {
26  (
27    $name:ident,
28    $definition:literal
29  ) => {
30    paste! {
31      pub fn $name(field_context: &FieldContext, value: &Bytes) -> Result<(), Violation> {
32        let string_val = parse_bytes_input(value, field_context)?;
33        let check = [<is_valid _ $name>](string_val);
34
35        create_bytes_violation!(check, field_context, $name, concat!("must be a valid ", $definition))
36      }
37    }
38  };
39}
40
41macro_rules! bytes_validator {
42  (
43    $mode:ident,
44    $name:ident,
45    $target_type:ty,
46    $validation_expression:expr
47  ) => {
48    macro_rules! _generate_check {
49      (string_arg, $closure:expr, $value:expr, $target:expr, $field_context:expr) => {{
50        let string_val = parse_bytes_input($value, $field_context)?;
51        $closure($target, &string_val)
52      }};
53
54      (bytes_arg, $closure:expr, $value:expr, $target:expr, $field_context:expr) => {
55        $closure($target, $value)
56      };
57    }
58
59    pub fn $name(
60      field_context: &FieldContext,
61      value: &Bytes,
62      target: $target_type,
63      error_message: &'static str,
64    ) -> Result<(), Violation> {
65      let check = _generate_check!($mode, $validation_expression, value, target, field_context);
66
67      create_bytes_violation!(check, field_context, $name, error_message)
68    }
69  };
70}
71
72well_known_rule!(ip, "ip address");
73
74well_known_rule!(ipv4, "ipv4 address");
75
76well_known_rule!(ipv6, "ipv6 address");
77
78#[cfg(feature = "regex")]
79bytes_validator!(string_arg, pattern, &Regex, |t: &Regex, s: &str| t
80  .is_match(s));
81
82bytes_validator!(bytes_arg, min_len, u64, |t: u64, v: &Bytes| v.len()
83  >= t as usize);
84
85bytes_validator!(bytes_arg, max_len, u64, |t: u64, v: &Bytes| v.len()
86  <= t as usize);
87
88bytes_validator!(bytes_arg, len, u64, |t: u64, v: &Bytes| v.len()
89  == t as usize);
90
91bytes_validator!(
92  bytes_arg,
93  contains,
94  &'static [u8],
95  |t: &'static [u8], v: &Bytes| v.windows(t.len()).any(|win| win == t)
96);
97
98bytes_validator!(
99  bytes_arg,
100  suffix,
101  &'static [u8],
102  |t: &'static [u8], v: &Bytes| v.ends_with(t)
103);
104
105bytes_validator!(
106  bytes_arg,
107  prefix,
108  &'static [u8],
109  |t: &'static [u8], v: &Bytes| v.starts_with(t)
110);