1use crate::error::{Error, Result};
7use crate::layout::{self, StructLayout};
8use crate::value::Value;
9
10pub const SCHEMA_MAGIC: &[u8; 4] = b"VSC1";
11
12pub const MAX_TYPE_DEPTH: u32 = 64;
16
17#[derive(Clone, Debug, PartialEq, Eq)]
20pub enum Type {
21 Bool,
22 U8,
23 U16,
24 U32,
25 U64,
26 I8,
27 I16,
28 I32,
29 I64,
30 F32,
31 F64,
32 String,
33 Bytes,
34 Struct(u16),
35 Enum(u16),
36 List(Box<Type>),
37 Map(Box<Type>, Box<Type>),
41 Union(Vec<Type>),
45}
46
47impl Type {
48 pub fn describe(&self, schema: &Schema) -> String {
49 match self {
50 Type::Struct(i) => format!("struct {}", schema.type_name(*i)),
51 Type::Enum(i) => format!("enum {}", schema.type_name(*i)),
52 Type::List(e) => format!("list<{}>", e.describe(schema)),
53 Type::Map(k, v) => format!("map<{}, {}>", k.describe(schema), v.describe(schema)),
54 Type::Union(variants) => {
55 let parts: Vec<String> = variants.iter().map(|t| t.describe(schema)).collect();
56 format!("union<{}>", parts.join(", "))
57 }
58 other => format!("{other:?}").to_lowercase(),
59 }
60 }
61
62 pub fn is_valid_map_key(&self) -> bool {
66 matches!(
67 self,
68 Type::Bool
69 | Type::U8
70 | Type::U16
71 | Type::U32
72 | Type::U64
73 | Type::I8
74 | Type::I16
75 | Type::I32
76 | Type::I64
77 | Type::String
78 | Type::Enum(_)
79 )
80 }
81}
82
83#[derive(Clone, Copy, Debug, PartialEq, Eq)]
90pub enum Default {
91 Bool(bool),
92 U8(u8),
93 U16(u16),
94 U32(u32),
95 U64(u64),
96 I8(i8),
97 I16(i16),
98 I32(i32),
99 I64(i64),
100 F32(u32),
102 F64(u64),
104 Enum(u32),
105}
106
107impl Default {
108 fn wire_size(&self) -> usize {
111 match self {
112 Default::Bool(_) | Default::U8(_) | Default::I8(_) => 1,
113 Default::U16(_) | Default::I16(_) => 2,
114 Default::U32(_) | Default::I32(_) | Default::F32(_) | Default::Enum(_) => 4,
115 Default::U64(_) | Default::I64(_) | Default::F64(_) => 8,
116 }
117 }
118
119 fn to_bits(self) -> u64 {
121 match self {
122 Default::Bool(b) => b as u64,
123 Default::U8(x) => x as u64,
124 Default::U16(x) => x as u64,
125 Default::U32(x) => x as u64,
126 Default::U64(x) => x,
127 Default::I8(x) => x as u8 as u64,
128 Default::I16(x) => x as u16 as u64,
129 Default::I32(x) => x as u32 as u64,
130 Default::I64(x) => x as u64,
131 Default::F32(bits) => bits as u64,
132 Default::F64(bits) => bits,
133 Default::Enum(x) => x as u64,
134 }
135 }
136
137 fn from_bits(ty: &Type, bits: u64) -> Option<Default> {
141 Some(match ty {
142 Type::Bool => Default::Bool(bits != 0),
143 Type::U8 => Default::U8(bits as u8),
144 Type::U16 => Default::U16(bits as u16),
145 Type::U32 => Default::U32(bits as u32),
146 Type::U64 => Default::U64(bits),
147 Type::I8 => Default::I8(bits as i8),
148 Type::I16 => Default::I16(bits as i16),
149 Type::I32 => Default::I32(bits as i32),
150 Type::I64 => Default::I64(bits as i64),
151 Type::F32 => Default::F32(bits as u32),
152 Type::F64 => Default::F64(bits),
153 Type::Enum(_) => Default::Enum(bits as u32),
154 _ => return None,
155 })
156 }
157
158 fn scalar_type(&self) -> Option<Type> {
161 Some(match self {
162 Default::Bool(_) => Type::Bool,
163 Default::U8(_) => Type::U8,
164 Default::U16(_) => Type::U16,
165 Default::U32(_) => Type::U32,
166 Default::U64(_) => Type::U64,
167 Default::I8(_) => Type::I8,
168 Default::I16(_) => Type::I16,
169 Default::I32(_) => Type::I32,
170 Default::I64(_) => Type::I64,
171 Default::F32(_) => Type::F32,
172 Default::F64(_) => Type::F64,
173 Default::Enum(_) => return None,
174 })
175 }
176}
177
178#[derive(Clone, Debug, PartialEq, Eq)]
179pub struct FieldDef {
180 pub id: u16,
181 pub name: String,
182 pub ty: Type,
183 pub default: Option<Default>,
185}
186
187#[derive(Clone, Copy, Debug, PartialEq, Eq)]
189pub enum StructMode {
190 Sparse,
193 Dense,
196 Packed,
201}
202
203#[derive(Clone, Debug, PartialEq, Eq)]
204pub struct StructDef {
205 pub name: String,
206 pub fields: Vec<FieldDef>,
208 pub mode: StructMode,
209}
210
211#[derive(Clone, Debug, PartialEq, Eq)]
212pub struct EnumDef {
213 pub name: String,
214 pub variants: Vec<(u32, String)>,
217}
218
219impl EnumDef {
220 pub fn name_of(&self, value: u32) -> Option<&str> {
221 self.variants
222 .binary_search_by_key(&value, |(v, _)| *v)
223 .ok()
224 .map(|i| self.variants[i].1.as_str())
225 }
226}
227
228#[derive(Clone, Debug, PartialEq, Eq)]
229pub enum TypeDef {
230 Struct(StructDef),
231 Enum(EnumDef),
232}
233
234impl TypeDef {
235 pub fn name(&self) -> &str {
236 match self {
237 TypeDef::Struct(s) => &s.name,
238 TypeDef::Enum(e) => &e.name,
239 }
240 }
241}
242
243impl StructDef {
244 pub fn is_dense(&self) -> bool {
245 self.mode == StructMode::Dense
246 }
247
248 pub fn is_packed(&self) -> bool {
249 self.mode == StructMode::Packed
250 }
251}
252
253#[derive(Clone, Debug)]
256pub struct Schema {
257 types: Vec<TypeDef>,
258 root: u16,
259 canonical: Vec<u8>,
260 id: u128,
261 layouts: Vec<Option<StructLayout>>,
262}
263
264impl Schema {
265 pub fn id(&self) -> u128 {
269 self.id
270 }
271
272 pub fn canonical_bytes(&self) -> &[u8] {
273 &self.canonical
274 }
275
276 pub fn root_index(&self) -> u16 {
277 self.root
278 }
279
280 pub fn type_count(&self) -> u16 {
281 self.types.len() as u16
282 }
283
284 pub fn type_def(&self, index: u16) -> Option<&TypeDef> {
285 self.types.get(index as usize)
286 }
287
288 pub fn type_name(&self, index: u16) -> &str {
289 self.types
290 .get(index as usize)
291 .map(|t| t.name())
292 .unwrap_or("<bad type index>")
293 }
294
295 pub(crate) fn struct_def_unchecked(&self, index: u16) -> &StructDef {
298 match &self.types[index as usize] {
299 TypeDef::Struct(s) => s,
300 TypeDef::Enum(_) => panic!("schema invariant: type {index} is not a struct"),
301 }
302 }
303
304 pub(crate) fn enum_def_unchecked(&self, index: u16) -> &EnumDef {
305 match &self.types[index as usize] {
306 TypeDef::Enum(e) => e,
307 TypeDef::Struct(_) => panic!("schema invariant: type {index} is not an enum"),
308 }
309 }
310
311 pub(crate) fn layout_unchecked(&self, index: u16) -> &StructLayout {
312 self.layouts[index as usize]
313 .as_ref()
314 .expect("schema invariant: struct type has a layout")
315 }
316
317 pub(crate) fn packed_layout_unchecked(&self, index: u16) -> &crate::layout::PackedLayout {
318 self.layout_unchecked(index).as_packed()
319 }
320
321 pub fn find_field(&self, struct_index: u16, id: u16) -> Option<(usize, &FieldDef)> {
323 let sd = match self.type_def(struct_index)? {
324 TypeDef::Struct(s) => s,
325 TypeDef::Enum(_) => return None,
326 };
327 sd.fields
328 .binary_search_by_key(&id, |f| f.id)
329 .ok()
330 .map(|pos| (pos, &sd.fields[pos]))
331 }
332
333 pub fn from_canonical(bytes: &[u8]) -> Result<Schema> {
336 let mut cur = Cur { b: bytes, p: 0 };
337 let magic = cur.take(4)?;
338 if magic != SCHEMA_MAGIC {
339 return Err(Error::BadSchema("bad VSC1 magic".into()));
340 }
341 let type_count = cur.u16()?;
342 let mut types = Vec::with_capacity(type_count as usize);
343 for _ in 0..type_count {
344 let kind = cur.u8()?;
345 let name = cur.name()?;
346 match kind {
347 0 | 2 | 3 => {
348 let field_count = cur.u16()?;
349 let mut fields = Vec::with_capacity(field_count as usize);
350 for _ in 0..field_count {
351 let id = cur.u16()?;
352 let fname = cur.name()?;
353 let ty = cur.type_expr(type_count)?;
354 fields.push(FieldDef {
355 id,
356 name: fname,
357 ty,
358 default: None,
359 });
360 }
361 let mode = match kind {
362 2 => StructMode::Dense,
363 3 => StructMode::Packed,
364 _ => StructMode::Sparse,
365 };
366 types.push(TypeDef::Struct(StructDef { name, fields, mode }));
367 }
368 1 => {
369 let variant_count = cur.u16()?;
370 let mut variants = Vec::with_capacity(variant_count as usize);
371 for _ in 0..variant_count {
372 let value = cur.u32()?;
373 let vname = cur.name()?;
374 variants.push((value, vname));
375 }
376 types.push(TypeDef::Enum(EnumDef { name, variants }));
377 }
378 k => return Err(Error::BadSchema(format!("unknown type kind {k}"))),
379 }
380 }
381 let root = cur.u16()?;
382 if cur.p < bytes.len() {
384 let count = cur.u16()?;
385 if count == 0 {
390 return Err(Error::BadSchema(
391 "empty defaults section must be omitted, not encoded as count 0".into(),
392 ));
393 }
394 for _ in 0..count {
395 let ti = cur.u16()? as usize;
396 let fid = cur.u16()?;
397 let ty = match types.get(ti) {
398 Some(TypeDef::Struct(sd)) => {
399 sd.fields.iter().find(|f| f.id == fid).map(|f| f.ty.clone())
400 }
401 _ => None,
402 }
403 .ok_or_else(|| Error::BadSchema("default references unknown field".into()))?;
404 let size = default_wire_size(&ty)
405 .ok_or_else(|| Error::BadSchema("default on a non-scalar field".into()))?;
406 let raw = cur.take(size)?;
407 let mut word = [0u8; 8];
408 word[..size].copy_from_slice(raw);
409 let d = Default::from_bits(&ty, u64::from_le_bytes(word))
410 .ok_or_else(|| Error::BadSchema("default on a non-scalar field".into()))?;
411 if let Some(TypeDef::Struct(sd)) = types.get_mut(ti) {
412 if let Some(f) = sd.fields.iter_mut().find(|f| f.id == fid) {
413 f.default = Some(d);
414 }
415 }
416 }
417 }
418 if cur.p != bytes.len() {
419 return Err(Error::BadSchema("trailing bytes after schema".into()));
420 }
421 let schema = Schema::assemble(types, root)?;
422 if schema.canonical_bytes() != bytes {
433 return Err(Error::BadSchema(
434 "schema is not in canonical form (re-encoding differs)".into(),
435 ));
436 }
437 Ok(schema)
438 }
439
440 fn assemble(types: Vec<TypeDef>, root: u16) -> Result<Schema> {
442 validate(&types, root)?;
443 let canonical = encode_canonical(&types, root);
444 let id = crate::hash::schema_id(&canonical);
445 let layouts = types
446 .iter()
447 .map(|t| match t {
448 TypeDef::Struct(s) => Some(layout::compute(&s.fields, s.mode)),
449 TypeDef::Enum(_) => None,
450 })
451 .collect();
452 Ok(Schema {
453 types,
454 root,
455 canonical,
456 id,
457 layouts,
458 })
459 }
460}
461
462fn validate(types: &[TypeDef], root: u16) -> Result<()> {
463 if types.is_empty() {
464 return Err(Error::BadSchema("schema has no types".into()));
465 }
466 for w in types.windows(2) {
468 if w[0].name() >= w[1].name() {
469 return Err(Error::BadSchema(format!(
470 "types not in canonical (name-sorted) order: {:?} then {:?}",
471 w[0].name(),
472 w[1].name()
473 )));
474 }
475 }
476 fn check_type(types: &[TypeDef], t: &Type, depth: u32) -> Result<()> {
477 if depth > MAX_TYPE_DEPTH {
478 return Err(Error::BadSchema(format!(
479 "type nesting exceeds limit of {MAX_TYPE_DEPTH}"
480 )));
481 }
482 match t {
483 Type::Struct(i) => match types.get(*i as usize) {
484 Some(TypeDef::Struct(_)) => Ok(()),
485 _ => Err(Error::BadSchema(format!("type ref {i} is not a struct"))),
486 },
487 Type::Enum(i) => match types.get(*i as usize) {
488 Some(TypeDef::Enum(_)) => Ok(()),
489 _ => Err(Error::BadSchema(format!("type ref {i} is not an enum"))),
490 },
491 Type::List(e) => check_type(types, e, depth + 1),
492 Type::Map(k, v) => {
493 if !k.is_valid_map_key() {
494 return Err(Error::BadSchema(format!(
495 "map key type {k:?} is not a valid key (use bool, an integer, string, or an enum)"
496 )));
497 }
498 check_type(types, k, depth + 1)?;
499 check_type(types, v, depth + 1)
500 }
501 Type::Union(variants) => {
502 if variants.is_empty() {
503 return Err(Error::BadSchema("union has no variants".into()));
504 }
505 for v in variants {
506 check_type(types, v, depth + 1)?;
507 }
508 Ok(())
509 }
510 _ => Ok(()),
511 }
512 }
513 let check_ref = |ty: &Type| -> Result<()> { check_type(types, ty, 0) };
514 for td in types {
515 match td {
516 TypeDef::Struct(s) => {
517 if s.name.is_empty() {
518 return Err(Error::BadSchema("empty type name".into()));
519 }
520 if s.mode == StructMode::Packed && s.fields.len() > 64 {
521 return Err(Error::BadSchema(format!(
522 "packed struct {} has {} fields; packed structs are \
523 limited to 64 (the bitmap must fit one u64 rank word)",
524 s.name,
525 s.fields.len()
526 )));
527 }
528 for w in s.fields.windows(2) {
529 if w[0].id >= w[1].id {
530 return Err(Error::BadSchema(format!(
531 "fields of {} not strictly ascending by id",
532 s.name
533 )));
534 }
535 }
536 for f in &s.fields {
537 if f.name.is_empty() {
538 return Err(Error::BadSchema(format!("empty field name in {}", s.name)));
539 }
540 check_ref(&f.ty)?;
541 if let Some(d) = f.default {
542 let ok = match d.scalar_type() {
543 Some(t) => f.ty == t,
544 None => matches!(f.ty, Type::Enum(_)), };
546 if !ok {
547 return Err(Error::BadSchema(format!(
548 "field {} in {} has a default whose type does not match the field",
549 f.name, s.name
550 )));
551 }
552 }
553 }
554 }
555 TypeDef::Enum(e) => {
556 if e.name.is_empty() {
557 return Err(Error::BadSchema("empty type name".into()));
558 }
559 for w in e.variants.windows(2) {
560 if w[0].0 >= w[1].0 {
561 return Err(Error::BadSchema(format!(
562 "variants of {} not strictly ascending by value",
563 e.name
564 )));
565 }
566 }
567 }
568 }
569 }
570 match types.get(root as usize) {
571 Some(TypeDef::Struct(_)) => Ok(()),
572 Some(TypeDef::Enum(_)) => Err(Error::BadSchema("root type must be a struct".into())),
573 None => Err(Error::BadSchema("root type index out of range".into())),
574 }
575}
576
577fn push_u16(b: &mut Vec<u8>, v: u16) {
582 b.extend_from_slice(&v.to_le_bytes());
583}
584
585fn push_u32(b: &mut Vec<u8>, v: u32) {
586 b.extend_from_slice(&v.to_le_bytes());
587}
588
589fn push_name(b: &mut Vec<u8>, s: &str) {
590 push_u16(b, s.len() as u16);
591 b.extend_from_slice(s.as_bytes());
592}
593
594fn push_type(b: &mut Vec<u8>, ty: &Type) {
595 match ty {
596 Type::Bool => b.push(0x01),
597 Type::U8 => b.push(0x02),
598 Type::U16 => b.push(0x03),
599 Type::U32 => b.push(0x04),
600 Type::U64 => b.push(0x05),
601 Type::I8 => b.push(0x06),
602 Type::I16 => b.push(0x07),
603 Type::I32 => b.push(0x08),
604 Type::I64 => b.push(0x09),
605 Type::F32 => b.push(0x0A),
606 Type::F64 => b.push(0x0B),
607 Type::String => b.push(0x10),
608 Type::Bytes => b.push(0x11),
609 Type::Struct(i) => {
610 b.push(0x20);
611 push_u16(b, *i);
612 }
613 Type::Enum(i) => {
614 b.push(0x21);
615 push_u16(b, *i);
616 }
617 Type::List(e) => {
618 b.push(0x22);
619 push_type(b, e);
620 }
621 Type::Map(k, v) => {
622 b.push(0x23);
623 push_type(b, k);
624 push_type(b, v);
625 }
626 Type::Union(variants) => {
627 b.push(0x24);
628 push_u16(b, variants.len() as u16);
629 for v in variants {
630 push_type(b, v);
631 }
632 }
633 }
634}
635
636fn encode_canonical(types: &[TypeDef], root: u16) -> Vec<u8> {
637 let mut b = Vec::new();
638 b.extend_from_slice(SCHEMA_MAGIC);
639 push_u16(&mut b, types.len() as u16);
640 for td in types {
641 match td {
642 TypeDef::Struct(s) => {
643 b.push(match s.mode {
644 StructMode::Sparse => 0,
645 StructMode::Dense => 2,
646 StructMode::Packed => 3,
647 });
648 push_name(&mut b, &s.name);
649 push_u16(&mut b, s.fields.len() as u16);
650 for f in &s.fields {
651 push_u16(&mut b, f.id);
652 push_name(&mut b, &f.name);
653 push_type(&mut b, &f.ty);
654 }
655 }
656 TypeDef::Enum(e) => {
657 b.push(1);
658 push_name(&mut b, &e.name);
659 push_u16(&mut b, e.variants.len() as u16);
660 for (v, n) in &e.variants {
661 push_u32(&mut b, *v);
662 push_name(&mut b, n);
663 }
664 }
665 }
666 }
667 push_u16(&mut b, root);
668 let mut defaults: Vec<(u16, u16, Default)> = Vec::new();
673 for (ti, td) in types.iter().enumerate() {
674 if let TypeDef::Struct(sd) = td {
675 for f in &sd.fields {
676 if let Some(d) = f.default {
677 defaults.push((ti as u16, f.id, d));
678 }
679 }
680 }
681 }
682 if !defaults.is_empty() {
683 push_u16(&mut b, defaults.len() as u16);
684 for (ti, fid, d) in defaults {
685 push_u16(&mut b, ti);
686 push_u16(&mut b, fid);
687 let bytes = d.to_bits().to_le_bytes();
688 b.extend_from_slice(&bytes[..d.wire_size()]);
689 }
690 }
691 b
692}
693
694fn default_wire_size(ty: &Type) -> Option<usize> {
697 Some(match ty {
698 Type::Bool | Type::U8 | Type::I8 => 1,
699 Type::U16 | Type::I16 => 2,
700 Type::U32 | Type::I32 | Type::F32 | Type::Enum(_) => 4,
701 Type::U64 | Type::I64 | Type::F64 => 8,
702 _ => return None,
703 })
704}
705
706struct Cur<'a> {
711 b: &'a [u8],
712 p: usize,
713}
714
715impl<'a> Cur<'a> {
716 fn take(&mut self, n: usize) -> Result<&'a [u8]> {
717 let end = self
718 .p
719 .checked_add(n)
720 .ok_or_else(|| Error::BadSchema("length overflow".into()))?;
721 let s = self
722 .b
723 .get(self.p..end)
724 .ok_or_else(|| Error::BadSchema("schema truncated".into()))?;
725 self.p = end;
726 Ok(s)
727 }
728
729 fn u8(&mut self) -> Result<u8> {
730 Ok(self.take(1)?[0])
731 }
732
733 fn u16(&mut self) -> Result<u16> {
734 Ok(u16::from_le_bytes(self.take(2)?.try_into().unwrap()))
735 }
736
737 fn u32(&mut self) -> Result<u32> {
738 Ok(u32::from_le_bytes(self.take(4)?.try_into().unwrap()))
739 }
740
741 fn name(&mut self) -> Result<String> {
742 let len = self.u16()? as usize;
743 let bytes = self.take(len)?;
744 String::from_utf8(bytes.to_vec())
745 .map_err(|_| Error::BadSchema("name is not valid UTF-8".into()))
746 }
747
748 fn type_expr(&mut self, type_count: u16) -> Result<Type> {
749 self.type_expr_depth(type_count, 0)
750 }
751
752 fn type_expr_depth(&mut self, type_count: u16, depth: u32) -> Result<Type> {
755 if depth > MAX_TYPE_DEPTH {
756 return Err(Error::BadSchema(format!(
757 "type nesting exceeds limit of {MAX_TYPE_DEPTH}"
758 )));
759 }
760 let code = self.u8()?;
761 Ok(match code {
762 0x01 => Type::Bool,
763 0x02 => Type::U8,
764 0x03 => Type::U16,
765 0x04 => Type::U32,
766 0x05 => Type::U64,
767 0x06 => Type::I8,
768 0x07 => Type::I16,
769 0x08 => Type::I32,
770 0x09 => Type::I64,
771 0x0A => Type::F32,
772 0x0B => Type::F64,
773 0x10 => Type::String,
774 0x11 => Type::Bytes,
775 0x20 => {
776 let i = self.u16()?;
777 if i >= type_count {
778 return Err(Error::BadSchema("struct type index out of range".into()));
779 }
780 Type::Struct(i)
781 }
782 0x21 => {
783 let i = self.u16()?;
784 if i >= type_count {
785 return Err(Error::BadSchema("enum type index out of range".into()));
786 }
787 Type::Enum(i)
788 }
789 0x22 => Type::List(Box::new(self.type_expr_depth(type_count, depth + 1)?)),
790 0x23 => {
791 let key = self.type_expr_depth(type_count, depth + 1)?;
792 let value = self.type_expr_depth(type_count, depth + 1)?;
793 Type::Map(Box::new(key), Box::new(value))
794 }
795 0x24 => {
796 let count = self.u16()?;
797 if count == 0 {
798 return Err(Error::BadSchema("union has no variants".into()));
799 }
800 let mut variants = Vec::with_capacity(count as usize);
801 for _ in 0..count {
802 variants.push(self.type_expr_depth(type_count, depth + 1)?);
803 }
804 Type::Union(variants)
805 }
806 c => return Err(Error::BadSchema(format!("unknown type code {c:#04x}"))),
807 })
808 }
809}
810
811#[derive(Clone, Debug)]
818pub enum Dt {
819 Bool,
820 U8,
821 U16,
822 U32,
823 U64,
824 I8,
825 I16,
826 I32,
827 I64,
828 F32,
829 F64,
830 Str,
831 Bytes,
832 Named(String),
833 List(Box<Dt>),
834 Map(Box<Dt>, Box<Dt>),
835 Union(Vec<Dt>),
836}
837
838impl Dt {
839 pub fn named(name: &str) -> Dt {
840 Dt::Named(name.to_string())
841 }
842
843 pub fn list(elem: Dt) -> Dt {
844 Dt::List(Box::new(elem))
845 }
846
847 pub fn map(key: Dt, value: Dt) -> Dt {
848 Dt::Map(Box::new(key), Box::new(value))
849 }
850
851 pub fn union(variants: Vec<Dt>) -> Dt {
852 Dt::Union(variants)
853 }
854}
855
856enum DraftDef {
857 Struct(Vec<(u16, String, Dt)>, StructMode),
858 Enum(Vec<(u32, String)>),
859}
860
861pub struct SchemaBuilder {
864 types: Vec<(String, DraftDef)>,
865 defaults: Vec<(String, u16, Value)>,
866}
867
868impl SchemaBuilder {
869 #[allow(clippy::new_without_default)]
870 pub fn new() -> SchemaBuilder {
871 SchemaBuilder {
872 types: Vec::new(),
873 defaults: Vec::new(),
874 }
875 }
876
877 pub fn set_default(
884 mut self,
885 struct_name: &str,
886 field_id: u16,
887 default: Value,
888 ) -> SchemaBuilder {
889 self.defaults
890 .push((struct_name.to_string(), field_id, default));
891 self
892 }
893
894 pub fn add_struct(mut self, name: &str, fields: Vec<(u16, &str, Dt)>) -> SchemaBuilder {
895 self.push_struct(name, fields, StructMode::Sparse);
896 self
897 }
898
899 pub fn add_dense_struct(mut self, name: &str, fields: Vec<(u16, &str, Dt)>) -> SchemaBuilder {
904 self.push_struct(name, fields, StructMode::Dense);
905 self
906 }
907
908 pub fn add_packed_struct(mut self, name: &str, fields: Vec<(u16, &str, Dt)>) -> SchemaBuilder {
915 self.push_struct(name, fields, StructMode::Packed);
916 self
917 }
918
919 fn push_struct(&mut self, name: &str, fields: Vec<(u16, &str, Dt)>, mode: StructMode) {
920 self.types.push((
921 name.to_string(),
922 DraftDef::Struct(
923 fields
924 .into_iter()
925 .map(|(id, n, t)| (id, n.to_string(), t))
926 .collect(),
927 mode,
928 ),
929 ));
930 }
931
932 pub fn add_enum(mut self, name: &str, variants: Vec<(u32, &str)>) -> SchemaBuilder {
933 self.types.push((
934 name.to_string(),
935 DraftDef::Enum(
936 variants
937 .into_iter()
938 .map(|(v, n)| (v, n.to_string()))
939 .collect(),
940 ),
941 ));
942 self
943 }
944
945 pub fn build(mut self, root: &str) -> Result<Schema> {
946 if self.types.len() > u16::MAX as usize {
947 return Err(Error::BadSchema("too many types".into()));
948 }
949 self.types.sort_by(|a, b| a.0.cmp(&b.0));
950 for w in self.types.windows(2) {
951 if w[0].0 == w[1].0 {
952 return Err(Error::BadSchema(format!(
953 "duplicate type name {:?}",
954 w[0].0
955 )));
956 }
957 }
958 let index_of = |name: &str| -> Result<u16> {
959 self.types
960 .binary_search_by(|(n, _)| n.as_str().cmp(name))
961 .map(|i| i as u16)
962 .map_err(|_| Error::BadSchema(format!("unknown type name {name:?}")))
963 };
964 let resolve = |dt: &Dt| -> Result<Type> {
965 fn go(
966 types: &[(String, DraftDef)],
967 index_of: &dyn Fn(&str) -> Result<u16>,
968 dt: &Dt,
969 ) -> Result<Type> {
970 Ok(match dt {
971 Dt::Bool => Type::Bool,
972 Dt::U8 => Type::U8,
973 Dt::U16 => Type::U16,
974 Dt::U32 => Type::U32,
975 Dt::U64 => Type::U64,
976 Dt::I8 => Type::I8,
977 Dt::I16 => Type::I16,
978 Dt::I32 => Type::I32,
979 Dt::I64 => Type::I64,
980 Dt::F32 => Type::F32,
981 Dt::F64 => Type::F64,
982 Dt::Str => Type::String,
983 Dt::Bytes => Type::Bytes,
984 Dt::Named(n) => {
985 let i = index_of(n)?;
986 match &types[i as usize].1 {
987 DraftDef::Struct(..) => Type::Struct(i),
988 DraftDef::Enum(_) => Type::Enum(i),
989 }
990 }
991 Dt::List(e) => Type::List(Box::new(go(types, index_of, e)?)),
992 Dt::Map(k, v) => Type::Map(
993 Box::new(go(types, index_of, k)?),
994 Box::new(go(types, index_of, v)?),
995 ),
996 Dt::Union(variants) => {
997 let mut out = Vec::with_capacity(variants.len());
998 for v in variants {
999 out.push(go(types, index_of, v)?);
1000 }
1001 Type::Union(out)
1002 }
1003 })
1004 }
1005 go(&self.types, &index_of, dt)
1006 };
1007
1008 let mut types = Vec::with_capacity(self.types.len());
1009 for (name, draft) in &self.types {
1010 match draft {
1011 DraftDef::Struct(fields, mode) => {
1012 if fields.len() > u16::MAX as usize {
1013 return Err(Error::BadSchema(format!("too many fields in {name}")));
1014 }
1015 let mut fds = Vec::with_capacity(fields.len());
1016 for (id, fname, dt) in fields {
1017 if fname.len() > u16::MAX as usize || name.len() > u16::MAX as usize {
1018 return Err(Error::BadSchema("name too long".into()));
1019 }
1020 fds.push(FieldDef {
1021 id: *id,
1022 name: fname.clone(),
1023 ty: resolve(dt)?,
1024 default: None,
1025 });
1026 }
1027 fds.sort_by_key(|f| f.id);
1028 for w in fds.windows(2) {
1029 if w[0].id == w[1].id {
1030 return Err(Error::BadSchema(format!(
1031 "duplicate field id {} in {name}",
1032 w[0].id
1033 )));
1034 }
1035 }
1036 types.push(TypeDef::Struct(StructDef {
1037 name: name.clone(),
1038 fields: fds,
1039 mode: *mode,
1040 }));
1041 }
1042 DraftDef::Enum(variants) => {
1043 let mut vs = variants.clone();
1044 vs.sort_by_key(|(v, _)| *v);
1045 for w in vs.windows(2) {
1046 if w[0].0 == w[1].0 {
1047 return Err(Error::BadSchema(format!(
1048 "duplicate variant value {} in {name}",
1049 w[0].0
1050 )));
1051 }
1052 }
1053 types.push(TypeDef::Enum(EnumDef {
1054 name: name.clone(),
1055 variants: vs,
1056 }));
1057 }
1058 }
1059 }
1060 for (sname, fid, value) in &self.defaults {
1063 let d = value_to_default(value).ok_or_else(|| {
1064 Error::BadSchema(format!("default for {sname} field {fid} is not a scalar"))
1065 })?;
1066 let td = types
1067 .iter_mut()
1068 .find(|t| t.name() == sname)
1069 .ok_or_else(|| {
1070 Error::BadSchema(format!("default references unknown type {sname:?}"))
1071 })?;
1072 match td {
1073 TypeDef::Struct(sd) => {
1074 let f = sd.fields.iter_mut().find(|f| f.id == *fid).ok_or_else(|| {
1075 Error::BadSchema(format!(
1076 "default references unknown field {fid} in {sname}"
1077 ))
1078 })?;
1079 f.default = Some(d);
1080 }
1081 TypeDef::Enum(_) => {
1082 return Err(Error::BadSchema(format!(
1083 "cannot set a default on enum type {sname}"
1084 )))
1085 }
1086 }
1087 }
1088 let root_idx = index_of(root)?;
1089 Schema::assemble(types, root_idx)
1090 }
1091}
1092
1093fn value_to_default(v: &Value) -> Option<Default> {
1095 Some(match v {
1096 Value::Bool(b) => Default::Bool(*b),
1097 Value::U8(x) => Default::U8(*x),
1098 Value::U16(x) => Default::U16(*x),
1099 Value::U32(x) => Default::U32(*x),
1100 Value::U64(x) => Default::U64(*x),
1101 Value::I8(x) => Default::I8(*x),
1102 Value::I16(x) => Default::I16(*x),
1103 Value::I32(x) => Default::I32(*x),
1104 Value::I64(x) => Default::I64(*x),
1105 Value::F32(x) => Default::F32(x.to_bits()),
1106 Value::F64(x) => Default::F64(x.to_bits()),
1107 Value::Enum(x) => Default::Enum(*x),
1108 _ => return None,
1109 })
1110}