1use std::{alloc::Layout, any::TypeId, collections::HashSet, fmt::Formatter};
2
3use nonmax::NonMaxU32;
4
5#[derive(Clone, Copy)]
7pub struct Shape {
8 pub name: &'static str,
10
11 pub typeid: TypeId,
13
14 pub layout: Layout,
16
17 pub innards: Innards,
19
20 pub set_to_default: Option<fn(*mut u8)>,
22
23 pub drop_in_place: Option<DropFunction>,
30}
31
32impl PartialEq for Shape {
33 fn eq(&self, other: &Self) -> bool {
34 self.typeid == other.typeid
35 }
36}
37
38impl Eq for Shape {}
39
40impl std::hash::Hash for Shape {
41 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
42 self.typeid.hash(state);
43 }
44}
45
46impl Shape {
47 const INDENT: usize = 2;
48
49 pub fn pretty_print_recursive(&self, f: &mut Formatter) -> std::fmt::Result {
51 self.pretty_print_recursive_internal(f, &mut HashSet::new(), 0)
52 }
53
54 fn pretty_print_recursive_internal(
55 &self,
56 f: &mut Formatter,
57 printed_schemas: &mut HashSet<Shape>,
58 indent: usize,
59 ) -> std::fmt::Result {
60 if !printed_schemas.insert(*self) {
61 writeln!(
62 f,
63 "{:indent$}\x1b[1;33m{}\x1b[0m (\x1b[1;31malready printed\x1b[0m)",
64 "",
65 self.name,
66 indent = indent
67 )?;
68 return Ok(());
69 }
70
71 writeln!(
72 f,
73 "{:indent$}\x1b[1;33m{}\x1b[0m (size: \x1b[1;34m{}\x1b[0m, align: \x1b[1;35m{}\x1b[0m)",
74 "",
75 self.name,
76 self.layout.size(),
77 self.layout.align(),
78 indent = indent
79 )?;
80
81 match &self.innards {
82 Innards::Struct { fields } => {
83 for field in *fields {
84 writeln!(
85 f,
86 "{:indent$}\x1b[1;32m{}\x1b[0m: ",
87 "",
88 field.name,
89 indent = indent + Self::INDENT
90 )?;
91 field.shape.get().pretty_print_recursive_internal(
92 f,
93 printed_schemas,
94 indent + Self::INDENT * 2,
95 )?;
96 }
97 }
98 Innards::HashMap { value_shape } => {
99 writeln!(
100 f,
101 "{:indent$}\x1b[1;36mHashMap with arbitrary keys and value shape:\x1b[0m",
102 "",
103 indent = indent + Self::INDENT
104 )?;
105 value_shape.get().pretty_print_recursive_internal(
106 f,
107 printed_schemas,
108 indent + Self::INDENT * 2,
109 )?;
110 }
111 Innards::Array(elem_schema) => {
112 write!(
113 f,
114 "{:indent$}\x1b[1;36mArray of:\x1b[0m ",
115 "",
116 indent = indent + Self::INDENT
117 )?;
118 elem_schema.get().pretty_print_recursive_internal(
119 f,
120 printed_schemas,
121 indent + Self::INDENT * 2,
122 )?;
123 }
124 Innards::Transparent(inner_schema) => {
125 write!(
126 f,
127 "{:indent$}\x1b[1;36mTransparent wrapper for:\x1b[0m ",
128 "",
129 indent = indent + Self::INDENT
130 )?;
131 inner_schema.get().pretty_print_recursive_internal(
132 f,
133 printed_schemas,
134 indent + Self::INDENT * 2,
135 )?;
136 }
137 Innards::Scalar(scalar) => {
138 writeln!(
139 f,
140 "{:indent$}\x1b[1;36mScalar:\x1b[0m \x1b[1;33m{:?}\x1b[0m",
141 "",
142 scalar,
143 indent = indent
144 )?;
145 }
146 }
147
148 Ok(())
149 }
150}
151
152impl std::fmt::Debug for Shape {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 self.pretty_print_recursive(f)
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
160pub enum Innards {
161 Struct { fields: &'static [Field<'static>] },
163
164 HashMap { value_shape: ShapeDesc },
166
167 Array(ShapeDesc),
169
170 Transparent(ShapeDesc),
172
173 Scalar(Scalar),
175}
176
177impl Innards {
178 pub fn static_fields(&self) -> &'static [Field<'static>] {
180 match self {
181 Innards::Struct { fields } => fields,
182 _ => &[],
183 }
184 }
185}
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
187pub struct Field<'s> {
188 pub name: &'s str,
190
191 pub shape: ShapeDesc,
193
194 pub offset: Option<NonMaxU32>,
204}
205
206#[derive(Debug, Clone, Copy)]
208pub enum SetFieldOutcome {
209 Accepted,
211
212 Rejected,
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
217#[non_exhaustive]
218pub enum Scalar {
219 String,
221
222 Bytes,
224
225 I8,
226 I16,
227 I32,
228 I64,
229 I128,
230
231 U8,
232 U16,
233 U32,
234 U64,
235 U128,
236
237 F32,
238 F64,
239
240 Boolean,
241
242 Nothing,
244}
245
246pub type DropFunction = fn(*mut u8);
248
249#[derive(Clone, Copy)]
252pub struct ShapeDesc(pub fn() -> Shape);
253
254impl From<fn() -> Shape> for ShapeDesc {
255 fn from(f: fn() -> Shape) -> Self {
256 Self(f)
257 }
258}
259
260impl ShapeDesc {
261 pub fn get(&self) -> Shape {
263 (self.0)()
264 }
265}
266
267impl PartialEq for ShapeDesc {
268 fn eq(&self, other: &Self) -> bool {
269 if std::ptr::eq(self.0 as *const (), other.0 as *const ()) {
270 true
271 } else {
272 let self_shape = self.0();
273 let other_shape = other.0();
274 self_shape == other_shape
275 }
276 }
277}
278
279impl Eq for ShapeDesc {}
280
281impl std::hash::Hash for ShapeDesc {
282 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
283 (self.0 as *const ()).hash(state);
285 }
286}
287
288impl std::fmt::Debug for ShapeDesc {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 self.get().fmt(f)
291 }
292}