1use {
4 bytes::BufMut,
5 sealed::sealed,
6 serde::{Deserialize, Serialize},
7 smallvec::SmallVec,
8 std::any::TypeId,
9};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum Type {
14 Primitive(Primitive),
16
17 String,
19
20 Array(Box<Array>),
22
23 Object(Box<Object>),
25}
26
27#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
28pub enum Primitive {
30 Void,
32
33 Bool,
35
36 Int32,
38
39 Int64,
41
42 Float32,
44
45 Float64,
47}
48
49#[derive(Debug, Copy, Clone, PartialEq)]
51pub enum TypeRef<'a> {
52 Primitive(Primitive),
54
55 String,
57
58 Array(&'a Array),
60
61 Object(&'a Object),
63}
64
65#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
67pub struct Object {
68 class: String,
69 fields: SmallVec<[Field; 2]>,
70}
71
72#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub struct Field {
75 name: String,
76 ty: Type,
77 offset: usize,
78}
79
80#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
82pub struct Array {
83 elem_ty: Type,
84 len: usize,
85}
86
87impl Type {
88 pub fn size(&self) -> usize {
90 self.as_ref().size()
91 }
92
93 pub fn as_ref(&self) -> TypeRef<'_> {
95 match self {
96 Type::Primitive(primitive) => TypeRef::Primitive(*primitive),
97 Type::String => TypeRef::String,
98 Type::Array(array) => TypeRef::Array(array.as_ref()),
99 Type::Object(object) => TypeRef::Object(object.as_ref()),
100 }
101 }
102
103 pub fn as_object(&self) -> Option<&Object> {
105 match self {
106 Type::Object(object) => Some(object),
107 _ => None,
108 }
109 }
110
111 pub(crate) fn type_id(&self) -> Option<TypeId> {
113 match self {
114 Type::Primitive(Primitive::Void) => Some(TypeId::of::<()>()),
115 Type::Primitive(Primitive::Bool) => Some(TypeId::of::<bool>()),
116 Type::Primitive(Primitive::Int32) => Some(TypeId::of::<i32>()),
117 Type::Primitive(Primitive::Int64) => Some(TypeId::of::<i64>()),
118 Type::Primitive(Primitive::Float32) => Some(TypeId::of::<f32>()),
119 Type::Primitive(Primitive::Float64) => Some(TypeId::of::<f64>()),
120 _ => None,
121 }
122 }
123
124 pub fn is<T>(&self) -> bool
126 where
127 T: IsPrimitive + 'static,
128 {
129 TypeId::of::<T>()
130 == self
131 .type_id()
132 .expect("primitive types always have a type id")
133 }
134}
135
136fn write_packed_int(mut buffer: impl BufMut, mut value: u64) {
137 while value >= 0x80 {
138 buffer.put_u8((value & 0x7F) as u8 | 0x80);
139 value >>= 7;
140 }
141 buffer.put_u8(value as u8);
142}
143
144fn write_null_terminated_string(mut buffer: impl BufMut, string: impl AsRef<str>) {
145 buffer.put_slice(string.as_ref().as_bytes());
146 buffer.put_u8(0);
147}
148
149impl TypeRef<'_> {
150 pub fn size(&self) -> usize {
152 match self {
153 TypeRef::Primitive(Primitive::Void) => 0,
154 TypeRef::Primitive(Primitive::Bool) => 4,
155 TypeRef::Primitive(Primitive::Int32) => 4,
156 TypeRef::Primitive(Primitive::Int64) => 8,
157 TypeRef::Primitive(Primitive::Float32) => 4,
158 TypeRef::Primitive(Primitive::Float64) => 8,
159 TypeRef::String => 4,
160 TypeRef::Array(array) => array.size(),
161 TypeRef::Object(object) => object.size(),
162 }
163 }
164
165 pub fn to_owned(&self) -> Type {
167 match *self {
168 TypeRef::Primitive(primitive) => Type::Primitive(primitive),
169 TypeRef::String => Type::String,
170 TypeRef::Array(array) => Type::Array(Box::new(array.clone())),
171 TypeRef::Object(object) => Type::Object(Box::new(object.clone())),
172 }
173 }
174
175 pub(crate) fn serialise_as_choc_type(&self) -> Vec<u8> {
176 match self {
177 TypeRef::Primitive(Primitive::Void) => vec![0],
178 TypeRef::Primitive(Primitive::Int32) => vec![1],
179 TypeRef::Primitive(Primitive::Int64) => vec![2],
180 TypeRef::Primitive(Primitive::Float32) => vec![3],
181 TypeRef::Primitive(Primitive::Float64) => vec![4],
182 TypeRef::Primitive(Primitive::Bool) => vec![5],
183 TypeRef::String => todo!("serialising string types is not yet supported"),
184 TypeRef::Array(array) => {
185 let mut buffer = vec![];
186 buffer.put_u8(7);
187 buffer.put_u8(if array.is_empty() { 0 } else { 1 });
188 write_packed_int(&mut buffer, array.len() as u64);
189 buffer.put_slice(array.elem_ty().as_ref().serialise_as_choc_type().as_slice());
190 buffer
191 }
192 TypeRef::Object(object) => {
193 let mut buffer = vec![];
194 buffer.put_u8(8);
195 write_packed_int(&mut buffer, object.fields.len() as u64);
196 write_null_terminated_string(&mut buffer, object.class.as_str());
197 for field in object.fields() {
198 buffer.put_slice(field.ty().as_ref().serialise_as_choc_type().as_slice());
199 write_null_terminated_string(&mut buffer, field.name());
200 }
201 buffer
202 }
203 }
204 }
205}
206
207impl Array {
208 pub fn new(elem_ty: impl Into<Type>, len: usize) -> Self {
210 Array {
211 elem_ty: elem_ty.into(),
212 len,
213 }
214 }
215
216 pub fn size(&self) -> usize {
218 self.elem_ty.size() * self.len
219 }
220
221 pub fn elem_ty(&self) -> &Type {
223 &self.elem_ty
224 }
225
226 pub fn len(&self) -> usize {
228 self.len
229 }
230
231 pub fn is_empty(&self) -> bool {
233 self.len == 0
234 }
235}
236
237impl Object {
238 pub fn new(class: impl AsRef<str>) -> Self {
240 Object {
241 class: class.as_ref().to_string(),
242 fields: SmallVec::default(),
243 }
244 }
245
246 pub fn size(&self) -> usize {
248 self.fields.iter().map(|field| field.ty.size()).sum()
249 }
250
251 pub fn add_field(&mut self, name: impl AsRef<str>, ty: impl Into<Type>) {
253 let size = self.size();
254 self.fields.push(Field {
255 name: name.as_ref().to_owned(),
256 ty: ty.into(),
257 offset: size,
258 });
259 }
260
261 pub fn with_field(mut self, name: impl AsRef<str>, ty: impl Into<Type>) -> Self {
263 self.add_field(name, ty.into());
264 self
265 }
266
267 pub fn fields(&self) -> impl Iterator<Item = &Field> {
269 self.fields.iter()
270 }
271}
272
273impl From<Primitive> for Type {
274 fn from(primitive: Primitive) -> Self {
275 Type::Primitive(primitive)
276 }
277}
278
279impl From<Array> for Type {
280 fn from(array: Array) -> Self {
281 Type::Array(Box::new(array))
282 }
283}
284
285impl From<Object> for Type {
286 fn from(object: Object) -> Self {
287 Type::Object(Box::new(object))
288 }
289}
290
291impl Field {
292 pub fn name(&self) -> &str {
294 &self.name
295 }
296
297 pub fn ty(&self) -> &Type {
299 &self.ty
300 }
301
302 pub fn offset(&self) -> usize {
304 self.offset
305 }
306}
307
308#[sealed]
310pub trait IsPrimitive {}
311
312macro_rules! impl_is_primitive {
313 ($($ty:ty),*) => {
314 $(
315 #[sealed]
316 impl IsPrimitive for $ty {}
317 )*
318 };
319}
320
321impl_is_primitive!(bool, i32, i64, f32, f64);
322
323#[sealed]
325pub trait IsScalar: IsPrimitive {}
326
327macro_rules! impl_is_scalar {
328 ($($ty:ty),*) => {
329 $(
330 #[sealed]
331 impl IsScalar for $ty {}
332 )*
333 };
334}
335
336impl_is_scalar!(i32, i64, f32, f64);
337
338#[sealed]
340pub trait IsFloatingPoint {}
341
342#[sealed]
343impl IsFloatingPoint for f32 {}
344
345#[sealed]
346impl IsFloatingPoint for f64 {}