prost_protovalidate_types/
lib.rs1#![warn(missing_docs)]
30
31#[allow(
32 missing_docs,
33 clippy::len_without_is_empty,
34 clippy::doc_lazy_continuation,
35 clippy::doc_markdown,
36 clippy::must_use_candidate
37)]
38mod proto;
39
40use anyhow::anyhow;
41use prost_reflect::{
42 DynamicMessage, ExtensionDescriptor, FieldDescriptor, MessageDescriptor, OneofDescriptor,
43};
44use std::sync::LazyLock;
45
46pub use proto::*;
47
48#[allow(clippy::unwrap_used)]
50static BUF_VALIDATE_MESSAGE: LazyLock<ExtensionDescriptor> = LazyLock::new(|| {
51 DESCRIPTOR_POOL
52 .get_extension_by_name("buf.validate.message")
53 .ok_or(anyhow!("buf.validate.message extension not found"))
54 .unwrap()
55});
56
57#[allow(clippy::unwrap_used)]
58static BUF_VALIDATE_ONEOF: LazyLock<ExtensionDescriptor> = LazyLock::new(|| {
59 DESCRIPTOR_POOL
60 .get_extension_by_name("buf.validate.oneof")
61 .ok_or(anyhow!("buf.validate.oneof extension not found"))
62 .unwrap()
63});
64
65#[allow(clippy::unwrap_used)]
66static BUF_VALIDATE_FIELD: LazyLock<ExtensionDescriptor> = LazyLock::new(|| {
67 DESCRIPTOR_POOL
68 .get_extension_by_name("buf.validate.field")
69 .ok_or(anyhow!("buf.validate.field extension not found"))
70 .unwrap()
71});
72
73#[allow(clippy::unwrap_used)]
74static BUF_VALIDATE_PREDEFINED: LazyLock<ExtensionDescriptor> = LazyLock::new(|| {
75 DESCRIPTOR_POOL
76 .get_extension_by_name("buf.validate.predefined")
77 .ok_or(anyhow!("buf.validate.predefined extension not found"))
78 .unwrap()
79});
80
81pub trait FieldConstraintsExt {
83 fn field_constraints(&self) -> anyhow::Result<Option<FieldRules>>;
89
90 fn real_oneof(&self) -> Option<OneofDescriptor>;
92
93 fn is_optional(&self) -> bool;
95}
96
97impl FieldConstraintsExt for FieldDescriptor {
98 fn field_constraints(&self) -> anyhow::Result<Option<FieldRules>> {
99 let options = self.options();
100 if !options.has_extension(&BUF_VALIDATE_FIELD) {
101 return Ok(None);
102 }
103 match options.get_extension(&BUF_VALIDATE_FIELD).as_message() {
104 Some(r) => Ok(Some(r.transcode_to::<FieldRules>()?)),
105 None => Ok(None),
106 }
107 }
108
109 fn real_oneof(&self) -> Option<OneofDescriptor> {
110 self.containing_oneof().filter(|o| !o.is_synthetic())
111 }
112
113 fn is_optional(&self) -> bool {
114 self.containing_oneof().is_some_and(|d| d.is_synthetic())
115 }
116}
117
118pub trait OneofConstraintsExt {
120 fn is_required(&self) -> bool;
122}
123
124impl OneofConstraintsExt for OneofDescriptor {
125 fn is_required(&self) -> bool {
126 let options = self.options();
127 if !options.has_extension(&BUF_VALIDATE_ONEOF) {
128 return false;
129 }
130 options
131 .get_extension(&BUF_VALIDATE_ONEOF)
132 .as_message()
133 .and_then(|msg| msg.transcode_to::<OneofRules>().ok())
134 .is_some_and(|rules| rules.required.unwrap_or(false))
135 }
136}
137
138pub trait MessageConstraintsExt {
140 fn message_constraints(&self) -> anyhow::Result<Option<MessageRules>>;
146}
147
148impl MessageConstraintsExt for MessageDescriptor {
149 fn message_constraints(&self) -> anyhow::Result<Option<MessageRules>> {
150 let options = self.options();
151 if !options.has_extension(&BUF_VALIDATE_MESSAGE) {
152 return Ok(None);
153 }
154 match options.get_extension(&BUF_VALIDATE_MESSAGE).as_message() {
155 Some(r) => Ok(Some(r.transcode_to::<MessageRules>()?)),
156 None => Ok(None),
157 }
158 }
159}
160
161pub trait PredefinedConstraintsExt {
163 fn predefined_constraints(&self) -> anyhow::Result<Option<PredefinedRules>>;
169}
170
171impl PredefinedConstraintsExt for FieldDescriptor {
172 fn predefined_constraints(&self) -> anyhow::Result<Option<PredefinedRules>> {
173 let options = self.options();
174 if !options.has_extension(&BUF_VALIDATE_PREDEFINED) {
175 return Ok(None);
176 }
177 match options.get_extension(&BUF_VALIDATE_PREDEFINED).as_message() {
178 Some(r) => Ok(Some(r.transcode_to::<PredefinedRules>()?)),
179 None => Ok(None),
180 }
181 }
182}
183
184pub trait FieldConstraintsDynExt {
187 fn field_constraints_dynamic(&self) -> Option<DynamicMessage>;
189}
190
191impl FieldConstraintsDynExt for FieldDescriptor {
192 fn field_constraints_dynamic(&self) -> Option<DynamicMessage> {
193 let options = self.options();
194 if !options.has_extension(&BUF_VALIDATE_FIELD) {
195 return None;
196 }
197 options
198 .get_extension(&BUF_VALIDATE_FIELD)
199 .as_message()
200 .cloned()
201 }
202}
203
204pub trait MessageConstraintsDynExt {
206 fn message_constraints_dynamic(&self) -> Option<DynamicMessage>;
208}
209
210impl MessageConstraintsDynExt for MessageDescriptor {
211 fn message_constraints_dynamic(&self) -> Option<DynamicMessage> {
212 let options = self.options();
213 if !options.has_extension(&BUF_VALIDATE_MESSAGE) {
214 return None;
215 }
216 options
217 .get_extension(&BUF_VALIDATE_MESSAGE)
218 .as_message()
219 .cloned()
220 }
221}