1mod codec;
15
16use std::borrow::Cow;
22use std::collections::HashSet;
23use std::fmt;
24use std::mem::size_of;
25use serde::de::{DeserializeSeed, Error as _, MapAccess, SeqAccess, Visitor};
27use serde::{Deserialize, Deserializer, Serialize};
28use super::{Cardinality, MAX_NAME_BYTES, diagnostic_name};
30use crate::config::SchemaSettings;
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
41pub struct Schema {
42 pub root: usize,
43 pub definitions: Vec<Vec<Field>>,
44}
45
46#[derive(Clone, Copy, Debug)]
47pub struct View<'a> {
48 schema: &'a Schema,
49 root: usize,
50}
51
52#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
53#[serde(deny_unknown_fields)]
54pub struct Field<R = usize> {
55 #[serde(deserialize_with = "name")]
56 pub name: Cow<'static, str>,
57
58 pub tag: u32,
59 pub kind: Kind<R>,
60 pub cardinality: Cardinality,
61}
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq)]
64pub struct Preparation {
65 pub definitions: usize,
66 pub fields: usize,
67 pub bytes: usize,
68 pub work: usize,
69}
70
71pub struct Seed<'a> {
72 pub settings: &'a SchemaSettings,
73}
74
75struct DefinitionsSeed<'a>(&'a mut Budget);
76struct DefinitionSeed<'a>(&'a mut Budget);
77struct FieldSeed<'a>(&'a mut Budget);
78struct Budget {
79 remaining: usize,
80}
81
82#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
85#[serde(tag = "type", rename_all = "snake_case")]
86pub enum Kind<R = usize> {
87 Bool,
88 U32,
89 U64,
90 I32,
91 I64,
92 F32,
93 F64,
94 String,
95 Bytes,
96 Message { definition: R },
97}
98
99#[derive(Debug, thiserror::Error)]
100pub enum Error {
101 #[error("schema preparation exceeds its memory or work allowance")]
102 Budget,
103
104 #[error("schema definition {definition} is absent")]
105 Reference { definition: usize },
106
107 #[error("schema definition {definition} is unreachable")]
108 Unreachable { definition: usize },
109
110 #[error("invalid schema field `{field}`: {reason}")]
111 Field { field: String, reason: &'static str },
112}
113
114impl<R> Kind<R> {
119 pub(crate) fn try_map<S, E>(self, reference: impl FnOnce(R) -> Result<S, E>) -> Result<Kind<S>, E> {
120 Ok(match self {
121 Self::Bool => Kind::Bool,
122 Self::U32 => Kind::U32,
123 Self::U64 => Kind::U64,
124 Self::I32 => Kind::I32,
125 Self::I64 => Kind::I64,
126 Self::F32 => Kind::F32,
127 Self::F64 => Kind::F64,
128 Self::String => Kind::String,
129 Self::Bytes => Kind::Bytes,
130 Self::Message { definition } => Kind::Message { definition: reference(definition)? },
131 })
132 }
133}
134
135impl<'de, R: Deserialize<'de>> Deserialize<'de> for Kind<R> {
136 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
137 #[derive(Deserialize)]
138 #[serde(deny_unknown_fields, bound(deserialize = "R: Deserialize<'de>"))]
139 struct Input<R> {
140 #[serde(rename = "type", deserialize_with = "kind_name")]
141 kind: String,
142
143 #[serde(default, deserialize_with = "definition")]
144 definition: Option<R>,
145 }
146 let input = Input::<R>::deserialize(deserializer)?;
147 if input.kind == "message" {
148 return input.definition.map(|definition| Self::Message { definition }).ok_or_else(|| D::Error::missing_field("definition"));
149 }
150 if input.definition.is_some() {
151 return Err(D::Error::custom("scalar schema kind cannot reference a definition"));
152 }
153 match input.kind.as_str() {
154 "bool" => Ok(Self::Bool),
155 "u32" => Ok(Self::U32),
156 "u64" => Ok(Self::U64),
157 "i32" => Ok(Self::I32),
158 "i64" => Ok(Self::I64),
159 "f32" => Ok(Self::F32),
160 "f64" => Ok(Self::F64),
161 "string" => Ok(Self::String),
162 "bytes" => Ok(Self::Bytes),
163 _ => Err(D::Error::custom("unknown schema kind")),
164 }
165 }
166}
167
168impl crate::MemorySize for Schema {
169 fn memory_size(&self) -> usize {
170 let mut bytes = size_of::<Self>().saturating_add(self.definitions.capacity().saturating_mul(size_of::<Vec<Field>>()));
171 for fields in &self.definitions {
172 bytes = bytes.saturating_add(fields.capacity().saturating_mul(size_of::<Field>()));
173 for field in fields {
174 if let Cow::Owned(name) = &field.name {
175 bytes = bytes.saturating_add(name.capacity());
176 }
177 }
178 }
179 bytes
180 }
181}
182
183impl Schema {
184 pub fn clone_memory_bytes(&self) -> Result<usize, Error> {
185 let mut bytes = self
186 .definitions
187 .len()
188 .checked_mul(size_of::<Vec<Field>>())
189 .and_then(|bytes| bytes.checked_add(size_of::<Self>()))
190 .ok_or(Error::Budget)?;
191 for fields in &self.definitions {
192 bytes = fields.len().checked_mul(size_of::<Field>()).and_then(|fields| bytes.checked_add(fields)).ok_or(Error::Budget)?;
193 for field in fields {
194 if let Cow::Owned(name) = &field.name {
195 bytes = bytes.checked_add(name.len()).ok_or(Error::Budget)?;
196 }
197 }
198 }
199 Ok(bytes)
200 }
201
202 pub fn validation_memory_bytes(&self, settings: &SchemaSettings) -> Result<usize, Error> {
203 let preparation = self.preparation(settings)?;
204 preparation.bytes.checked_sub(crate::MemorySize::memory_size(self)).ok_or(Error::Budget)
205 }
206
207 pub fn view(&self, root: usize) -> Result<View<'_>, Error> {
208 if root >= self.definitions.len() {
209 return Err(Error::Reference { definition: root });
210 }
211 Ok(View { schema: self, root })
212 }
213
214 pub fn root(&self) -> Result<View<'_>, Error> {
215 self.view(self.root)
216 }
217
218 pub fn equivalent(&self, root: usize, other: &Self, other_root: usize, settings: &SchemaSettings) -> Result<bool, Error> {
220 let mut preparation = self.prepare(settings)?;
221 let right = other.prepare(settings)?;
222 if root >= self.definitions.len() {
223 return Err(Error::Reference { definition: root });
224 }
225 if other_root >= other.definitions.len() {
226 return Err(Error::Reference { definition: other_root });
227 }
228 if !std::ptr::eq(self, other) {
229 preparation.add_bytes(right.bytes, 1, settings)?;
230 preparation.add_work(right.work, settings)?;
231 }
232 preparation.add_bytes(4, size_of::<(usize, usize)>(), settings)?;
233 let mut pending = vec![(root, other_root)];
234 let mut visited = HashSet::new();
235 while let Some((left, right)) = pending.pop() {
236 preparation.add_work(1, settings)?;
237 if visited.contains(&(left, right)) {
238 continue;
239 }
240 preparation.add_bytes(4, size_of::<(usize, usize)>(), settings)?;
241 visited.insert((left, right));
242 let left = &self.definitions[left];
243 let right = &other.definitions[right];
244 if left.len() != right.len() {
245 return Ok(false);
246 }
247 for (left, right) in left.iter().zip(right) {
248 preparation.add_work(left.name.len() + 1, settings)?;
249 if left.name != right.name || left.tag != right.tag || left.cardinality != right.cardinality {
250 return Ok(false);
251 }
252 match (left.kind, right.kind) {
253 (Kind::Message { definition: left }, Kind::Message { definition: right }) => {
254 preparation.add_bytes(4, size_of::<(usize, usize)>(), settings)?;
255 pending.push((left, right));
256 }
257 (left, right) if left == right => {}
258 _ => return Ok(false),
259 }
260 }
261 }
262 Ok(true)
263 }
264
265 pub fn preparation(&self, settings: &SchemaSettings) -> Result<Preparation, Error> {
266 if self.root >= self.definitions.len() {
267 return Err(Error::Reference { definition: self.root });
268 }
269 let mut preparation = Preparation {
270 definitions: self.definitions.len(),
271 fields: 0,
272 bytes: size_of::<Self>(),
273 work: 0,
274 };
275 preparation.add_bytes(self.definitions.capacity(), size_of::<Vec<Field>>(), settings)?;
277 preparation.add_bytes(self.definitions.len(), size_of::<bool>() + size_of::<usize>(), settings)?;
278 for fields in &self.definitions {
279 preparation.fields = preparation.fields.checked_add(fields.len()).ok_or(Error::Budget)?;
280 preparation.add_bytes(fields.capacity(), size_of::<Field>(), settings)?;
281 preparation.add_work(fields.len() + 1, settings)?;
282 for field in fields {
283 if let Cow::Owned(name) = &field.name {
284 preparation.add_bytes(name.capacity(), 1, settings)?;
285 }
286 preparation.add_work(field.name.len(), settings)?;
287 }
288 }
289 let scratch = self.definitions.iter().map(|fields| fields.len()).max().unwrap_or(0);
290 preparation.add_bytes(scratch, size_of::<&str>() + size_of::<u32>(), settings)?;
291 for fields in &self.definitions {
292 let bits = usize::BITS as usize - fields.len().leading_zeros() as usize;
293 let work = fields.len().checked_mul(2 * bits + 2).ok_or(Error::Budget)?;
294 preparation.add_work(work, settings)?;
295 }
296 preparation.add_work(self.definitions.len(), settings)?;
297 preparation.add_work(preparation.fields, settings)?;
298 Ok(preparation)
299 }
300
301 pub fn prepare(&self, settings: &SchemaSettings) -> Result<Preparation, Error> {
302 let preparation = self.preparation(settings)?;
303 for fields in &self.definitions {
304 let mut names = Vec::with_capacity(fields.len());
306 let mut tags = Vec::with_capacity(fields.len());
307 let variants = fields.iter().any(|field| field.cardinality == Cardinality::Variant);
308 for field in fields {
309 let invalid = |reason| Error::Field {
310 field: diagnostic_name(&field.name),
311 reason,
312 };
313 if variants && (field.cardinality != Cardinality::Variant || !matches!(field.kind, Kind::Message { .. })) {
314 return Err(invalid("an enum schema requires only message-valued variants"));
315 }
316 if field.name.is_empty() || field.name.len() > MAX_NAME_BYTES || field.name.chars().any(char::is_control) {
317 return Err(invalid("name must be nonempty, at most 256 bytes, and contain no control characters"));
318 }
319 if field.tag == 0 || field.tag > 536_870_911 || (19_000..=19_999).contains(&field.tag) {
320 return Err(invalid("invalid protobuf tag"));
321 }
322 if let Kind::Message { definition } = field.kind
323 && definition >= self.definitions.len()
324 {
325 return Err(Error::Reference { definition });
326 }
327 names.push(field.name.as_ref());
328 tags.push(field.tag);
329 }
330 names.sort_unstable();
331 tags.sort_unstable();
332 if let Some(pair) = names.windows(2).find(|pair| pair[0] == pair[1]) {
333 return Err(Error::Field {
334 field: diagnostic_name(pair[0]),
335 reason: "duplicate name",
336 });
337 }
338 if let Some(pair) = tags.windows(2).find(|pair| pair[0] == pair[1]) {
339 let field = fields.iter().find(|field| field.tag == pair[0]).unwrap();
340 return Err(Error::Field {
341 field: diagnostic_name(&field.name),
342 reason: "duplicate protobuf tag",
343 });
344 }
345 }
346 let mut reached = vec![false; self.definitions.len()];
347 let mut pending = Vec::with_capacity(self.definitions.len());
348 reached[self.root] = true;
349 pending.push(self.root);
350 while let Some(definition) = pending.pop() {
351 for field in &self.definitions[definition] {
352 if let Kind::Message { definition } = field.kind
353 && !reached[definition]
354 {
355 reached[definition] = true;
356 pending.push(definition);
357 }
358 }
359 }
360 if let Some(definition) = reached.iter().position(|reached| !reached) {
361 return Err(Error::Unreachable { definition });
362 }
363 Ok(preparation)
364 }
365}
366
367impl<'a> View<'a> {
368 pub fn schema(self) -> &'a Schema {
369 self.schema
370 }
371 pub fn index(self) -> usize {
372 self.root
373 }
374 pub fn fields(self) -> &'a [Field] {
375 &self.schema.definitions[self.root]
376 }
377
378 pub fn message(self, field: &Field) -> Result<Option<Self>, Error> {
379 match field.kind {
380 Kind::Message { definition } => self.schema.view(definition).map(Some),
381 _ => Ok(None),
382 }
383 }
384}
385
386impl Preparation {
387 fn add_bytes(&mut self, count: usize, size: usize, settings: &SchemaSettings) -> Result<(), Error> {
388 self.bytes = count.checked_mul(size).and_then(|bytes| self.bytes.checked_add(bytes)).ok_or(Error::Budget)?;
389 if self.bytes > settings.preparation_bytes.get() {
390 return Err(Error::Budget);
391 }
392 Ok(())
393 }
394
395 fn add_work(&mut self, work: usize, settings: &SchemaSettings) -> Result<(), Error> {
396 self.work = self.work.checked_add(work).ok_or(Error::Budget)?;
397 if self.work > settings.preparation_work.get() {
398 return Err(Error::Budget);
399 }
400 Ok(())
401 }
402}
403
404impl<'de> Deserialize<'de> for Schema {
405 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
406 Seed { settings: &SchemaSettings::default() }.deserialize(deserializer)
407 }
408}
409
410impl<'de> DeserializeSeed<'de> for Seed<'_> {
411 type Value = Schema;
412 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Schema, D::Error> {
413 struct Input<'a>(&'a SchemaSettings);
414 impl<'de> Visitor<'de> for Input<'_> {
415 type Value = Schema;
416 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
417 formatter.write_str("a bounded shared message schema")
418 }
419 fn visit_map<A: MapAccess<'de>>(self, mut input: A) -> Result<Schema, A::Error> {
420 let mut root = None;
421 let mut definitions = None;
422 let mut budget = Budget {
423 remaining: self.0.preparation_bytes.get(),
424 };
425 while let Some(key) = input.next_key::<String>()? {
426 match key.as_str() {
427 "root" => {
428 if root.is_some() {
429 return Err(A::Error::duplicate_field("root"));
430 }
431 root = Some(input.next_value()?);
432 }
433 "definitions" => {
434 if definitions.is_some() {
435 return Err(A::Error::duplicate_field("definitions"));
436 }
437 definitions = Some(input.next_value_seed(DefinitionsSeed(&mut budget))?);
438 }
439 _ => return Err(A::Error::unknown_field(&key, &["root", "definitions"])),
440 }
441 }
442 let schema = Schema {
443 root: root.ok_or_else(|| A::Error::missing_field("root"))?,
444 definitions: definitions.ok_or_else(|| A::Error::missing_field("definitions"))?,
445 };
446 schema.prepare(self.0).map_err(A::Error::custom)?;
447 Ok(schema)
448 }
449 }
450 deserializer.deserialize_map(Input(self.settings))
451 }
452}
453
454impl Budget {
455 fn charge<E: serde::de::Error>(&mut self, bytes: usize) -> Result<(), E> {
456 self.remaining = self.remaining.checked_sub(bytes).ok_or_else(|| E::custom(Error::Budget))?;
457 Ok(())
458 }
459}
460
461impl<'de> DeserializeSeed<'de> for DefinitionsSeed<'_> {
462 type Value = Vec<Vec<Field>>;
463 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
464 deserializer.deserialize_seq(self)
465 }
466}
467
468impl<'de> DeserializeSeed<'de> for DefinitionSeed<'_> {
469 type Value = Vec<Field>;
470 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
471 deserializer.deserialize_seq(self)
472 }
473}
474
475impl<'de> DeserializeSeed<'de> for FieldSeed<'_> {
476 type Value = Field;
477 fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> {
478 self.0.charge::<D::Error>(4 * size_of::<Field>() + size_of::<&str>() + size_of::<u32>() + MAX_NAME_BYTES)?;
480 Field::deserialize(deserializer)
481 }
482}
483
484impl<'de> Visitor<'de> for DefinitionsSeed<'_> {
485 type Value = Vec<Vec<Field>>;
486 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
487 formatter.write_str("bounded message definitions")
488 }
489 fn visit_seq<A: SeqAccess<'de>>(self, mut input: A) -> Result<Self::Value, A::Error> {
490 let mut definitions = Vec::new();
491 while let Some(fields) = input.next_element_seed(DefinitionSeed(self.0))? {
492 definitions.push(fields);
493 }
494 Ok(definitions)
495 }
496}
497
498impl<'de> Visitor<'de> for DefinitionSeed<'_> {
499 type Value = Vec<Field>;
500 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
501 formatter.write_str("bounded direct message fields")
502 }
503 fn visit_seq<A: SeqAccess<'de>>(self, mut input: A) -> Result<Self::Value, A::Error> {
504 self.0.charge::<A::Error>(4 * size_of::<Vec<Field>>() + size_of::<usize>() + size_of::<bool>())?;
505 let mut fields = Vec::new();
506 while let Some(field) = input.next_element_seed(FieldSeed(self.0))? {
507 fields.push(field);
508 }
509 Ok(fields)
510 }
511}
512
513fn definition<'de, D: Deserializer<'de>, R: Deserialize<'de>>(deserializer: D) -> Result<Option<R>, D::Error> {
518 R::deserialize(deserializer).map(Some)
519}
520
521fn kind_name<'de, D: Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> {
522 name(deserializer).map(Cow::into_owned)
523}
524
525fn name<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Cow<'static, str>, D::Error> {
526 struct Name;
527 impl<'de> Visitor<'de> for Name {
528 type Value = String;
529 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
530 formatter.write_str("a field name of at most 256 bytes")
531 }
532 fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<String, E> {
533 if value.len() > MAX_NAME_BYTES {
534 return Err(E::custom("schema field name exceeds 256 bytes"));
535 }
536 Ok(value.to_owned())
537 }
538 fn visit_string<E: serde::de::Error>(self, value: String) -> Result<String, E> {
539 if value.len() > MAX_NAME_BYTES {
540 return Err(E::custom("schema field name exceeds 256 bytes"));
541 }
542 Ok(value)
543 }
544 }
545 deserializer.deserialize_string(Name).map(Cow::Owned)
546}
547
548