1use crate::*;
2
3pub trait ProxiedOneof: From<Self::Proxy> + Into<Self::Proxy> {
5 type Proxy: OneofProxy<Oneof = Self> + From<Self> + Into<Self>;
6
7 #[inline]
9 fn into_proxy(self) -> Self::Proxy {
10 self.into()
11 }
12}
13
14pub trait OneofProxy: From<Self::Oneof> + Into<Self::Oneof> {
16 type Oneof: ProtoOneof + From<Self> + Into<Self>;
17
18 #[inline]
20 fn into_oneof(self) -> Self::Oneof {
21 self.into()
22 }
23}
24
25pub trait ProtoOneof {
27 #[doc(hidden)]
28 const TAGS: &[i32];
29
30 fn proto_schema() -> Oneof;
32
33 #[doc(hidden)]
34 fn __check_tags(
35 message_name: &str,
36 oneof_name: &str,
37 found_tags: &mut [i32],
38 ) -> Result<(), String> {
39 use similar_asserts::SimpleDiff;
40
41 let expected = Self::TAGS;
42
43 found_tags.sort_unstable();
44
45 if expected != found_tags {
46 let exp_str = format!("{expected:#?}");
47 let found_str = format!("{found_tags:#?}");
48
49 let diff = SimpleDiff::from_str(&exp_str, &found_str, "expected", "found");
50
51 let error = format!(
52 "Found tags mismatch for oneof {oneof_name} in message {message_name}:\n{diff}"
53 );
54
55 return Err(error);
56 }
57
58 Ok(())
59 }
60}
61
62pub trait ValidatedOneof: ProtoValidation + Clone {
66 #[inline]
71 fn validate(&self) -> Result<(), ValidationErrors> {
72 if !Self::HAS_DEFAULT_VALIDATOR {
73 return Ok(());
74 }
75
76 let mut ctx = ValidationCtx::default();
77
78 let _ = self.validate_with_ctx(&mut ctx);
79
80 if ctx.violations.is_empty() {
81 Ok(())
82 } else {
83 Err(ctx.violations)
84 }
85 }
86
87 #[inline]
92 fn is_valid(&self) -> bool {
93 if Self::HAS_DEFAULT_VALIDATOR {
94 self.validate().is_ok()
95 } else {
96 true
97 }
98 }
99
100 #[inline]
105 fn validated(self) -> Result<Self, ValidationErrors> {
106 if !Self::HAS_DEFAULT_VALIDATOR {
107 return Ok(self);
108 }
109
110 match self.validate() {
111 Ok(()) => Ok(self),
112 Err(e) => Err(e),
113 }
114 }
115
116 fn validate_with_ctx(&self, ctx: &mut ValidationCtx) -> ValidationResult;
119}
120
121#[derive(Debug, Default, Clone, PartialEq, Builder)]
123#[non_exhaustive]
124#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
125pub struct Oneof {
126 pub name: FixedStr,
127 pub fields: Vec<Field>,
128 pub options: Vec<ProtoOption>,
129 pub validators: Vec<ValidatorSchema>,
130}
131
132impl Oneof {
133 #[must_use]
134 pub(crate) const fn has_options(&self) -> bool {
135 !self.options.is_empty() || !self.validators.is_empty()
136 }
137
138 pub fn options_with_validators(&self) -> impl Iterator<Item = &options::ProtoOption> {
140 self.options
141 .iter()
142 .chain(self.validators.iter().map(|v| &v.schema))
143 }
144
145 #[doc(hidden)]
146 #[must_use]
147 #[inline]
148 pub fn with_name(mut self, name: impl Into<FixedStr>) -> Self {
149 self.name = name.into();
150 self
151 }
152
153 #[doc(hidden)]
154 #[must_use]
155 #[inline]
156 pub fn with_validators(mut self, mut validators: Vec<ValidatorSchema>) -> Self {
157 self.validators.append(&mut validators);
158 self
159 }
160
161 #[doc(hidden)]
162 #[must_use]
163 #[inline]
164 pub fn with_options(mut self, mut options: Vec<ProtoOption>) -> Self {
165 self.options.append(&mut options);
166 self
167 }
168}