gel_db_protocol/
structs.rs1use 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<'a>(buf: &'a [u8]) -> Result<Self::Struct<'a>, 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}
66
67impl StructFieldMeta {
68 pub const fn new(type_name: &'static str, constant_size: Option<usize>) -> Self {
69 Self {
70 type_name,
71 constant_size,
72 is_length: false,
73 is_enum: false,
74 is_struct: false,
75 is_array: false,
76 }
77 }
78
79 pub const fn set_length(self) -> Self {
80 Self {
81 is_length: true,
82 ..self
83 }
84 }
85
86 pub const fn set_enum(self) -> Self {
87 Self {
88 is_enum: true,
89 ..self
90 }
91 }
92
93 pub const fn set_struct(self) -> Self {
94 Self {
95 is_struct: true,
96 ..self
97 }
98 }
99
100 pub const fn set_array(self) -> Self {
101 Self {
102 is_array: true,
103 ..self
104 }
105 }
106}
107
108#[derive(Clone, Copy, Debug)]
109pub struct StructFieldComputed {
110 pub field: StructField,
111 pub fixed_offset: Option<usize>,
112}
113
114impl StructFieldComputed {
115 pub const fn new<const N: usize>(fields: [StructField; N]) -> [Self; N] {
116 let mut out: [MaybeUninit<Self>; N] = [const { MaybeUninit::uninit() }; N];
119 let mut i = 0;
120 let mut fixed_offset = Some(0);
121 while i < N {
122 out[i] = MaybeUninit::new(Self {
123 field: fields[i],
124 fixed_offset,
125 });
126 if let Some(fixed_offset_value) = fixed_offset {
127 if let Some(size) = fields[i].meta.constant_size {
128 fixed_offset = Some(fixed_offset_value + size);
129 } else {
130 fixed_offset = None;
131 }
132 } else {
133 fixed_offset = None;
134 }
135 i += 1;
136 }
137 unsafe { out.as_ptr().cast::<[Self; N]>().read() }
141 }
142}
143
144pub struct StructFields {
145 pub fields: &'static [StructFieldComputed],
146 pub constant_size: Option<usize>,
147}
148
149impl StructFields {
150 pub const fn new(fields: &'static [StructFieldComputed]) -> Self {
151 let constant_size = Self::compute_constant_size(fields);
152 Self {
153 fields,
154 constant_size,
155 }
156 }
157
158 const fn compute_constant_size(fields: &'static [StructFieldComputed]) -> Option<usize> {
159 let mut i = 0;
160 let mut size = 0;
161 while i < fields.len() {
162 if let Some(constant_size) = fields[i].field.meta.constant_size {
163 size += constant_size;
164 } else {
165 return None;
166 }
167 i += 1;
168 }
169 Some(size)
170 }
171
172 pub const fn field_by_name(&self, name: &str) -> Option<usize> {
173 let mut i = 0;
174 while i < self.fields.len() {
175 if const_str::equal!(self.fields[i].field.name, name) {
176 return Some(i);
177 }
178 i += 1;
179 }
180 None
181 }
182
183 pub const fn field_by_index(&self, i: usize) -> &StructField {
184 &self.fields[i].field
185 }
186
187 pub const fn field_fixed_offset(&self, field_index: usize) -> Option<usize> {
188 self.fields[field_index].fixed_offset
189 }
190
191 pub const fn length_field_fixed_offset(&self) -> Option<usize> {
192 let mut i = 0;
193 while i < self.fields.len() {
194 if self.fields[i].field.meta.is_length {
195 return Some(i);
196 }
197 i += 1;
198 }
199 None
200 }
201
202 pub const fn constant_size(&self) -> Option<usize> {
203 self.constant_size
204 }
205
206 pub const fn matches_field_constants(&self, buf: &[u8]) -> bool {
207 let mut i = 0;
208 while i < self.fields.len() {
209 if let Some(value) = self.fields[i].field.value {
210 if let Some(fixed_offset) = self.fields[i].fixed_offset {
211 if let Some(constant_size) = self.fields[i].field.meta.constant_size {
212 let buf = buf.split_at(fixed_offset).1;
213 if buf.len() < constant_size {
214 return false;
215 }
216 let buf = buf.split_at(constant_size).0;
217 match constant_size {
218 1 => {
219 if buf[0] != value as u8 {
220 return false;
221 }
222 }
223 2 => {
224 if value
225 != u16::from_be_bytes(*buf.split_first_chunk::<2>().unwrap().0)
226 as _
227 {
228 return false;
229 }
230 }
231 4 => {
232 if value
233 != u32::from_be_bytes(*buf.split_first_chunk::<4>().unwrap().0)
234 as _
235 {
236 return false;
237 }
238 }
239 8 => {
240 if value
241 != u64::from_be_bytes(*buf.split_first_chunk::<8>().unwrap().0)
242 as _
243 {
244 return false;
245 }
246 }
247 16 => {
248 if value
249 != u128::from_be_bytes(
250 *buf.split_first_chunk::<16>().unwrap().0,
251 ) as _
252 {
253 return false;
254 }
255 }
256 _ => panic!("Unsupported constant size for field"),
257 }
258 }
259 }
260 }
261 i += 1;
262 }
263 true
264 }
265}
266
267impl<T: StructAttributeFixedSize<true>> DataTypeFixedSize for T {
268 const SIZE: usize = T::FIXED_SIZE.unwrap();
269}
270
271impl<T: StructAttributeHasLengthField<true> + StructMeta> StructLength for T {
272 fn length_of_buf(buf: &[u8]) -> Option<usize> {
273 let index = T::LENGTH_FIELD_INDEX.unwrap();
274 if buf.len() < index + std::mem::size_of::<u32>() {
275 None
276 } else {
277 let len =
278 <u32 as DataType>::decode(&mut &buf[index..index + std::mem::size_of::<u32>()])
279 .ok()?;
280 Some(index + len as usize)
281 }
282 }
283}
284
285pub trait StructLength: StructMeta {
287 fn length_of_buf(buf: &[u8]) -> Option<usize>;
288}