near_schema_checker_core/
lib.rs

1#![cfg_attr(enable_const_type_id, feature(const_type_id))]
2
3use std::any::TypeId;
4
5pub type TypeName = &'static str;
6pub type FieldName = &'static str;
7pub type VariantName = &'static str;
8pub type Variant = Option<&'static [(FieldName, FieldTypeInfo)]>;
9
10/// Type name and its decomposition into type ids.
11/// Decomposition is defined recursively, starting from type id of the type
12/// itself, followed by decompositions of its generic parameters, respectively.
13/// For example, for `Vec<Vec<u8>>` it will be `[TypeId::of::<Vec<Vec<u8>>>(),
14/// TypeId::of::<Vec<u8>>(), TypeId::of::<u8>()]`.
15// TODO (#11755): consider better candidates for decomposition. For example,
16// `Vec<u8>` is not expected to implement `ProtocolSchema`, so its type id
17// won't help to identify changes in the outer struct.
18pub type FieldTypeInfo = (TypeName, &'static [TypeId]);
19
20#[derive(Debug, Copy, Clone)]
21pub enum ProtocolSchemaInfo {
22    Struct { name: FieldName, type_id: TypeId, fields: &'static [(FieldName, FieldTypeInfo)] },
23    Enum { name: FieldName, type_id: TypeId, variants: &'static [(VariantName, Variant)] },
24}
25
26impl ProtocolSchemaInfo {
27    pub fn type_id(&self) -> TypeId {
28        match self {
29            ProtocolSchemaInfo::Struct { type_id, .. } => *type_id,
30            ProtocolSchemaInfo::Enum { type_id, .. } => *type_id,
31        }
32    }
33
34    pub fn type_name(&self) -> TypeName {
35        match self {
36            ProtocolSchemaInfo::Struct { name, .. } => name,
37            ProtocolSchemaInfo::Enum { name, .. } => name,
38        }
39    }
40}
41
42#[cfg(feature = "protocol_schema")]
43inventory::collect!(ProtocolSchemaInfo);
44
45pub trait ProtocolSchema {
46    /// Workaround to be called directly for the specific type, if this is not
47    /// included by collecting tool for some reason.
48    /// Perhaps a call to this function, which is overridden for each type,
49    /// ensures that linker doesn't optimize the type out, even if all
50    /// implementations are no-op.
51    /// TODO (#11755): understand cases where it may be needed and find a
52    /// proper solution for them.
53    fn ensure_registration() {}
54}
55
56/// Implementation for primitive types.
57macro_rules! primitive_impl {
58    ($($t:ty),*) => {
59        $(
60            impl ProtocolSchema for $t {}
61
62            #[cfg(all(enable_const_type_id, feature = "protocol_schema"))]
63            inventory::submit! {
64                ProtocolSchemaInfo::Struct {
65                    name: stringify!($t),
66                    type_id: TypeId::of::<$t>(),
67                    fields: &[],
68                }
69            }
70        )*
71    }
72}
73
74primitive_impl!(bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, String);