1use std::mem::MaybeUninit;
2
3use crate::prelude::*;
4
5pub trait EnumMeta {
7 const VALUES: &'static [(&'static str, usize)];
8}
9
10pub trait StructMeta: Copy + Clone + std::fmt::Debug {
14 type Struct<'a>: Copy + Clone + std::fmt::Debug;
15 const FIELDS: StructFields;
16 const FIELD_COUNT: usize = Self::FIELDS.fields.len();
17 const IS_FIXED_SIZE: bool = Self::FIELDS.constant_size().is_some();
18 const FIXED_SIZE: Option<usize> = Self::FIELDS.constant_size();
19 const LENGTH_FIELD_INDEX: Option<usize> = Self::FIELDS.length_field_fixed_offset();
20 const HAS_LENGTH_FIELD: bool = Self::LENGTH_FIELD_INDEX.is_some();
21
22 fn new(buf: &[u8]) -> Result<Self::Struct<'_>, ParseError>;
23 fn to_vec(&self) -> Vec<u8>;
24}
25
26pub trait StructAttributeFixedSize<const IS_FIXED_SIZE: bool>: StructMeta {}
32
33pub trait StructAttributeHasLengthField<const HAS_LENGTH_FIELD: bool>: StructMeta {}
39
40pub trait StructAttributeFieldCount<const FIELD_COUNT: usize>: StructMeta {}
45
46#[derive(Clone, Copy, Debug)]
47pub struct StructField {
48 pub name: &'static str,
50 pub meta: &'static StructFieldMeta,
52 pub value: Option<usize>,
54}
55
56#[derive(Clone, Copy, Debug, Default)]
58pub struct StructFieldMeta {
59 pub type_name: &'static str,
60 pub constant_size: Option<usize>,
61 pub is_length: bool,
62 pub is_enum: bool,
63 pub is_struct: bool,
64 pub is_array: bool,
65 pub is_primitive: bool,
66}
67
68impl StructFieldMeta {
69 pub const fn new(type_name: &'static str, constant_size: Option<usize>) -> Self {
70 Self {
71 type_name,
72 constant_size,
73 is_length: false,
74 is_enum: false,
75 is_struct: false,
76 is_array: false,
77 is_primitive: false,
78 }
79 }
80
81 pub const fn set_length(self) -> Self {
82 Self {
83 is_length: true,
84 ..self
85 }
86 }
87
88 pub const fn set_enum(self) -> Self {
89 Self {
90 is_enum: true,
91 ..self
92 }
93 }
94
95 pub const fn set_struct(self) -> Self {
96 Self {
97 is_struct: true,
98 ..self
99 }
100 }
101
102 pub const fn set_array(self) -> Self {
103 Self {
104 is_array: true,
105 ..self
106 }
107 }
108
109 pub const fn set_primitive(self) -> Self {
110 Self {
111 is_primitive: true,
112 ..self
113 }
114 }
115}
116
117#[derive(Clone, Copy, Debug)]
118pub struct StructFieldComputed {
119 pub field: StructField,
120 pub fixed_offset: Option<usize>,
121}
122
123impl StructFieldComputed {
124 pub const fn new<const N: usize>(fields: [StructField; N]) -> [Self; N] {
125 let mut out: [MaybeUninit<Self>; N] = [const { MaybeUninit::uninit() }; N];
128 let mut i = 0;
129 let mut fixed_offset = Some(0);
130 while i < N {
131 out[i] = MaybeUninit::new(Self {
132 field: fields[i],
133 fixed_offset,
134 });
135 if let Some(fixed_offset_value) = fixed_offset {
136 if let Some(size) = fields[i].meta.constant_size {
137 fixed_offset = Some(fixed_offset_value + size);
138 } else {
139 fixed_offset = None;
140 }
141 } else {
142 fixed_offset = None;
143 }
144 i += 1;
145 }
146 unsafe { out.as_ptr().cast::<[Self; N]>().read() }
150 }
151}
152
153pub struct StructFields {
154 pub fields: &'static [StructFieldComputed],
155 pub constant_size: Option<usize>,
156}
157
158impl StructFields {
159 pub const fn new(fields: &'static [StructFieldComputed]) -> Self {
160 let constant_size = Self::compute_constant_size(fields);
161 Self {
162 fields,
163 constant_size,
164 }
165 }
166
167 const fn compute_constant_size(fields: &'static [StructFieldComputed]) -> Option<usize> {
168 let mut i = 0;
169 let mut size = 0;
170 while i < fields.len() {
171 if let Some(constant_size) = fields[i].field.meta.constant_size {
172 size += constant_size;
173 } else {
174 return None;
175 }
176 i += 1;
177 }
178 Some(size)
179 }
180
181 pub const fn field_by_name(&self, name: &str) -> Option<usize> {
182 let mut i = 0;
183 while i < self.fields.len() {
184 if const_str::equal!(self.fields[i].field.name, name) {
185 return Some(i);
186 }
187 i += 1;
188 }
189 None
190 }
191
192 pub const fn field_by_index(&self, i: usize) -> &StructField {
193 &self.fields[i].field
194 }
195
196 pub const fn field_fixed_offset(&self, field_index: usize) -> Option<usize> {
197 self.fields[field_index].fixed_offset
198 }
199
200 pub const fn length_field_fixed_offset(&self) -> Option<usize> {
201 let mut i = 0;
202 while i < self.fields.len() {
203 if self.fields[i].field.meta.is_length {
204 return Some(i);
205 }
206 i += 1;
207 }
208 None
209 }
210
211 pub const fn constant_size(&self) -> Option<usize> {
212 self.constant_size
213 }
214
215 pub const fn matches_field_constants(&self, buf: &[u8]) -> bool {
216 let mut i = 0;
217 while i < self.fields.len() {
218 if let Some(value) = self.fields[i].field.value {
219 if let Some(fixed_offset) = self.fields[i].fixed_offset {
220 if let Some(constant_size) = self.fields[i].field.meta.constant_size {
221 if buf.len() < fixed_offset {
222 return false;
223 }
224 let buf = buf.split_at(fixed_offset).1;
225 if buf.len() < constant_size {
226 return false;
227 }
228 let buf = buf.split_at(constant_size).0;
229 match constant_size {
230 1 => {
231 if buf[0] != value as u8 {
232 return false;
233 }
234 }
235 2 => {
236 if value
237 != u16::from_be_bytes(*buf.split_first_chunk::<2>().unwrap().0)
238 as _
239 {
240 return false;
241 }
242 }
243 4 => {
244 if value
245 != u32::from_be_bytes(*buf.split_first_chunk::<4>().unwrap().0)
246 as _
247 {
248 return false;
249 }
250 }
251 8 => {
252 if value
253 != u64::from_be_bytes(*buf.split_first_chunk::<8>().unwrap().0)
254 as _
255 {
256 return false;
257 }
258 }
259 16 => {
260 if value
261 != u128::from_be_bytes(
262 *buf.split_first_chunk::<16>().unwrap().0,
263 ) as _
264 {
265 return false;
266 }
267 }
268 _ => panic!("Unsupported constant size for field"),
269 }
270 }
271 }
272 }
273 i += 1;
274 }
275 true
276 }
277}
278
279impl<T: StructAttributeFixedSize<true>> DataTypeFixedSize for T {
280 const SIZE: usize = T::FIXED_SIZE.unwrap();
281}
282
283impl<T: StructAttributeHasLengthField<true> + StructMeta> StructLength for T {
284 fn length_of_buf(buf: &[u8]) -> Option<usize> {
285 let index = T::LENGTH_FIELD_INDEX.unwrap();
286 if buf.len() < index + std::mem::size_of::<u32>() {
287 None
288 } else {
289 let len = <u32 as DecoderFor<'_, u32>>::decode_for(
290 &mut &buf[index..index + std::mem::size_of::<u32>()],
291 )
292 .ok()?;
293 Some(index + len as usize)
294 }
295 }
296}
297
298pub trait StructLength: StructMeta {
300 fn length_of_buf(buf: &[u8]) -> Option<usize>;
301}