1use std::{alloc::Layout, any::TypeId, collections::HashSet, fmt::Formatter, ptr::NonNull};
2
3#[derive(Clone, Copy)]
5pub struct Shape {
6 pub name: NameFn,
8
9 pub typeid: TypeId,
11
12 pub layout: Layout,
14
15 pub innards: Innards,
17
18 pub set_to_default: Option<SetToDefaultFn>,
20
21 pub drop_in_place: Option<DropFn>,
28}
29
30pub type NameFn = fn(f: &mut std::fmt::Formatter) -> std::fmt::Result;
31
32impl std::fmt::Display for Shape {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 (self.name)(f)
36 }
37}
38
39pub type SetToDefaultFn = unsafe fn(*mut u8);
41
42pub type DropFn = unsafe fn(*mut u8);
44
45impl PartialEq for Shape {
46 fn eq(&self, other: &Self) -> bool {
47 self.typeid == other.typeid
48 }
49}
50
51impl Eq for Shape {}
52
53impl std::hash::Hash for Shape {
54 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55 self.typeid.hash(state);
56 }
57}
58
59impl Shape {
60 const INDENT: usize = 2;
61
62 pub fn pretty_print_recursive(&self, f: &mut Formatter) -> std::fmt::Result {
64 self.pretty_print_recursive_internal(f, &mut HashSet::new(), 0)
65 }
66
67 fn pretty_print_recursive_internal(
68 &self,
69 f: &mut Formatter,
70 printed_schemas: &mut HashSet<Shape>,
71 indent: usize,
72 ) -> std::fmt::Result {
73 if !printed_schemas.insert(*self) {
74 write!(
75 f,
76 "{:indent$}\x1b[1;33m",
77 "",
78 indent = indent
79 )?;
80 (self.name)(f)?;
81 writeln!(
82 f,
83 "\x1b[0m (\x1b[1;31malready printed\x1b[0m)"
84 )?;
85 return Ok(());
86 }
87
88 write!(
89 f,
90 "{:indent$}\x1b[1;33m",
91 "",
92 indent = indent
93 )?;
94 (self.name)(f)?;
95 writeln!(
96 f,
97 "\x1b[0m (size: \x1b[1;34m{}\x1b[0m, align: \x1b[1;35m{}\x1b[0m)",
98 self.layout.size(),
99 self.layout.align()
100 )?;
101
102 match &self.innards {
103 Innards::Struct { fields } => {
104 for field in *fields {
105 writeln!(
106 f,
107 "{:indent$}\x1b[1;32m{}\x1b[0m: ",
108 "",
109 field.name,
110 indent = indent + Self::INDENT
111 )?;
112 field.shape.get().pretty_print_recursive_internal(
113 f,
114 printed_schemas,
115 indent + Self::INDENT * 2,
116 )?;
117 }
118 }
119 Innards::HashMap { value_shape } => {
120 writeln!(
121 f,
122 "{:indent$}\x1b[1;36mHashMap with arbitrary keys and value shape:\x1b[0m",
123 "",
124 indent = indent + Self::INDENT
125 )?;
126 value_shape.get().pretty_print_recursive_internal(
127 f,
128 printed_schemas,
129 indent + Self::INDENT * 2,
130 )?;
131 }
132 Innards::Array(elem_schema) => {
133 write!(
134 f,
135 "{:indent$}\x1b[1;36mArray of:\x1b[0m ",
136 "",
137 indent = indent + Self::INDENT
138 )?;
139 elem_schema.get().pretty_print_recursive_internal(
140 f,
141 printed_schemas,
142 indent + Self::INDENT * 2,
143 )?;
144 }
145 Innards::Transparent(inner_schema) => {
146 write!(
147 f,
148 "{:indent$}\x1b[1;36mTransparent wrapper for:\x1b[0m ",
149 "",
150 indent = indent + Self::INDENT
151 )?;
152 inner_schema.get().pretty_print_recursive_internal(
153 f,
154 printed_schemas,
155 indent + Self::INDENT * 2,
156 )?;
157 }
158 Innards::Scalar(scalar) => {
159 writeln!(
160 f,
161 "{:indent$}\x1b[1;36mScalar:\x1b[0m \x1b[1;33m{:?}\x1b[0m",
162 "",
163 scalar,
164 indent = indent
165 )?;
166 }
167 }
168
169 Ok(())
170 }
171
172 pub fn known_fields(&self) -> &'static [Field] {
174 match self.innards {
175 Innards::Struct { fields } => fields,
176 _ => &[],
177 }
178 }
179
180 pub fn field_by_name(&self, name: &str) -> Option<&Field> {
182 self.known_fields().iter().find(|field| field.name == name)
183 }
184
185 pub fn field_by_index(&self, index: usize) -> Result<&Field, FieldError> {
187 match self.innards {
188 Innards::Struct { fields } => fields.get(index).ok_or(FieldError::IndexOutOfBounds),
189 _ => Err(FieldError::NotAStruct),
190 }
191 }
192
193 pub fn dangling(&self) -> NonNull<u8> {
203 let dang = NonNull::dangling();
204 let offset = dang.align_offset(self.layout.align());
205 unsafe { dang.byte_add(offset) }
206 }
207}
208
209#[derive(Debug)]
211pub enum FieldError {
212 NoStaticFields,
216
217 NoSuchStaticField,
220
221 IndexOutOfBounds,
224
225 NotAStruct,
227}
228
229impl std::error::Error for FieldError {}
230
231impl std::fmt::Display for FieldError {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 match self {
234 FieldError::NoStaticFields => write!(f, "No static fields available"),
235 FieldError::NoSuchStaticField => write!(f, "No such static field"),
236 FieldError::IndexOutOfBounds => write!(f, "Index out of bounds"),
237 FieldError::NotAStruct => write!(f, "Not a struct"),
238 }
239 }
240}
241
242impl std::fmt::Debug for Shape {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 self.pretty_print_recursive(f)
245 }
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
250pub enum Innards {
251 Struct { fields: &'static [Field] },
253
254 HashMap { value_shape: ShapeDesc },
256
257 Array(ShapeDesc),
259
260 Transparent(ShapeDesc),
262
263 Scalar(Scalar),
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268pub struct Field {
269 pub name: &'static str,
271
272 pub shape: ShapeDesc,
274
275 pub offset: usize,
285}
286
287#[derive(Debug, Clone, Copy)]
289pub enum SetFieldOutcome {
290 Accepted,
292
293 Rejected,
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
298#[non_exhaustive]
299pub enum Scalar {
300 String,
302
303 Bytes,
305
306 I8,
307 I16,
308 I32,
309 I64,
310 I128,
311
312 U8,
313 U16,
314 U32,
315 U64,
316 U128,
317
318 F32,
319 F64,
320
321 Boolean,
322
323 Nothing,
325}
326
327#[derive(Clone, Copy)]
330pub struct ShapeDesc(pub fn() -> Shape);
331
332impl From<fn() -> Shape> for ShapeDesc {
333 fn from(f: fn() -> Shape) -> Self {
334 Self(f)
335 }
336}
337
338impl ShapeDesc {
339 #[inline(always)]
341 pub fn get(&self) -> Shape {
342 (self.0)()
343 }
344}
345
346impl PartialEq for ShapeDesc {
347 fn eq(&self, other: &Self) -> bool {
348 if std::ptr::eq(self.0 as *const (), other.0 as *const ()) {
349 true
350 } else {
351 let self_shape = self.0();
352 let other_shape = other.0();
353 self_shape == other_shape
354 }
355 }
356}
357
358impl Eq for ShapeDesc {}
359
360impl std::hash::Hash for ShapeDesc {
361 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
362 (self.0 as *const ()).hash(state);
364 }
365}
366
367impl std::fmt::Debug for ShapeDesc {
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 self.get().fmt(f)
370 }
371}