Skip to main content

prost_protovalidate/
config.rs

1use std::sync::Arc;
2
3use prost_reflect::{
4    DynamicMessage, FieldDescriptor, MessageDescriptor, OneofDescriptor, ReflectMessage,
5};
6use prost_types::Timestamp;
7
8/// Options for configuring the `Validator` at construction time.
9#[non_exhaustive]
10pub enum ValidatorOption {
11    /// Stop validation on the first violation instead of collecting all.
12    FailFast,
13
14    /// Disable lazy compilation: all known message types must be
15    /// pre-registered, and unknown types will produce a compilation error.
16    DisableLazy,
17
18    /// Override the function used to populate `now` in timestamp-based rules/CEL.
19    NowFn(Arc<dyn Fn() -> Timestamp + Send + Sync>),
20
21    /// Additional encoded `FileDescriptorSet` payloads used to resolve
22    /// custom/proprietary rule extensions at runtime.
23    AdditionalDescriptorSetBytes(Vec<u8>),
24
25    /// Preload evaluators for these descriptors at validator construction time.
26    /// Useful with `DisableLazy` to allow a fixed set of message types.
27    MessageDescriptors(Vec<MessageDescriptor>),
28
29    /// Allow unknown fields in constraint messages instead of producing a
30    /// compilation error. Useful when working with newer constraint protos
31    /// that contain fields not yet recognized by this library.
32    AllowUnknownFields,
33}
34
35/// Options for configuring a single `Validator::validate_with` call.
36#[non_exhaustive]
37pub enum ValidationOption {
38    /// Stop validation on the first violation instead of collecting all.
39    FailFast,
40    /// Override the filter for this validation call.
41    Filter(Arc<dyn Filter>),
42    /// Override the function used to populate `now` in timestamp-based rules/CEL.
43    NowFn(Arc<dyn Fn() -> Timestamp + Send + Sync>),
44}
45
46/// Controls which fields/messages are validated.
47pub trait Filter: Send + Sync {
48    /// Returns true if the given message should be validated.
49    fn should_validate(&self, message: &DynamicMessage, descriptor: &MessageDescriptor) -> bool;
50
51    /// Returns true if the given field should be validated.
52    /// Defaults to message-level filtering for compatibility.
53    fn should_validate_field(&self, message: &DynamicMessage, _field: &FieldDescriptor) -> bool {
54        let descriptor = message.descriptor();
55        self.should_validate(message, &descriptor)
56    }
57
58    /// Returns true if the given oneof should be validated.
59    /// Defaults to message-level filtering for compatibility.
60    fn should_validate_oneof(&self, message: &DynamicMessage, _oneof: &OneofDescriptor) -> bool {
61        let descriptor = message.descriptor();
62        self.should_validate(message, &descriptor)
63    }
64}
65
66/// A filter that always validates everything.
67pub(crate) struct NopFilter;
68
69impl Filter for NopFilter {
70    fn should_validate(&self, _message: &DynamicMessage, _descriptor: &MessageDescriptor) -> bool {
71        true
72    }
73}
74
75/// Runtime configuration passed to evaluators during validation.
76pub(crate) struct ValidationConfig {
77    pub fail_fast: bool,
78    pub filter: Arc<dyn Filter>,
79    pub now_fn: Arc<dyn Fn() -> Timestamp + Send + Sync>,
80}
81
82/// Default timestamp factory using `SystemTime::now()`.
83///
84/// Shared by `ValidationConfig::default()` and `Validator::with_options()`.
85/// Delegates to [`crate::time::now_systemtime`] so the runtime default and
86/// the compile-time `Validate` path read time through the same code path.
87pub(crate) fn default_now_fn() -> Arc<dyn Fn() -> Timestamp + Send + Sync> {
88    Arc::new(crate::time::now_systemtime)
89}
90
91impl Default for ValidationConfig {
92    fn default() -> Self {
93        Self {
94            fail_fast: false,
95            filter: Arc::new(NopFilter),
96            now_fn: default_now_fn(),
97        }
98    }
99}