1use std::any::TypeId;
20use std::collections::HashMap;
21use std::fmt;
22use std::mem::size_of;
23use serde::{Deserialize, Serialize};
25use super::graph::{self, Error, Schema};
27use super::{Cardinality, MAX_NAME_BYTES};
28use crate::config::SchemaSettings;
29use crate::inventory::{digits, number, quoted, quoted_len, write};
30
31const HEADER: &[u8] = b"{\"kind\":\"schema\",\"name\":";
34const FIELDS: &[u8] = b",\"fields\":[";
35const NAME: &[u8] = b"{\"name\":";
36const TAG: &[u8] = b",\"tag\":";
37const KIND: &[u8] = b",\"kind\":{\"type\":";
38const REFERENCE: &[u8] = b",\"definition\":";
39const CARDINALITY: &[u8] = b"},\"cardinality\":";
40
41pub type Field<R = Definition> = graph::Field<R>;
46pub type Kind<R = Definition> = graph::Kind<R>;
47
48#[derive(Clone, Copy)]
51pub struct Definition {
52 pub name: &'static str,
53
54 pub default_variant: Option<usize>,
55
56 pub identity: fn() -> TypeId,
57 pub fields: fn() -> &'static [Field<Definition>],
58 pub marker: fn() -> &'static [u8],
59}
60
61#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
62#[serde(from = "Fragment", into = "Fragment")]
63pub struct Named {
64 pub name: String,
65 pub fields: Vec<Field<String>>,
66}
67
68pub struct Name {
70 bytes: [u8; MAX_NAME_BYTES],
71 length: usize,
72}
73
74struct Plan {
75 declarations: Vec<Definition>,
76 indices: HashMap<&'static str, usize>,
77 remaining_bytes: usize,
78 remaining_work: usize,
79}
80
81#[derive(Serialize, Deserialize)]
84#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
85enum Fragment {
86 Schema { name: String, fields: Vec<Field<String>> },
87}
88
89impl PartialEq for Definition {
94 fn eq(&self, other: &Self) -> bool {
95 self.name == other.name && (self.identity)() == (other.identity)()
96 }
97}
98impl Eq for Definition {}
99
100impl Name {
101 pub const fn new(owner: &str, arguments: &[&str]) -> Self {
102 let mut name = Self { bytes: [0; MAX_NAME_BYTES], length: 0 };
103 name.push(owner);
104 if !arguments.is_empty() {
105 name.push("<");
106 let mut index = 0;
107 while index < arguments.len() {
108 if index > 0 {
109 name.push(",");
110 }
111 name.push(arguments[index]);
112 index += 1;
113 }
114 name.push(">");
115 }
116 name
117 }
118
119 pub const fn as_str(&self) -> &str {
120 match std::str::from_utf8(self.bytes.split_at(self.length).0) {
121 Ok(name) => name,
122 Err(_) => panic!("schema names originate from valid UTF-8"),
123 }
124 }
125
126 const fn push(&mut self, part: &str) {
127 assert!(part.len() <= MAX_NAME_BYTES - self.length, "schema name exceeds its bound");
128 let mut index = 0;
129 while index < part.len() {
130 self.bytes[self.length] = part.as_bytes()[index];
131 self.length += 1;
132 index += 1;
133 }
134 }
135}
136
137impl Definition {
138 pub const fn of<T: super::Described + ?Sized>() -> Self {
139 Self {
140 name: T::NAME,
141 default_variant: T::DEFAULT_VARIANT,
142 identity: TypeId::of::<T>,
143 fields: fields::<T>,
144 marker: marker::<T>,
145 }
146 }
147}
148
149impl Named {
150 pub fn decode<'a>(fragments: impl IntoIterator<Item = &'a [u8]>, settings: &SchemaSettings) -> Result<Vec<Self>, Error> {
151 let mut budget = Plan::new(settings);
152 let mut declarations = Vec::new();
153 for encoded in fragments {
154 if encoded.len() > crate::FRAGMENT_LIMIT {
155 return Err(Error::Budget);
156 }
157 budget.charge(encoded.len().checked_mul(8).ok_or(Error::Budget)? + 4 * size_of::<Self>(), encoded.len() + 1)?;
159 let declaration: Self = serde_json::from_slice(encoded).map_err(|_| Error::Field {
160 field: "schema fragment".into(),
161 reason: "invalid schema metadata",
162 })?;
163 declarations.push(declaration);
164 }
165 Ok(declarations)
166 }
167}
168
169impl From<Fragment> for Named {
170 fn from(fragment: Fragment) -> Self {
171 let Fragment::Schema { name, fields } = fragment;
172 Self { name, fields }
173 }
174}
175impl From<Named> for Fragment {
176 fn from(named: Named) -> Self {
177 Self::Schema { name: named.name, fields: named.fields }
178 }
179}
180
181impl fmt::Debug for Definition {
182 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
183 formatter.debug_struct("Definition").field("name", &self.name).finish_non_exhaustive()
184 }
185}
186
187impl Schema {
188 pub fn from_named(root: &str, declarations: &[Named], settings: &SchemaSettings) -> Result<Self, Error> {
190 resolve_named(&[("", root)], declarations, settings, false)
191 }
192
193 pub fn from_named_roots(roots: &[(&str, &str)], declarations: &[Named], settings: &SchemaSettings) -> Result<Self, Error> {
195 resolve_named(roots, declarations, settings, true)
196 }
197
198 pub fn from_declaration(root: Definition, settings: &SchemaSettings) -> Result<Self, Error> {
199 let mut plan = Plan::new(settings);
200 plan.insert(root)?;
201 let schema = Self { root: 0, definitions: plan.compile()? };
202 schema.prepare(settings)?;
203 Ok(schema)
204 }
205
206 pub fn from_declarations(roots: &[(&str, Definition)], settings: &SchemaSettings) -> Result<Self, Error> {
208 let mut plan = Plan::new(settings);
209 plan.charge(4 * size_of::<Vec<Field>>() + size_of::<Self>(), 1)?;
210 let mut fields = Vec::new();
211 for (index, (name, declaration)) in roots.iter().enumerate() {
212 plan.charge(4 * size_of::<Field<usize>>() + name.len(), name.len() + 1)?;
213 let tag = u32::try_from(index + 1).map_err(|_| Error::Budget)?;
214 fields.push(Field {
215 name: (*name).to_owned().into(),
216 tag,
217 kind: Kind::Message { definition: plan.insert(*declaration)? },
218 cardinality: Cardinality::Required,
219 });
220 }
221 let mut definitions = plan.compile()?;
222 let root = definitions.len();
223 definitions.push(fields);
224 let schema = Self { root, definitions };
225 schema.prepare(settings)?;
226 Ok(schema)
227 }
228}
229
230impl Plan {
231 fn compile(mut self) -> Result<Vec<Vec<Field<usize>>>, Error> {
232 let mut definitions = Vec::new();
233 let mut index = 0;
234 while index < self.declarations.len() {
235 let declaration = self.declarations[index];
236 let mut fields = Vec::new();
237 for field in (declaration.fields)() {
238 self.charge(4 * size_of::<Field<usize>>() + field.name.len(), field.name.len() + 1)?;
239 let kind = field.kind.try_map(|definition| self.insert(definition))?;
240 fields.push(Field {
241 name: field.name.to_string().into(),
242 tag: field.tag,
243 kind,
244 cardinality: field.cardinality,
245 });
246 }
247 definitions.push(fields);
248 index += 1;
249 }
250 Ok(definitions)
251 }
252 fn new(settings: &SchemaSettings) -> Self {
253 Self {
254 declarations: Vec::new(),
255 indices: HashMap::new(),
256 remaining_bytes: settings.preparation_bytes.get(),
257 remaining_work: settings.preparation_work.get(),
258 }
259 }
260 fn charge(&mut self, bytes: usize, work: usize) -> Result<(), Error> {
261 self.remaining_bytes = self.remaining_bytes.checked_sub(bytes).ok_or(Error::Budget)?;
262 self.remaining_work = self.remaining_work.checked_sub(work).ok_or(Error::Budget)?;
263 Ok(())
264 }
265 fn insert(&mut self, definition: Definition) -> Result<usize, Error> {
266 self.charge(0, definition.name.len() + 1)?;
267 if definition.name.is_empty() || definition.name.len() > MAX_NAME_BYTES || definition.name.chars().any(char::is_control) {
268 return Err(Error::Field {
269 field: super::diagnostic_name(definition.name),
270 reason: "invalid schema definition name",
271 });
272 }
273 if let Some(index) = self.indices.get(definition.name).copied() {
274 let original = self.declarations[index];
275 if (original.identity)() != (definition.identity)() {
276 return Err(Error::Field {
277 field: definition.name.into(),
278 reason: "schema definition name has multiple owners",
279 });
280 }
281 return Ok(index);
282 }
283 self.charge(4 * (size_of::<Definition>() + size_of::<Vec<Field>>() + size_of::<(&str, usize)>() + 1), 1)?;
284 let index = self.declarations.len();
285 self.declarations.push(definition);
286 self.indices.insert(definition.name, index);
287 Ok(index)
288 }
289}
290
291pub fn markers(root: Definition, settings: &SchemaSettings) -> Result<Vec<&'static [u8]>, Error> {
294 markers_many([root], settings)
295}
296
297pub fn markers_many(roots: impl IntoIterator<Item = Definition>, settings: &SchemaSettings) -> Result<Vec<&'static [u8]>, Error> {
298 let mut plan = Plan::new(settings);
299 for root in roots {
300 plan.insert(root)?;
301 }
302 let mut index = 0;
303 while index < plan.declarations.len() {
304 let declaration = plan.declarations[index];
305 for field in (declaration.fields)() {
306 plan.charge(0, 1)?;
307 if let Kind::Message { definition } = field.kind {
308 plan.insert(definition)?;
309 }
310 }
311 index += 1;
312 }
313 let output_bytes = plan.declarations.len().checked_mul(std::mem::size_of::<&[u8]>()).ok_or(Error::Budget)?;
314 plan.charge(output_bytes, 0)?;
315 Ok(plan.declarations.iter().map(|definition| (definition.marker)()).collect())
316}
317
318pub const fn encoded_len(name: &str, fields: &[Field<Definition>]) -> usize {
319 let mut length = crate::PREFIX.len() + HEADER.len() + quoted_len(name) + FIELDS.len() + 3;
320 let mut index = 0;
321 while index < fields.len() {
322 let field = &fields[index];
323 length += NAME.len()
324 + quoted_len(field_name(field))
325 + TAG.len()
326 + digits(field.tag as u64)
327 + KIND.len()
328 + quoted_len(kind_name(&field.kind))
329 + CARDINALITY.len()
330 + quoted_len(cardinality_name(field.cardinality))
331 + 1;
332 if let Kind::Message { definition } = &field.kind {
333 length += REFERENCE.len() + quoted_len(definition.name);
334 }
335 if index > 0 {
336 length += 1;
337 }
338 index += 1;
339 }
340 assert!(length - crate::PREFIX.len() - 1 <= crate::FRAGMENT_LIMIT);
341 length
342}
343
344pub const fn encode<const N: usize>(name: &str, fields: &[Field<Definition>]) -> [u8; N] {
345 assert!(N == encoded_len(name, fields));
346 encode_buffer(name, fields)
347}
348
349pub const fn encode_buffer<const N: usize>(name: &str, fields: &[Field<Definition>]) -> [u8; N] {
352 assert!(N >= encoded_len(name, fields), "schema marker exceeds its static storage");
353 let mut output = [0; N];
354 let mut cursor = 0;
355 write(&mut output, &mut cursor, crate::PREFIX);
356 write(&mut output, &mut cursor, HEADER);
357 quoted(&mut output, &mut cursor, name);
358 write(&mut output, &mut cursor, FIELDS);
359 let mut index = 0;
360 while index < fields.len() {
361 let field = &fields[index];
362 if index > 0 {
363 write(&mut output, &mut cursor, b",");
364 }
365 write(&mut output, &mut cursor, NAME);
366 quoted(&mut output, &mut cursor, field_name(field));
367 write(&mut output, &mut cursor, TAG);
368 number(&mut output, &mut cursor, field.tag as u64);
369 write(&mut output, &mut cursor, KIND);
370 quoted(&mut output, &mut cursor, kind_name(&field.kind));
371 if let Kind::Message { definition } = &field.kind {
372 write(&mut output, &mut cursor, REFERENCE);
373 quoted(&mut output, &mut cursor, definition.name);
374 }
375 write(&mut output, &mut cursor, CARDINALITY);
376 quoted(&mut output, &mut cursor, cardinality_name(field.cardinality));
377 write(&mut output, &mut cursor, b"}");
378 index += 1;
379 }
380 write(&mut output, &mut cursor, b"]}\0");
381 assert!(cursor == encoded_len(name, fields));
382 output
383}
384
385fn fields<T: super::Described + ?Sized>() -> &'static [Field<Definition>] {
388 T::FIELDS
389}
390
391fn marker<T: super::Described + ?Sized>() -> &'static [u8] {
392 T::MARKER
393}
394
395fn resolve_named(roots: &[(&str, &str)], declarations: &[Named], settings: &SchemaSettings, composite: bool) -> Result<Schema, Error> {
396 let mut budget = Plan::new(settings);
397 let mut dictionary = HashMap::new();
398 for declaration in declarations {
399 let name = declaration.name.as_str();
400 budget.charge(4 * size_of::<(&str, &Named)>() + name.len(), name.len() + 1)?;
401 if name.is_empty() || name.len() > MAX_NAME_BYTES || name.chars().any(char::is_control) {
402 return Err(Error::Field {
403 field: super::diagnostic_name(name),
404 reason: "invalid schema definition name",
405 });
406 }
407 budget.charge(declaration.fields.capacity() * size_of::<Field<String>>(), 1)?;
409 for field in &declaration.fields {
410 budget.charge(field.name.len(), field.name.len() + 1)?;
411 if let Kind::Message { definition } = &field.kind {
412 budget.charge(definition.len(), definition.len() + 1)?;
413 }
414 }
415 if let Some(original) = dictionary.insert(name, declaration) {
416 budget.charge(0, declaration.fields.len() + 1)?;
417 if original != declaration {
418 return Err(Error::Field {
419 field: name.into(),
420 reason: "schema definition name has conflicting metadata",
421 });
422 }
423 }
424 }
425 let missing = |name: &str| Error::Field {
426 field: super::diagnostic_name(name),
427 reason: "schema definition is absent",
428 };
429 let mut names = Vec::new();
430 let mut indices = HashMap::new();
431 let mut directions = Vec::new();
432 budget.charge(4 * size_of::<Vec<Field>>() + size_of::<Schema>(), 1)?;
433 for (index, (direction, root)) in roots.iter().enumerate() {
434 let declaration = dictionary.get(root).ok_or_else(|| missing(root))?;
435 let name = declaration.name.as_str();
436 let definition = if let Some(index) = indices.get(name) {
437 *index
438 } else {
439 budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>()), name.len() + 1)?;
440 let index = names.len();
441 names.push(name);
442 indices.insert(name, index);
443 index
444 };
445 if composite {
446 budget.charge(4 * size_of::<Field<usize>>() + direction.len(), direction.len() + 1)?;
447 directions.push(Field {
448 name: (*direction).to_owned().into(),
449 tag: u32::try_from(index + 1).map_err(|_| Error::Budget)?,
450 kind: Kind::Message { definition },
451 cardinality: Cardinality::Required,
452 });
453 }
454 }
455 let mut definitions = Vec::new();
456 let mut index = 0;
457 while index < names.len() {
458 let declaration = dictionary[names[index]];
459 let mut fields = Vec::new();
460 budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>() + size_of::<Vec<Field>>()), 1)?;
461 for field in &declaration.fields {
462 budget.charge(4 * size_of::<Field<usize>>() + field.name.len(), field.name.len() + 1)?;
463 let kind = field.kind.clone().try_map(|name| {
464 let declaration = dictionary.get(name.as_str()).ok_or_else(|| missing(&name))?;
465 let name = declaration.name.as_str();
466 if let Some(index) = indices.get(name) {
467 return Ok(*index);
468 }
469 budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>()), name.len() + 1)?;
470 let index = names.len();
471 indices.insert(name, index);
472 names.push(name);
473 Ok(index)
474 })?;
475 fields.push(Field {
476 name: field.name.clone(),
477 tag: field.tag,
478 kind,
479 cardinality: field.cardinality,
480 });
481 }
482 definitions.push(fields);
483 index += 1;
484 }
485 let root = if composite {
486 let root = definitions.len();
487 definitions.push(directions);
488 root
489 } else {
490 0
491 };
492 let schema = Schema { root, definitions };
493 schema.prepare(settings)?;
494 Ok(schema)
495}
496
497const fn field_name(field: &Field<Definition>) -> &str {
498 match &field.name {
499 std::borrow::Cow::Borrowed(name) => name,
500 std::borrow::Cow::Owned(_) => panic!("constant schema names must be borrowed"),
501 }
502}
503const fn kind_name(kind: &Kind<Definition>) -> &'static str {
504 match kind {
505 Kind::Bool => "bool",
506 Kind::U32 => "u32",
507 Kind::U64 => "u64",
508 Kind::I32 => "i32",
509 Kind::I64 => "i64",
510 Kind::F32 => "f32",
511 Kind::F64 => "f64",
512 Kind::String => "string",
513 Kind::Bytes => "bytes",
514 Kind::Message { .. } => "message",
515 }
516}
517const fn cardinality_name(cardinality: Cardinality) -> &'static str {
518 match cardinality {
519 Cardinality::Required => "required",
520 Cardinality::Optional => "optional",
521 Cardinality::Repeated => "repeated",
522 Cardinality::Variant => "variant",
523 }
524}
525
526