prost_validate_types/
lib.rs

1#[allow(clippy::len_without_is_empty)]
2mod proto;
3
4use anyhow::anyhow;
5use once_cell::sync::Lazy;
6use prost_reflect::{
7    ExtensionDescriptor, FieldDescriptor, MessageDescriptor, OneofDescriptor, Value,
8};
9pub use proto::*;
10use std::borrow::Cow;
11
12#[allow(clippy::unwrap_used)]
13static VALIDATION_DISABLED: Lazy<ExtensionDescriptor> = Lazy::new(|| {
14    DESCRIPTOR_POOL
15        .get_extension_by_name("validate.disabled")
16        .ok_or(anyhow!("validate.disabled extension not found"))
17        .unwrap()
18});
19#[allow(clippy::unwrap_used)]
20static VALIDATION_IGNORED: Lazy<ExtensionDescriptor> = Lazy::new(|| {
21    DESCRIPTOR_POOL
22        .get_extension_by_name("validate.ignored")
23        .ok_or(anyhow!("validate.ignored extension not found"))
24        .unwrap()
25});
26#[allow(clippy::unwrap_used)]
27static VALIDATION_FIELD_RULES: Lazy<ExtensionDescriptor> = Lazy::new(|| {
28    DESCRIPTOR_POOL
29        .get_extension_by_name("validate.rules")
30        .ok_or(anyhow!("validate.rules extension not found"))
31        .unwrap()
32});
33#[allow(clippy::unwrap_used)]
34static VALIDATION_ONE_OF_RULES: Lazy<ExtensionDescriptor> = Lazy::new(|| {
35    DESCRIPTOR_POOL
36        .get_extension_by_name("validate.required")
37        .ok_or(anyhow!("validate.required extension not found"))
38        .unwrap()
39});
40
41pub trait FieldRulesExt {
42    fn validation_rules(&self) -> anyhow::Result<Option<FieldRules>>;
43    fn real_oneof(&self) -> Option<OneofDescriptor>;
44    fn optional(&self) -> bool;
45}
46
47impl FieldRulesExt for FieldDescriptor {
48    fn validation_rules(&self) -> anyhow::Result<Option<FieldRules>> {
49        match self
50            .options()
51            .get_extension(&VALIDATION_FIELD_RULES)
52            .as_message()
53        {
54            Some(r) => Ok(Some(r.transcode_to::<FieldRules>()?)),
55            None => Ok(None),
56        }
57    }
58    fn real_oneof(&self) -> Option<OneofDescriptor> {
59        if let Some(oneof) = self.containing_oneof() {
60            if oneof.is_synthetic() {
61                return None;
62            }
63            return Some(oneof);
64        }
65        None
66    }
67
68    fn optional(&self) -> bool {
69        self.containing_oneof().is_some_and(|d| d.is_synthetic())
70    }
71}
72
73pub trait OneofRulesExt {
74    fn required(&self) -> bool;
75}
76
77impl OneofRulesExt for OneofDescriptor {
78    fn required(&self) -> bool {
79        self.options()
80            .get_extension(&VALIDATION_ONE_OF_RULES)
81            .is_true()
82    }
83}
84
85pub trait MessageRulesExt {
86    fn validation_disabled(&self) -> bool;
87    fn validation_ignored(&self) -> bool;
88}
89
90impl MessageRulesExt for MessageDescriptor {
91    fn validation_disabled(&self) -> bool {
92        self.options().get_extension(&VALIDATION_DISABLED).is_true()
93    }
94
95    fn validation_ignored(&self) -> bool {
96        self.options().get_extension(&VALIDATION_IGNORED).is_true()
97    }
98}
99
100trait IsTrueExt {
101    fn is_true(&self) -> bool;
102}
103
104impl IsTrueExt for Cow<'_, Value> {
105    fn is_true(&self) -> bool {
106        self.as_bool().unwrap_or(false)
107    }
108}