1use std::sync::Arc;
18use super::{Cardinality, graph};
21use crate::MessageError;
22use crate::config::SchemaSettings;
23use crate::message::PostcardReader;
24
25#[derive(Clone, Debug)]
34pub struct Validator {
35 root: usize,
36 definitions: Arc<[Box<[Checked]>]>,
37}
38#[derive(Debug)]
39struct Checked {
40 name: Box<str>,
41 tag: u32,
42 cardinality: Cardinality,
43 kind: Wire,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum PathElement<'schema> {
50 Field { name: &'schema str, tag: u32 },
51 Index(usize),
52}
53
54#[derive(Debug, Clone, Copy, PartialEq)]
55pub enum Scalar<'payload> {
56 Bool(bool),
57 U32(u32),
58 U64(u64),
59 I32(i32),
60 I64(i64),
61 F32(f32),
62 F64(f64),
63 String(&'payload str),
64 Bytes(&'payload [u8]),
65}
66
67#[derive(Debug, Clone, Copy, PartialEq)]
68pub enum Event<'payload> {
69 BeginMessage,
70 EndMessage,
71 Optional { present: bool },
72 BeginRepeated { length: usize },
73 EndRepeated,
74 Variant { index: u32 },
75 Scalar(Scalar<'payload>),
76}
77
78#[derive(Debug, thiserror::Error)]
79pub enum VisitError<E> {
80 #[error(transparent)]
81 Payload(#[from] PayloadError),
82
83 #[error("Postcard visitor failed: {0}")]
84 Consumer(#[source] E),
85}
86
87#[derive(Debug)]
88enum Wire {
89 Bool,
90 U32,
91 U64,
92 I32,
93 I64,
94 F32,
95 F64,
96 String,
97 Bytes,
98 Message(usize),
99}
100#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
101#[error(transparent)]
102pub struct PayloadError(#[from] MessageError);
103
104impl Validator {
109 pub fn at(&self, root: usize) -> Result<Self, graph::Error> {
111 if root >= self.definitions.len() {
112 return Err(graph::Error::Reference { definition: root });
113 }
114 Ok(Self { root, definitions: Arc::clone(&self.definitions) })
115 }
116 pub fn construction_memory_bytes(schema: &graph::Schema, settings: &SchemaSettings) -> Result<usize, graph::Error> {
117 schema
118 .preparation(settings)?
119 .bytes
120 .checked_add(graph_compilation_bytes(schema)?)
121 .and_then(|bytes| bytes.checked_add(2 * std::mem::size_of::<usize>()))
122 .and_then(|bytes| {
123 schema
124 .definitions
125 .len()
126 .checked_mul(std::mem::size_of::<Box<[Checked]>>())
127 .and_then(|temporary| bytes.checked_add(temporary))
128 })
129 .ok_or(graph::Error::Budget)
130 }
131 pub fn validate(&self, bytes: &[u8]) -> Result<(), PayloadError> {
132 match self.visit(bytes, |_, _| Ok::<(), std::convert::Infallible>(())) {
133 Ok(()) => Ok(()),
134 Err(VisitError::Payload(error)) => Err(error),
135 Err(VisitError::Consumer(error)) => match error {},
136 }
137 }
138
139 pub fn visit<'schema, 'payload, E>(
140 &'schema self, bytes: &'payload [u8], mut visitor: impl FnMut(&[PathElement<'schema>], Event<'payload>) -> Result<(), E>,
141 ) -> Result<(), VisitError<E>> {
142 let mut input = PostcardReader::new(bytes);
143 let mut path = Vec::new();
144 let mut failure = None;
145 let result = self.read(self.root, &mut input, &mut path, &mut |path, event| {
146 visitor(path, event).map_err(|error| {
147 failure = Some(error);
148 MessageError::borrowed("Postcard consumer failed")
149 })
150 });
151 if let Some(error) = failure {
152 return Err(VisitError::Consumer(error));
153 }
154 result.map_err(PayloadError::from)?;
155 input.finish().map_err(PayloadError::from)?;
156 Ok(())
157 }
158 pub fn from_schema(schema: &graph::Schema, settings: &SchemaSettings) -> Result<Self, graph::Error> {
159 schema.prepare(settings)?;
160 if Self::construction_memory_bytes(schema, settings)? > settings.preparation_bytes.get() {
161 return Err(graph::Error::Budget);
162 }
163 let definitions = schema
164 .definitions
165 .iter()
166 .map(|fields| {
167 fields
168 .iter()
169 .map(|field| Checked {
170 name: field.name.as_ref().into(),
171 tag: field.tag,
172 cardinality: field.cardinality,
173 kind: match field.kind {
174 graph::Kind::Bool => Wire::Bool,
175 graph::Kind::U32 => Wire::U32,
176 graph::Kind::U64 => Wire::U64,
177 graph::Kind::I32 => Wire::I32,
178 graph::Kind::I64 => Wire::I64,
179 graph::Kind::F32 => Wire::F32,
180 graph::Kind::F64 => Wire::F64,
181 graph::Kind::String => Wire::String,
182 graph::Kind::Bytes => Wire::Bytes,
183 graph::Kind::Message { definition } => Wire::Message(definition),
184 },
185 })
186 .collect::<Box<[_]>>()
187 })
188 .collect::<Box<[_]>>();
189 Ok(Self { root: schema.root, definitions: definitions.into() })
190 }
191 fn read<'schema, 'payload>(
192 &'schema self, definition: usize, input: &mut PostcardReader<'payload>, path: &mut Vec<PathElement<'schema>>,
193 visitor: &mut impl FnMut(&[PathElement<'schema>], Event<'payload>) -> Result<(), MessageError>,
194 ) -> Result<(), MessageError> {
195 input.nested(|input| {
196 visitor(path, Event::BeginMessage)?;
197 if self.definitions[definition].first().is_some_and(|field| field.cardinality == Cardinality::Variant) {
198 let index: u32 = input.value()?;
199 let field = self.definitions[definition]
200 .get(index as usize)
201 .ok_or_else(|| MessageError::borrowed("unknown Postcard enum variant"))?;
202 let Wire::Message(payload) = &field.kind else { unreachable!("validated enum schema") };
203 path.push(PathElement::Field { name: &field.name, tag: field.tag });
204 visitor(path, Event::Variant { index })?;
205 visitor(path, Event::BeginMessage)?;
206 self.read_fields(*payload, input, path, visitor)?;
207 visitor(path, Event::EndMessage)?;
208 path.pop();
209 } else {
210 self.read_fields(definition, input, path, visitor)?;
211 }
212 visitor(path, Event::EndMessage)
213 })
214 }
215 fn read_fields<'schema, 'payload>(
216 &'schema self, definition: usize, input: &mut PostcardReader<'payload>, path: &mut Vec<PathElement<'schema>>,
217 visitor: &mut impl FnMut(&[PathElement<'schema>], Event<'payload>) -> Result<(), MessageError>,
218 ) -> Result<(), MessageError> {
219 for field in &self.definitions[definition] {
220 path.push(PathElement::Field { name: &field.name, tag: field.tag });
221 match field.cardinality {
222 Cardinality::Required | Cardinality::Variant => field.kind.read(self, input, path, visitor)?,
223 Cardinality::Optional => input.nested(|input| {
224 let present = input.value::<bool>()?;
225 visitor(path, Event::Optional { present })?;
226 if present {
227 field.kind.read(self, input, path, visitor)?;
228 }
229 Ok(())
230 })?,
231 Cardinality::Repeated => input.nested(|input| {
232 let count: usize = input.value()?;
233 input.claim(count)?;
234 visitor(path, Event::BeginRepeated { length: count })?;
235 for index in 0..count {
236 path.push(PathElement::Index(index));
237 field.kind.read(self, input, path, visitor)?;
238 path.pop();
239 }
240 visitor(path, Event::EndRepeated)
241 })?,
242 }
243 path.pop();
244 }
245 Ok(())
246 }
247}
248impl Wire {
249 fn read<'schema, 'payload>(
250 &'schema self, schema: &'schema Validator, input: &mut PostcardReader<'payload>, path: &mut Vec<PathElement<'schema>>,
251 visitor: &mut impl FnMut(&[PathElement<'schema>], Event<'payload>) -> Result<(), MessageError>,
252 ) -> Result<(), MessageError> {
253 let scalar = match self {
254 Self::Bool => Scalar::Bool(input.value()?),
255 Self::U32 => Scalar::U32(input.value()?),
256 Self::U64 => Scalar::U64(input.value()?),
257 Self::I32 => Scalar::I32(input.value()?),
258 Self::I64 => Scalar::I64(input.value()?),
259 Self::F32 => Scalar::F32(input.value()?),
260 Self::F64 => Scalar::F64(input.value()?),
261 Self::String => Scalar::String(input.value()?),
262 Self::Bytes => Scalar::Bytes(input.nested(|input| {
263 let count = input.value()?;
264 input.take(count)
265 })?),
266 Self::Message(definition) => return schema.read(*definition, input, path, visitor),
267 };
268 visitor(path, Event::Scalar(scalar))
269 }
270}
271impl crate::MemorySize for Validator {
272 fn memory_size(&self) -> usize {
273 let mut bytes = std::mem::size_of::<Self>()
274 .saturating_add(2 * std::mem::size_of::<usize>())
275 .saturating_add(self.definitions.len().saturating_mul(std::mem::size_of::<Box<[Checked]>>()));
276 for fields in self.definitions.iter() {
277 bytes = bytes.saturating_add(fields.len().saturating_mul(std::mem::size_of::<Checked>()));
278 for field in fields {
279 bytes = bytes.saturating_add(field.name.len());
280 }
281 }
282 bytes
283 }
284}
285
286fn graph_compilation_bytes(schema: &graph::Schema) -> Result<usize, graph::Error> {
291 let mut bytes = std::mem::size_of::<Validator>()
292 .checked_add(schema.definitions.len().checked_mul(std::mem::size_of::<Box<[Checked]>>()).ok_or(graph::Error::Budget)?)
293 .ok_or(graph::Error::Budget)?;
294 for fields in &schema.definitions {
295 bytes = bytes
296 .checked_add(fields.len().checked_mul(std::mem::size_of::<Checked>()).ok_or(graph::Error::Budget)?)
297 .ok_or(graph::Error::Budget)?;
298 for field in fields {
299 bytes = bytes.checked_add(field.name.len()).ok_or(graph::Error::Budget)?;
300 }
301 }
302 Ok(bytes)
303}
304
305