1use crate::{str::Str, StableLike};
16use sha2_const_stable::Sha256;
17
18type NextField = StableLike<Option<&'static FieldReport>, usize>;
20
21#[crate::stabby]
23#[derive(Debug, PartialEq, Eq, Clone, Copy)]
24pub struct TypeReport {
25 pub name: Str<'static>,
27 pub module: Str<'static>,
29 pub fields: NextField,
31 pub tyty: TyTy,
33 pub version: u32,
35}
36
37impl core::fmt::Display for TypeReport {
38 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
39 let Self {
40 name,
41 module,
42 version,
43 tyty,
44 ..
45 } = self;
46 write!(f, "{tyty:?} {module} :: {name} (version{version}) {{")?;
47 for FieldReport { name, ty, .. } in self.fields() {
48 write!(f, "{name}: {ty}, ")?
49 }
50 write!(f, "}}")
51 }
52}
53impl core::hash::Hash for TypeReport {
54 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
55 self.name.hash(state);
56 self.module.hash(state);
57 for field in self.fields() {
58 field.hash(state);
59 }
60 self.version.hash(state);
61 self.tyty.hash(state);
62 }
63}
64
65impl TypeReport {
66 pub fn is_compatible(&self, other: &Self) -> bool {
68 self.name == other.name
69 && self.module == other.module
70 && self.version == other.version
71 && self.tyty == other.tyty
72 && self
73 .fields()
74 .zip(other.fields())
75 .all(|(s, o)| s.name == o.name && s.ty.is_compatible(o.ty))
76 }
77}
78
79#[crate::stabby]
81#[repr(u8)]
82#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
83pub enum TyTy {
84 Struct,
86 Enum(Str<'static>),
88 Union,
90}
91
92#[crate::stabby]
94#[derive(Debug, PartialEq, Eq, Clone, Copy)]
95pub struct FieldReport {
96 pub name: Str<'static>,
98 pub ty: &'static TypeReport,
100 pub next_field: NextField,
102}
103impl core::hash::Hash for FieldReport {
104 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
105 self.name.hash(state);
106 self.ty.hash(state);
107 }
108}
109
110impl TypeReport {
111 pub const fn fields(&self) -> Fields {
113 Fields(self.fields.value)
114 }
115}
116#[crate::stabby]
118pub struct Fields(Option<&'static FieldReport>);
119impl Fields {
120 pub const fn next_const(self) -> (Self, Option<&'static FieldReport>) {
122 match self.0 {
123 Some(field) => (Self(*field.next_field.as_ref()), Some(field)),
124 None => (self, None),
125 }
126 }
127}
128impl Iterator for Fields {
129 type Item = &'static FieldReport;
130 fn next(&mut self) -> Option<Self::Item> {
131 let field = self.0.take()?;
132 self.0 = field.next_field.value;
133 Some(field)
134 }
135}
136
137const fn hash_report(mut hash: Sha256, report: &TypeReport) -> Sha256 {
138 hash = hash
139 .update(report.module.as_str().as_bytes())
140 .update(report.name.as_str().as_bytes());
141 hash = match report.tyty {
142 crate::report::TyTy::Struct => hash.update(&[0]),
143 crate::report::TyTy::Union => hash.update(&[1]),
144 crate::report::TyTy::Enum(s) => hash.update(s.as_str().as_bytes()),
145 };
146 let mut fields = report.fields();
147 while let (new, Some(next)) = fields.next_const() {
148 fields = new;
149 hash = hash_report(hash.update(next.name.as_str().as_bytes()), next.ty)
150 }
151 hash
152}
153
154#[rustversion::attr(nightly, allow(unnecessary_transmutes))]
155const ARCH_INFO: [u8; 8] = [
156 0,
157 core::mem::size_of::<usize>() as u8,
158 core::mem::align_of::<usize>() as u8,
159 core::mem::size_of::<&()>() as u8,
160 core::mem::align_of::<&()>() as u8,
161 core::mem::align_of::<u128>() as u8,
162 unsafe { core::mem::transmute::<[u8; 2], u16>([0, 1]) } as u8,
164 0,
165];
166
167pub const fn gen_id(report: &TypeReport) -> u64 {
172 let [hash @ .., _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =
173 hash_report(Sha256::new(), report).finalize();
174 u64::from_le_bytes(hash) ^ u64::from_le_bytes(ARCH_INFO)
175}