plotnik_lib/bytecode/
type_meta.rs

1//! Type metadata definitions for bytecode format.
2
3use super::{StringId, TypeId};
4
5// Re-export the shared TypeKind
6pub use crate::type_system::TypeKind;
7
8/// Convenience aliases for bytecode-specific naming (ArrayStar/ArrayPlus).
9impl TypeKind {
10    /// Alias for `ArrayZeroOrMore` (T*).
11    pub const ARRAY_STAR: Self = Self::ArrayZeroOrMore;
12    /// Alias for `ArrayOneOrMore` (T+).
13    pub const ARRAY_PLUS: Self = Self::ArrayOneOrMore;
14}
15
16/// TypeMeta section header (8 bytes).
17///
18/// Contains counts for the three sub-sections. Located at `type_meta_offset`.
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20#[repr(C)]
21pub struct TypeMetaHeader {
22    /// Number of TypeDef entries.
23    pub(crate) type_defs_count: u16,
24    /// Number of TypeMember entries.
25    pub(crate) type_members_count: u16,
26    /// Number of TypeName entries.
27    pub(crate) type_names_count: u16,
28    /// Padding for alignment.
29    pub(crate) _pad: u16,
30}
31
32const _: () = assert!(std::mem::size_of::<TypeMetaHeader>() == 8);
33
34impl TypeMetaHeader {
35    /// Create a new header.
36    pub fn new(type_defs_count: u16, type_members_count: u16, type_names_count: u16) -> Self {
37        Self {
38            type_defs_count,
39            type_members_count,
40            type_names_count,
41            _pad: 0,
42        }
43    }
44
45    /// Decode from 8 bytes.
46    pub fn from_bytes(bytes: &[u8]) -> Self {
47        assert!(bytes.len() >= 8, "TypeMetaHeader too short");
48        Self {
49            type_defs_count: u16::from_le_bytes([bytes[0], bytes[1]]),
50            type_members_count: u16::from_le_bytes([bytes[2], bytes[3]]),
51            type_names_count: u16::from_le_bytes([bytes[4], bytes[5]]),
52            _pad: 0,
53        }
54    }
55
56    /// Encode to 8 bytes.
57    pub fn to_bytes(&self) -> [u8; 8] {
58        let mut bytes = [0u8; 8];
59        bytes[0..2].copy_from_slice(&self.type_defs_count.to_le_bytes());
60        bytes[2..4].copy_from_slice(&self.type_members_count.to_le_bytes());
61        bytes[4..6].copy_from_slice(&self.type_names_count.to_le_bytes());
62        // _pad is always 0
63        bytes
64    }
65
66    pub fn type_defs_count(&self) -> u16 {
67        self.type_defs_count
68    }
69    pub fn type_members_count(&self) -> u16 {
70        self.type_members_count
71    }
72    pub fn type_names_count(&self) -> u16 {
73        self.type_names_count
74    }
75}
76
77/// Type definition entry (4 bytes).
78///
79/// Semantics of `data` and `count` depend on `kind`:
80/// - Wrappers (Optional, ArrayStar, ArrayPlus): `data` = inner TypeId, `count` = 0
81/// - Struct/Enum: `data` = member index, `count` = member count
82/// - Alias: `data` = target TypeId, `count` = 0
83#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84#[repr(C)]
85pub struct TypeDef {
86    /// For wrappers/alias: inner/target TypeId.
87    /// For Struct/Enum: index into TypeMembers section.
88    data: u16,
89    /// Member count (0 for wrappers/alias, field/variant count for composites).
90    count: u8,
91    /// TypeKind discriminant.
92    kind: u8,
93}
94
95const _: () = assert!(std::mem::size_of::<TypeDef>() == 4);
96
97/// Structured view of TypeDef data, eliminating the need for Option-returning accessors.
98#[derive(Clone, Copy, Debug, PartialEq, Eq)]
99pub enum TypeData {
100    /// Primitive types: Void, Node, String.
101    Primitive(TypeKind),
102    /// Wrapper types: Optional, ArrayZeroOrMore, ArrayOneOrMore, Alias.
103    Wrapper { kind: TypeKind, inner: TypeId },
104    /// Composite types: Struct, Enum.
105    Composite {
106        kind: TypeKind,
107        member_start: u16,
108        member_count: u8,
109    },
110}
111
112impl TypeDef {
113    /// Create a builtin type (Void, Node, String).
114    pub fn builtin(kind: TypeKind) -> Self {
115        Self {
116            data: 0,
117            count: 0,
118            kind: kind as u8,
119        }
120    }
121
122    /// Create a placeholder slot (to be filled later).
123    pub fn placeholder() -> Self {
124        Self {
125            data: 0,
126            count: 0,
127            kind: 0,
128        }
129    }
130
131    /// Create a wrapper type (Optional, ArrayStar, ArrayPlus).
132    pub fn wrapper(kind: TypeKind, inner: TypeId) -> Self {
133        Self {
134            data: inner.0,
135            count: 0,
136            kind: kind as u8,
137        }
138    }
139
140    /// Create a composite type (Struct, Enum).
141    pub fn composite(kind: TypeKind, member_start: u16, member_count: u8) -> Self {
142        Self {
143            data: member_start,
144            count: member_count,
145            kind: kind as u8,
146        }
147    }
148
149    /// Create an optional wrapper type.
150    pub fn optional(inner: TypeId) -> Self {
151        Self::wrapper(TypeKind::Optional, inner)
152    }
153
154    /// Create an alias type.
155    pub fn alias(target: TypeId) -> Self {
156        Self::wrapper(TypeKind::Alias, target)
157    }
158
159    /// Create an ArrayStar (T*) wrapper type.
160    pub fn array_star(element: TypeId) -> Self {
161        Self::wrapper(TypeKind::ARRAY_STAR, element)
162    }
163
164    /// Create an ArrayPlus (T+) wrapper type.
165    pub fn array_plus(element: TypeId) -> Self {
166        Self::wrapper(TypeKind::ARRAY_PLUS, element)
167    }
168
169    /// Create a struct type.
170    pub fn struct_type(member_start: u16, member_count: u8) -> Self {
171        Self::composite(TypeKind::Struct, member_start, member_count)
172    }
173
174    /// Create an enum type.
175    pub fn enum_type(member_start: u16, member_count: u8) -> Self {
176        Self::composite(TypeKind::Enum, member_start, member_count)
177    }
178
179    /// Decode from 4 bytes (crate-internal deserialization).
180    pub(crate) fn from_bytes(bytes: &[u8]) -> Self {
181        Self {
182            data: u16::from_le_bytes([bytes[0], bytes[1]]),
183            count: bytes[2],
184            kind: bytes[3],
185        }
186    }
187
188    /// Encode to 4 bytes.
189    pub fn to_bytes(&self) -> [u8; 4] {
190        let mut bytes = [0u8; 4];
191        bytes[0..2].copy_from_slice(&self.data.to_le_bytes());
192        bytes[2] = self.count;
193        bytes[3] = self.kind;
194        bytes
195    }
196
197    /// Classify this type definition into a structured enum.
198    ///
199    /// # Panics
200    /// Panics if the kind byte is invalid (corrupted bytecode).
201    pub fn classify(&self) -> TypeData {
202        let kind = TypeKind::from_u8(self.kind)
203            .unwrap_or_else(|| panic!("invalid TypeKind byte: {}", self.kind));
204        match kind {
205            TypeKind::Void | TypeKind::Node | TypeKind::String => TypeData::Primitive(kind),
206            TypeKind::Optional
207            | TypeKind::ArrayZeroOrMore
208            | TypeKind::ArrayOneOrMore
209            | TypeKind::Alias => TypeData::Wrapper {
210                kind,
211                inner: TypeId(self.data),
212            },
213            TypeKind::Struct | TypeKind::Enum => TypeData::Composite {
214                kind,
215                member_start: self.data,
216                member_count: self.count,
217            },
218        }
219    }
220}
221
222/// Maps a name to a type (4 bytes).
223///
224/// Only named types (definitions, aliases) have entries here.
225/// Entries are sorted lexicographically by name for binary search.
226#[derive(Clone, Copy, Debug, PartialEq, Eq)]
227#[repr(C)]
228pub struct TypeName {
229    /// StringId of the type name.
230    pub(crate) name: StringId,
231    /// TypeId this name refers to.
232    pub(crate) type_id: TypeId,
233}
234
235const _: () = assert!(std::mem::size_of::<TypeName>() == 4);
236
237impl TypeName {
238    /// Create a new type name entry.
239    pub fn new(name: StringId, type_id: TypeId) -> Self {
240        Self { name, type_id }
241    }
242
243    /// Encode to 4 bytes.
244    pub fn to_bytes(&self) -> [u8; 4] {
245        let mut bytes = [0u8; 4];
246        bytes[0..2].copy_from_slice(&self.name.get().to_le_bytes());
247        bytes[2..4].copy_from_slice(&self.type_id.0.to_le_bytes());
248        bytes
249    }
250
251    pub fn name(&self) -> StringId {
252        self.name
253    }
254    pub fn type_id(&self) -> TypeId {
255        self.type_id
256    }
257}
258
259/// Field or variant entry (4 bytes).
260#[derive(Clone, Copy, Debug, PartialEq, Eq)]
261#[repr(C)]
262pub struct TypeMember {
263    /// Field/variant name.
264    pub(crate) name: StringId,
265    /// Type of this field/variant.
266    pub(crate) type_id: TypeId,
267}
268
269const _: () = assert!(std::mem::size_of::<TypeMember>() == 4);
270
271impl TypeMember {
272    /// Create a new type member entry.
273    pub fn new(name: StringId, type_id: TypeId) -> Self {
274        Self { name, type_id }
275    }
276
277    /// Encode to 4 bytes.
278    pub fn to_bytes(&self) -> [u8; 4] {
279        let mut bytes = [0u8; 4];
280        bytes[0..2].copy_from_slice(&self.name.get().to_le_bytes());
281        bytes[2..4].copy_from_slice(&self.type_id.0.to_le_bytes());
282        bytes
283    }
284
285    pub fn name(&self) -> StringId {
286        self.name
287    }
288    pub fn type_id(&self) -> TypeId {
289        self.type_id
290    }
291}