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 { name: T::NAME, default_variant: T::DEFAULT_VARIANT, identity: TypeId::of::<T>, fields: fields::<T>, marker: marker::<T> }
140 }
141}
142
143impl Named {
144 pub fn decode<'a>(fragments: impl IntoIterator<Item = &'a [u8]>, settings: &SchemaSettings) -> Result<Vec<Self>, Error> {
145 let mut budget = Plan::new(settings);
146 let mut declarations = Vec::new();
147 for encoded in fragments {
148 if encoded.len() > crate::FRAGMENT_LIMIT {
149 return Err(Error::Budget);
150 }
151 budget.charge(encoded.len().checked_mul(8).ok_or(Error::Budget)? + 4 * size_of::<Self>(), encoded.len() + 1)?;
153 let declaration: Self = serde_json::from_slice(encoded)
154 .map_err(|_| Error::Field { field: "schema fragment".into(), reason: "invalid schema metadata" })?;
155 declarations.push(declaration);
156 }
157 Ok(declarations)
158 }
159}
160
161impl From<Fragment> for Named {
162 fn from(fragment: Fragment) -> Self {
163 let Fragment::Schema { name, fields } = fragment;
164 Self { name, fields }
165 }
166}
167impl From<Named> for Fragment {
168 fn from(named: Named) -> Self {
169 Self::Schema { name: named.name, fields: named.fields }
170 }
171}
172
173impl fmt::Debug for Definition {
174 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
175 formatter.debug_struct("Definition").field("name", &self.name).finish_non_exhaustive()
176 }
177}
178
179impl Schema {
180 pub fn from_named(root: &str, declarations: &[Named], settings: &SchemaSettings) -> Result<Self, Error> {
182 resolve_named(&[("", root)], declarations, settings, false)
183 }
184
185 pub fn from_named_roots(roots: &[(&str, &str)], declarations: &[Named], settings: &SchemaSettings) -> Result<Self, Error> {
187 resolve_named(roots, declarations, settings, true)
188 }
189
190 pub fn from_declaration(root: Definition, settings: &SchemaSettings) -> Result<Self, Error> {
191 let mut plan = Plan::new(settings);
192 plan.insert(root)?;
193 let schema = Self { root: 0, definitions: plan.compile()? };
194 schema.prepare(settings)?;
195 Ok(schema)
196 }
197
198 pub fn from_declarations(roots: &[(&str, Definition)], settings: &SchemaSettings) -> Result<Self, Error> {
200 let mut plan = Plan::new(settings);
201 plan.charge(4 * size_of::<Vec<Field>>() + size_of::<Self>(), 1)?;
202 let mut fields = Vec::new();
203 for (index, (name, declaration)) in roots.iter().enumerate() {
204 plan.charge(4 * size_of::<Field<usize>>() + name.len(), name.len() + 1)?;
205 let tag = u32::try_from(index + 1).map_err(|_| Error::Budget)?;
206 fields.push(Field {
207 name: (*name).to_owned().into(),
208 tag,
209 kind: Kind::Message { definition: plan.insert(*declaration)? },
210 cardinality: Cardinality::Required,
211 });
212 }
213 let mut definitions = plan.compile()?;
214 let root = definitions.len();
215 definitions.push(fields);
216 let schema = Self { root, definitions };
217 schema.prepare(settings)?;
218 Ok(schema)
219 }
220}
221
222impl Plan {
223 fn compile(mut self) -> Result<Vec<Vec<Field<usize>>>, Error> {
224 let mut definitions = Vec::new();
225 let mut index = 0;
226 while index < self.declarations.len() {
227 let declaration = self.declarations[index];
228 let mut fields = Vec::new();
229 for field in (declaration.fields)() {
230 self.charge(4 * size_of::<Field<usize>>() + field.name.len(), field.name.len() + 1)?;
231 let kind = field.kind.try_map(|definition| self.insert(definition))?;
232 fields.push(Field { name: field.name.to_string().into(), tag: field.tag, kind, cardinality: field.cardinality });
233 }
234 definitions.push(fields);
235 index += 1;
236 }
237 Ok(definitions)
238 }
239 fn new(settings: &SchemaSettings) -> Self {
240 Self {
241 declarations: Vec::new(),
242 indices: HashMap::new(),
243 remaining_bytes: settings.preparation_bytes.get(),
244 remaining_work: settings.preparation_work.get(),
245 }
246 }
247 fn charge(&mut self, bytes: usize, work: usize) -> Result<(), Error> {
248 self.remaining_bytes = self.remaining_bytes.checked_sub(bytes).ok_or(Error::Budget)?;
249 self.remaining_work = self.remaining_work.checked_sub(work).ok_or(Error::Budget)?;
250 Ok(())
251 }
252 fn insert(&mut self, definition: Definition) -> Result<usize, Error> {
253 self.charge(0, definition.name.len() + 1)?;
254 if definition.name.is_empty() || definition.name.len() > MAX_NAME_BYTES || definition.name.chars().any(char::is_control) {
255 return Err(Error::Field { field: super::diagnostic_name(definition.name), reason: "invalid schema definition name" });
256 }
257 if let Some(index) = self.indices.get(definition.name).copied() {
258 let original = self.declarations[index];
259 if (original.identity)() != (definition.identity)() {
260 return Err(Error::Field { field: definition.name.into(), reason: "schema definition name has multiple owners" });
261 }
262 return Ok(index);
263 }
264 self.charge(4 * (size_of::<Definition>() + size_of::<Vec<Field>>() + size_of::<(&str, usize)>() + 1), 1)?;
265 let index = self.declarations.len();
266 self.declarations.push(definition);
267 self.indices.insert(definition.name, index);
268 Ok(index)
269 }
270}
271
272pub fn markers(root: Definition, settings: &SchemaSettings) -> Result<Vec<&'static [u8]>, Error> {
275 markers_many([root], settings)
276}
277
278pub fn markers_many(roots: impl IntoIterator<Item = Definition>, settings: &SchemaSettings) -> Result<Vec<&'static [u8]>, Error> {
279 let mut plan = Plan::new(settings);
280 for root in roots {
281 plan.insert(root)?;
282 }
283 let mut index = 0;
284 while index < plan.declarations.len() {
285 let declaration = plan.declarations[index];
286 for field in (declaration.fields)() {
287 plan.charge(0, 1)?;
288 if let Kind::Message { definition } = field.kind {
289 plan.insert(definition)?;
290 }
291 }
292 index += 1;
293 }
294 let output_bytes = plan.declarations.len().checked_mul(std::mem::size_of::<&[u8]>()).ok_or(Error::Budget)?;
295 plan.charge(output_bytes, 0)?;
296 Ok(plan.declarations.iter().map(|definition| (definition.marker)()).collect())
297}
298
299pub const fn encoded_len(name: &str, fields: &[Field<Definition>]) -> usize {
300 let mut length = crate::PREFIX.len() + HEADER.len() + quoted_len(name) + FIELDS.len() + 3;
301 let mut index = 0;
302 while index < fields.len() {
303 let field = &fields[index];
304 length += NAME.len()
305 + quoted_len(field_name(field))
306 + TAG.len()
307 + digits(field.tag as u64)
308 + KIND.len()
309 + quoted_len(kind_name(&field.kind))
310 + CARDINALITY.len()
311 + quoted_len(cardinality_name(field.cardinality))
312 + 1;
313 if let Kind::Message { definition } = &field.kind {
314 length += REFERENCE.len() + quoted_len(definition.name);
315 }
316 if index > 0 {
317 length += 1;
318 }
319 index += 1;
320 }
321 assert!(length - crate::PREFIX.len() - 1 <= crate::FRAGMENT_LIMIT);
322 length
323}
324
325pub const fn encode<const N: usize>(name: &str, fields: &[Field<Definition>]) -> [u8; N] {
326 assert!(N == encoded_len(name, fields));
327 encode_buffer(name, fields)
328}
329
330pub const fn encode_buffer<const N: usize>(name: &str, fields: &[Field<Definition>]) -> [u8; N] {
333 assert!(N >= encoded_len(name, fields), "schema marker exceeds its static storage");
334 let mut output = [0; N];
335 let mut cursor = 0;
336 write(&mut output, &mut cursor, crate::PREFIX);
337 write(&mut output, &mut cursor, HEADER);
338 quoted(&mut output, &mut cursor, name);
339 write(&mut output, &mut cursor, FIELDS);
340 let mut index = 0;
341 while index < fields.len() {
342 let field = &fields[index];
343 if index > 0 {
344 write(&mut output, &mut cursor, b",");
345 }
346 write(&mut output, &mut cursor, NAME);
347 quoted(&mut output, &mut cursor, field_name(field));
348 write(&mut output, &mut cursor, TAG);
349 number(&mut output, &mut cursor, field.tag as u64);
350 write(&mut output, &mut cursor, KIND);
351 quoted(&mut output, &mut cursor, kind_name(&field.kind));
352 if let Kind::Message { definition } = &field.kind {
353 write(&mut output, &mut cursor, REFERENCE);
354 quoted(&mut output, &mut cursor, definition.name);
355 }
356 write(&mut output, &mut cursor, CARDINALITY);
357 quoted(&mut output, &mut cursor, cardinality_name(field.cardinality));
358 write(&mut output, &mut cursor, b"}");
359 index += 1;
360 }
361 write(&mut output, &mut cursor, b"]}\0");
362 assert!(cursor == encoded_len(name, fields));
363 output
364}
365
366fn fields<T: super::Described + ?Sized>() -> &'static [Field<Definition>] {
369 T::FIELDS
370}
371
372fn marker<T: super::Described + ?Sized>() -> &'static [u8] {
373 T::MARKER
374}
375
376fn resolve_named(roots: &[(&str, &str)], declarations: &[Named], settings: &SchemaSettings, composite: bool) -> Result<Schema, Error> {
377 let mut budget = Plan::new(settings);
378 let mut dictionary = HashMap::new();
379 for declaration in declarations {
380 let name = declaration.name.as_str();
381 budget.charge(4 * size_of::<(&str, &Named)>() + name.len(), name.len() + 1)?;
382 if name.is_empty() || name.len() > MAX_NAME_BYTES || name.chars().any(char::is_control) {
383 return Err(Error::Field { field: super::diagnostic_name(name), reason: "invalid schema definition name" });
384 }
385 budget.charge(declaration.fields.capacity() * size_of::<Field<String>>(), 1)?;
387 for field in &declaration.fields {
388 budget.charge(field.name.len(), field.name.len() + 1)?;
389 if let Kind::Message { definition } = &field.kind {
390 budget.charge(definition.len(), definition.len() + 1)?;
391 }
392 }
393 if let Some(original) = dictionary.insert(name, declaration) {
394 budget.charge(0, declaration.fields.len() + 1)?;
395 if original != declaration {
396 return Err(Error::Field { field: name.into(), reason: "schema definition name has conflicting metadata" });
397 }
398 }
399 }
400 let missing = |name: &str| Error::Field { field: super::diagnostic_name(name), reason: "schema definition is absent" };
401 let mut names = Vec::new();
402 let mut indices = HashMap::new();
403 let mut directions = Vec::new();
404 budget.charge(4 * size_of::<Vec<Field>>() + size_of::<Schema>(), 1)?;
405 for (index, (direction, root)) in roots.iter().enumerate() {
406 let declaration = dictionary.get(root).ok_or_else(|| missing(root))?;
407 let name = declaration.name.as_str();
408 let definition = if let Some(index) = indices.get(name) {
409 *index
410 } else {
411 budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>()), name.len() + 1)?;
412 let index = names.len();
413 names.push(name);
414 indices.insert(name, index);
415 index
416 };
417 if composite {
418 budget.charge(4 * size_of::<Field<usize>>() + direction.len(), direction.len() + 1)?;
419 directions.push(Field {
420 name: (*direction).to_owned().into(),
421 tag: u32::try_from(index + 1).map_err(|_| Error::Budget)?,
422 kind: Kind::Message { definition },
423 cardinality: Cardinality::Required,
424 });
425 }
426 }
427 let mut definitions = Vec::new();
428 let mut index = 0;
429 while index < names.len() {
430 let declaration = dictionary[names[index]];
431 let mut fields = Vec::new();
432 budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>() + size_of::<Vec<Field>>()), 1)?;
433 for field in &declaration.fields {
434 budget.charge(4 * size_of::<Field<usize>>() + field.name.len(), field.name.len() + 1)?;
435 let kind = field.kind.clone().try_map(|name| {
436 let declaration = dictionary.get(name.as_str()).ok_or_else(|| missing(&name))?;
437 let name = declaration.name.as_str();
438 if let Some(index) = indices.get(name) {
439 return Ok(*index);
440 }
441 budget.charge(4 * (size_of::<&str>() + size_of::<(&str, usize)>()), name.len() + 1)?;
442 let index = names.len();
443 indices.insert(name, index);
444 names.push(name);
445 Ok(index)
446 })?;
447 fields.push(Field { name: field.name.clone(), tag: field.tag, kind, cardinality: field.cardinality });
448 }
449 definitions.push(fields);
450 index += 1;
451 }
452 let root = if composite {
453 let root = definitions.len();
454 definitions.push(directions);
455 root
456 } else {
457 0
458 };
459 let schema = Schema { root, definitions };
460 schema.prepare(settings)?;
461 Ok(schema)
462}
463
464const fn field_name(field: &Field<Definition>) -> &str {
465 match &field.name {
466 std::borrow::Cow::Borrowed(name) => name,
467 std::borrow::Cow::Owned(_) => panic!("constant schema names must be borrowed"),
468 }
469}
470const fn kind_name(kind: &Kind<Definition>) -> &'static str {
471 match kind {
472 Kind::Bool => "bool",
473 Kind::U32 => "u32",
474 Kind::U64 => "u64",
475 Kind::I32 => "i32",
476 Kind::I64 => "i64",
477 Kind::F32 => "f32",
478 Kind::F64 => "f64",
479 Kind::String => "string",
480 Kind::Bytes => "bytes",
481 Kind::Message { .. } => "message",
482 }
483}
484const fn cardinality_name(cardinality: Cardinality) -> &'static str {
485 match cardinality {
486 Cardinality::Required => "required",
487 Cardinality::Optional => "optional",
488 Cardinality::Repeated => "repeated",
489 Cardinality::Variant => "variant",
490 }
491}
492
493