Skip to main content

protify/
oneof_schema.rs

1use crate::*;
2
3/// Implemented for proxied oneofs by the [`proto_oneof`] macro.
4pub trait ProxiedOneof: From<Self::Proxy> + Into<Self::Proxy> {
5	type Proxy: OneofProxy<Oneof = Self> + From<Self> + Into<Self>;
6
7	/// Converts to the paired proxy.
8	#[inline]
9	fn into_proxy(self) -> Self::Proxy {
10		self.into()
11	}
12}
13
14/// Implemented for oneof proxies by the [`proto_oneof`] macro.
15pub trait OneofProxy: From<Self::Oneof> + Into<Self::Oneof> {
16	type Oneof: ProtoOneof + From<Self> + Into<Self>;
17
18	/// Converts to the paired oneof.
19	#[inline]
20	fn into_oneof(self) -> Self::Oneof {
21		self.into()
22	}
23}
24
25/// Trait responsible for generating the schema representation of a oneof.
26pub trait ProtoOneof {
27	#[doc(hidden)]
28	const TAGS: &[i32];
29
30	/// Returns the protobuf schema representation.
31	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
62/// Trait responsible for executing validators that have been assigned to a oneof.
63///
64/// Implemented by the [`proto_oneof`] macro.
65pub trait ValidatedOneof: ProtoValidation + Clone {
66	/// Executes validation on this oneof, triggering the validators that have been assigned to it
67	/// via macro attributes, if there are any.
68	///
69	/// Uses the default settings for [`ValidationCtx`], which include `fail_fast: true`.
70	#[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	/// Executes validation on this oneof, triggering the validators that have been assigned to it
88	/// via macro attributes, if there are any, and returns true if the validation was successful.
89	///
90	/// Uses the default settings for [`ValidationCtx`], which include `fail_fast: true`.
91	#[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	/// Executes validation on this oneof, triggering the validators that have been assigned to it
101	/// via macro attributes, if there are any, and returns the value if the validation was successful.
102	///
103	/// Uses the default settings for [`ValidationCtx`], which include `fail_fast: true`.
104	#[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	/// Executes validation on this oneof, triggering the validators that have been assigned to it
117	/// via macro attributes, if there are any.
118	fn validate_with_ctx(&self, ctx: &mut ValidationCtx) -> ValidationResult;
119}
120
121/// Schema representation for a protobuf oneof.
122#[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	/// Iterates all the options of the oneof, including those created by the [`ValidatorSchema`]s.
139	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}