1use crate::dynamic_value;
4use crate::introspect::{self, RawBrandedStructSchema, RawEnumSchema};
5use crate::private::layout;
6use crate::schema_capnp::{annotation, enumerant, field, node};
7use crate::struct_list;
8use crate::traits::{IndexMove, ListIter, ShortListIter};
9use crate::Result;
10
11#[derive(Clone, Copy)]
13pub struct StructSchema {
14 pub(crate) raw: RawBrandedStructSchema,
15 pub(crate) proto: node::Reader<'static>,
16}
17
18impl StructSchema {
19 pub fn new(raw: RawBrandedStructSchema) -> Self {
20 let proto = crate::any_pointer::Reader::new(
21 layout::PointerReader::get_root_from_arena(raw.generic.arena).unwrap(),
22 )
23 .get_as()
24 .unwrap();
25 Self { raw, proto }
26 }
27
28 pub fn get_proto(&self) -> node::Reader<'static> {
29 self.proto
30 }
31
32 pub fn get_newtype_ids(&self) -> &'static [u64] {
40 self.raw.generic.newtype_ids
41 }
42
43 pub fn get_fields(self) -> crate::Result<FieldList> {
44 if let node::Struct(s) = self.proto.which()? {
45 Ok(FieldList {
46 fields: s.get_fields()?,
47 parent: self,
48 })
49 } else {
50 panic!()
51 }
52 }
53
54 pub fn get_field_by_discriminant(self, discriminant: u16) -> Result<Option<Field>> {
55 match self
56 .raw
57 .generic
58 .members_by_discriminant
59 .get(discriminant as usize)
60 {
61 None => Ok(None),
62 Some(&idx) => Ok(Some(self.get_fields()?.get(idx))),
63 }
64 }
65
66 pub fn find_field_by_name(&self, name: &str) -> Result<Option<Field>> {
68 let fields = self.get_fields()?;
69 let mut lower: usize = 0;
70 let mut upper: usize = self.raw.generic.members_by_name.len();
71
72 while lower < upper {
73 let mid: usize = (lower + upper) / 2;
74 let candidate_index = self.raw.generic.members_by_name[mid];
75 let candidate_name = fields.get(candidate_index).get_proto().get_name()?;
76
77 use core::cmp::Ordering;
78 match (&name).partial_cmp(&candidate_name) {
79 Some(Ordering::Equal) => return Ok(Some(fields.get(candidate_index))),
80 Some(Ordering::Greater) => lower = mid + 1,
81 Some(Ordering::Less) => upper = mid,
82 None => unreachable!(),
83 }
84 }
85 Ok(None)
86 }
87
88 pub fn get_field_by_name(&self, name: &str) -> Result<Field> {
90 if let Some(field) = self.find_field_by_name(name)? {
91 Ok(field)
92 } else {
93 let mut error = crate::Error::from_kind(crate::ErrorKind::FieldNotFound);
94 write!(error, "{name}");
95 Err(error)
96 }
97 }
98
99 pub fn get_union_fields(self) -> Result<FieldSubset> {
100 if let node::Struct(s) = self.proto.which()? {
101 Ok(FieldSubset {
102 fields: s.get_fields()?,
103 indices: self.raw.generic.members_by_discriminant,
104 parent: self,
105 })
106 } else {
107 panic!()
108 }
109 }
110
111 pub fn get_non_union_fields(self) -> Result<FieldSubset> {
112 if let node::Struct(s) = self.proto.which()? {
113 Ok(FieldSubset {
114 fields: s.get_fields()?,
115 indices: self.raw.generic.nonunion_members,
116 parent: self,
117 })
118 } else {
119 panic!()
120 }
121 }
122
123 pub fn get_annotations(self) -> Result<AnnotationList> {
124 Ok(AnnotationList {
125 annotations: self.proto.get_annotations()?,
126 child_index: None,
127 get_annotation_type: self.raw.annotation_types,
128 })
129 }
130}
131
132impl From<RawBrandedStructSchema> for StructSchema {
133 fn from(rs: RawBrandedStructSchema) -> StructSchema {
134 StructSchema::new(rs)
135 }
136}
137
138impl ::core::cmp::PartialEq for StructSchema {
139 fn eq(&self, other: &Self) -> bool {
140 self.raw == other.raw
141 }
142}
143
144impl ::core::cmp::Eq for StructSchema {}
145
146impl ::core::hash::Hash for StructSchema {
147 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
148 self.raw.hash(state);
149 }
150}
151
152impl ::core::fmt::Debug for StructSchema {
153 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
154 match self.proto.get_display_name().map(|n| n.to_str()) {
157 Ok(Ok(name)) => write!(f, "StructSchema({name}, {:?})", self.raw.type_id),
158 _ => write!(f, "StructSchema({:?})", self.raw),
159 }
160 }
161}
162
163#[derive(Clone, Copy)]
165pub struct Field {
166 proto: field::Reader<'static>,
167 index: u16,
168 ty: introspect::Type,
169 pub(crate) parent: StructSchema,
170}
171
172impl Field {
173 pub fn get_proto(self) -> field::Reader<'static> {
174 self.proto
175 }
176
177 pub fn get_type(&self) -> introspect::Type {
178 self.ty
179 }
180
181 pub fn get_index(&self) -> u16 {
182 self.index
183 }
184
185 pub fn get_annotations(self) -> Result<AnnotationList> {
186 Ok(AnnotationList {
187 annotations: self.proto.get_annotations()?,
188 child_index: Some(self.index),
189 get_annotation_type: self.parent.raw.annotation_types,
190 })
191 }
192
193 pub fn get_newtype_ids(&self) -> &'static [u64] {
206 match self
207 .parent
208 .raw
209 .generic
210 .field_newtypes
211 .get(self.index as usize)
212 {
213 Some(ids) => ids,
214 None => &[],
215 }
216 }
217}
218
219impl ::core::cmp::PartialEq for Field {
220 fn eq(&self, other: &Self) -> bool {
221 self.parent == other.parent && self.index == other.index
222 }
223}
224impl ::core::cmp::Eq for Field {}
225impl ::core::hash::Hash for Field {
226 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
227 self.parent.hash(state);
228 self.index.hash(state);
229 }
230}
231
232impl ::core::fmt::Debug for Field {
233 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
234 match self.proto.get_name().map(|n| n.to_str()) {
235 Ok(Ok(name)) => write!(f, "Field({name}, {:?})", self.parent),
236 _ => write!(f, "Field(index {}, {:?})", self.index, self.parent),
237 }
238 }
239}
240
241#[derive(Clone, Copy)]
243pub struct FieldList {
244 pub(crate) fields: crate::struct_list::Reader<'static, field::Owned>,
245 pub(crate) parent: StructSchema,
246}
247
248impl FieldList {
249 pub fn len(&self) -> u16 {
250 self.fields.len().try_into().unwrap()
251 }
252
253 pub fn is_empty(&self) -> bool {
254 self.len() == 0
255 }
256
257 pub fn get(self, index: u16) -> Field {
258 Field {
259 proto: self.fields.get(index as u32),
260 index,
261 ty: (self.parent.raw.field_types)(index),
262 parent: self.parent,
263 }
264 }
265
266 pub fn iter(self) -> ShortListIter<Self, Field> {
267 ShortListIter::new(self, self.len())
268 }
269}
270
271impl IndexMove<u16, Field> for FieldList {
272 fn index_move(&self, index: u16) -> Field {
273 self.get(index)
274 }
275}
276
277impl ::core::iter::IntoIterator for FieldList {
278 type Item = Field;
279 type IntoIter = ShortListIter<FieldList, Self::Item>;
280
281 fn into_iter(self) -> Self::IntoIter {
282 self.iter()
283 }
284}
285
286#[derive(Clone, Copy)]
288pub struct FieldSubset {
289 fields: struct_list::Reader<'static, field::Owned>,
290 indices: &'static [u16],
291 parent: StructSchema,
292}
293
294impl FieldSubset {
295 pub fn len(&self) -> u16 {
296 self.indices.len().try_into().unwrap()
297 }
298
299 pub fn is_empty(&self) -> bool {
300 self.len() == 0
301 }
302
303 pub fn get(self, index: u16) -> Field {
304 let index = self.indices[index as usize];
305 Field {
306 proto: self.fields.get(index as u32),
307 index,
308 ty: (self.parent.raw.field_types)(index),
309 parent: self.parent,
310 }
311 }
312
313 pub fn iter(self) -> ShortListIter<Self, Field> {
314 ShortListIter::new(self, self.len())
315 }
316}
317
318impl IndexMove<u16, Field> for FieldSubset {
319 fn index_move(&self, index: u16) -> Field {
320 self.get(index)
321 }
322}
323
324impl ::core::iter::IntoIterator for FieldSubset {
325 type Item = Field;
326 type IntoIter = ShortListIter<FieldSubset, Self::Item>;
327
328 fn into_iter(self) -> Self::IntoIter {
329 self.iter()
330 }
331}
332
333#[derive(Clone, Copy)]
335pub struct EnumSchema {
336 pub(crate) raw: RawEnumSchema,
337 pub(crate) proto: node::Reader<'static>,
338}
339
340impl EnumSchema {
341 pub fn new(raw: RawEnumSchema) -> Self {
342 let proto = crate::any_pointer::Reader::new(
343 layout::PointerReader::get_root_from_arena(raw.arena).unwrap(),
344 )
345 .get_as()
346 .unwrap();
347 Self { raw, proto }
348 }
349
350 pub fn get_proto(self) -> node::Reader<'static> {
351 self.proto
352 }
353
354 pub fn get_enumerants(self) -> crate::Result<EnumerantList> {
355 if let node::Enum(s) = self.proto.which()? {
356 Ok(EnumerantList {
357 enumerants: s.get_enumerants()?,
358 parent: self,
359 })
360 } else {
361 panic!()
362 }
363 }
364
365 pub fn get_annotations(self) -> Result<AnnotationList> {
366 Ok(AnnotationList {
367 annotations: self.proto.get_annotations()?,
368 child_index: None,
369 get_annotation_type: self.raw.annotation_types,
370 })
371 }
372}
373
374impl From<RawEnumSchema> for EnumSchema {
375 fn from(re: RawEnumSchema) -> EnumSchema {
376 EnumSchema::new(re)
377 }
378}
379
380impl ::core::cmp::PartialEq for EnumSchema {
381 fn eq(&self, other: &Self) -> bool {
382 self.raw == other.raw
383 }
384}
385
386impl ::core::cmp::Eq for EnumSchema {}
387
388impl ::core::hash::Hash for EnumSchema {
389 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
390 self.raw.hash(state);
391 }
392}
393
394impl ::core::fmt::Debug for EnumSchema {
395 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
396 match self.proto.get_display_name().map(|n| n.to_str()) {
397 Ok(Ok(name)) => write!(f, "EnumSchema({name})"),
398 _ => write!(f, "EnumSchema({:?})", self.raw),
399 }
400 }
401}
402
403#[derive(Clone, Copy)]
405pub struct Enumerant {
406 ordinal: u16,
407 parent: EnumSchema,
408 proto: enumerant::Reader<'static>,
409}
410
411impl Enumerant {
412 pub fn get_containing_enum(self) -> EnumSchema {
413 self.parent
414 }
415
416 pub fn get_ordinal(self) -> u16 {
417 self.ordinal
418 }
419
420 pub fn get_proto(self) -> enumerant::Reader<'static> {
421 self.proto
422 }
423
424 pub fn get_annotations(self) -> Result<AnnotationList> {
425 Ok(AnnotationList {
426 annotations: self.proto.get_annotations()?,
427 child_index: Some(self.ordinal),
428 get_annotation_type: self.parent.raw.annotation_types,
429 })
430 }
431}
432
433impl ::core::cmp::PartialEq for Enumerant {
434 fn eq(&self, other: &Self) -> bool {
435 self.parent == other.parent && self.ordinal == other.ordinal
436 }
437}
438impl ::core::cmp::Eq for Enumerant {}
439impl ::core::hash::Hash for Enumerant {
440 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
441 self.parent.hash(state);
442 self.ordinal.hash(state);
443 }
444}
445
446impl ::core::fmt::Debug for Enumerant {
447 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
448 match self.proto.get_name().map(|n| n.to_str()) {
449 Ok(Ok(name)) => write!(f, "Enumerant({name}, {:?})", self.parent),
450 _ => write!(f, "Enumerant(ordinal {}, {:?})", self.ordinal, self.parent),
451 }
452 }
453}
454
455#[derive(Clone, Copy)]
457pub struct EnumerantList {
458 enumerants: struct_list::Reader<'static, enumerant::Owned>,
459 parent: EnumSchema,
460}
461
462impl EnumerantList {
463 pub fn len(&self) -> u16 {
464 self.enumerants.len().try_into().unwrap()
465 }
466
467 pub fn is_empty(&self) -> bool {
468 self.len() == 0
469 }
470
471 pub fn get(self, ordinal: u16) -> Enumerant {
472 Enumerant {
473 proto: self.enumerants.get(ordinal as u32),
474 ordinal,
475 parent: self.parent,
476 }
477 }
478
479 pub fn iter(self) -> ShortListIter<Self, Enumerant> {
480 ShortListIter::new(self, self.len())
481 }
482}
483
484impl IndexMove<u16, Enumerant> for EnumerantList {
485 fn index_move(&self, index: u16) -> Enumerant {
486 self.get(index)
487 }
488}
489
490impl ::core::iter::IntoIterator for EnumerantList {
491 type Item = Enumerant;
492 type IntoIter = ShortListIter<Self, Self::Item>;
493
494 fn into_iter(self) -> Self::IntoIter {
495 self.iter()
496 }
497}
498
499#[derive(Clone, Copy)]
501pub struct Annotation {
502 proto: annotation::Reader<'static>,
503 ty: introspect::Type,
504}
505
506impl Annotation {
507 pub fn get_value(self) -> Result<dynamic_value::Reader<'static>> {
509 dynamic_value::Reader::new(self.proto.get_value()?, self.ty)
510 }
511
512 pub fn get_id(&self) -> u64 {
514 self.proto.get_id()
515 }
516
517 pub fn get_type(&self) -> introspect::Type {
519 self.ty
520 }
521}
522
523#[derive(Clone, Copy)]
525pub struct AnnotationList {
526 annotations: struct_list::Reader<'static, annotation::Owned>,
527 child_index: Option<u16>,
528 get_annotation_type: fn(Option<u16>, u32) -> introspect::Type,
529}
530
531impl AnnotationList {
532 pub fn len(&self) -> u32 {
533 self.annotations.len()
534 }
535
536 pub fn is_empty(&self) -> bool {
537 self.len() == 0
538 }
539
540 pub fn get(self, index: u32) -> Annotation {
541 let proto = self.annotations.get(index);
542 let ty = (self.get_annotation_type)(self.child_index, index);
543 Annotation { proto, ty }
544 }
545
546 pub fn find(self, id: u64) -> Option<Annotation> {
549 self.iter().find(|&annotation| annotation.get_id() == id)
550 }
551
552 pub fn iter(self) -> ListIter<Self, Annotation> {
553 ListIter::new(self, self.len())
554 }
555}
556
557impl IndexMove<u32, Annotation> for AnnotationList {
558 fn index_move(&self, index: u32) -> Annotation {
559 self.get(index)
560 }
561}
562
563impl ::core::iter::IntoIterator for AnnotationList {
564 type Item = Annotation;
565 type IntoIter = ListIter<Self, Self::Item>;
566
567 fn into_iter(self) -> Self::IntoIter {
568 self.iter()
569 }
570}
571
572#[cfg(test)]
573mod tests {
574 use crate::introspect::Introspect;
575
576 #[cfg(feature = "std")]
577 #[test]
578 fn fields_can_be_hashed() {
579 let crate::introspect::TypeVariant::Struct(struct_schema) =
580 crate::schema_capnp::node::Owned::introspect().which()
581 else {
582 panic!("Expected a struct schema");
583 };
584
585 let struct_schema = crate::schema::StructSchema::new(struct_schema);
586
587 let display_name = struct_schema.get_field_by_name("displayName").unwrap();
588 let id = struct_schema.get_field_by_name("id").unwrap();
589
590 let mut map = std::collections::HashMap::new();
591 map.insert(display_name, 1);
592 map.insert(id, 2);
593
594 assert_eq!(map.get(&display_name), Some(&1));
595 assert_eq!(map.get(&id), Some(&2));
596 assert_eq!(
597 map.get(&struct_schema.get_field_by_name("displayName").unwrap()),
598 Some(&1)
599 );
600 assert_eq!(
601 map.get(&struct_schema.get_field_by_name("id").unwrap()),
602 Some(&2)
603 );
604 }
605
606 #[test]
607 fn fields_can_be_compared() {
608 let crate::introspect::TypeVariant::Struct(struct_schema) =
609 crate::schema_capnp::node::Owned::introspect().which()
610 else {
611 panic!("Expected a struct schema");
612 };
613
614 let struct_schema = crate::schema::StructSchema::new(struct_schema);
615
616 let display_name = struct_schema.get_field_by_name("displayName").unwrap();
617 let id = struct_schema.get_field_by_name("id").unwrap();
618
619 assert_eq!(display_name, display_name);
620 assert_eq!(
621 display_name,
622 struct_schema.get_field_by_name("displayName").unwrap()
623 );
624 assert_eq!(id, id);
625 assert_eq!(id, struct_schema.get_field_by_name("id").unwrap());
626
627 assert_ne!(display_name, id);
628 }
629
630 #[cfg(feature = "std")]
631 #[test]
632 fn schemas_can_be_hashed() {
633 let node_schema = {
634 let crate::introspect::TypeVariant::Struct(schema) =
635 crate::schema_capnp::node::Owned::introspect().which()
636 else {
637 panic!("Expected a struct schema");
638 };
639
640 crate::schema::StructSchema::new(schema)
641 };
642 let cgr_schema = {
643 let crate::introspect::TypeVariant::Struct(schema) =
644 crate::schema_capnp::code_generator_request::Owned::introspect().which()
645 else {
646 panic!("Expected a struct schema");
647 };
648 crate::schema::StructSchema::new(schema)
649 };
650
651 let mut map = std::collections::HashMap::new();
652 map.insert(node_schema, 1);
653 map.insert(cgr_schema, 2);
654
655 assert_eq!(map.get(&node_schema), Some(&1));
656 assert_eq!(map.get(&cgr_schema), Some(&2));
657 }
658
659 #[test]
660 fn schemas_can_be_compared() {
661 let node_schema = {
662 let crate::introspect::TypeVariant::Struct(schema) =
663 crate::schema_capnp::node::Owned::introspect().which()
664 else {
665 panic!("Expected a struct schema");
666 };
667
668 crate::schema::StructSchema::new(schema)
669 };
670 let cgr_schema = {
671 let crate::introspect::TypeVariant::Struct(schema) =
672 crate::schema_capnp::code_generator_request::Owned::introspect().which()
673 else {
674 panic!("Expected a struct schema");
675 };
676 crate::schema::StructSchema::new(schema)
677 };
678
679 assert_eq!(node_schema, node_schema);
680 assert_eq!(cgr_schema, cgr_schema);
681 assert_ne!(node_schema, cgr_schema);
682 }
683
684 #[test]
685 fn enum_schemas_can_be_compared() {
686 let crate::introspect::TypeVariant::Enum(raw) =
687 crate::schema_capnp::ElementSize::introspect().which()
688 else {
689 panic!("Expected an enum schema");
690 };
691 let schema = crate::schema::EnumSchema::new(raw);
692
693 assert_eq!(schema, crate::schema::EnumSchema::new(raw));
694
695 let enumerants = schema.get_enumerants().unwrap();
696 assert_eq!(enumerants.get(0), enumerants.get(0));
697 assert_ne!(enumerants.get(0), enumerants.get(1));
698 }
699
700 #[cfg(feature = "std")]
701 #[test]
702 fn enumerants_can_be_hashed() {
703 let crate::introspect::TypeVariant::Enum(raw) =
704 crate::schema_capnp::ElementSize::introspect().which()
705 else {
706 panic!("Expected an enum schema");
707 };
708 let schema = crate::schema::EnumSchema::new(raw);
709 let enumerants = schema.get_enumerants().unwrap();
710
711 let mut map = std::collections::HashMap::new();
712 map.insert(enumerants.get(0), 0);
713 map.insert(enumerants.get(1), 1);
714
715 assert_eq!(map.get(&enumerants.get(0)), Some(&0));
716 assert_eq!(map.get(&enumerants.get(1)), Some(&1));
717 }
718
719 #[test]
720 fn type_variants_can_be_compared() {
721 use crate::introspect::TypeVariant;
722
723 assert_eq!(u32::introspect().which(), TypeVariant::UInt32);
724 assert_ne!(u32::introspect().which(), TypeVariant::Int32);
725 assert_eq!(
726 crate::schema_capnp::node::Owned::introspect().which(),
727 crate::schema_capnp::node::Owned::introspect().which()
728 );
729 assert_ne!(
730 crate::schema_capnp::node::Owned::introspect().which(),
731 crate::schema_capnp::code_generator_request::Owned::introspect().which()
732 );
733 }
734}