1use std::{
2 convert::TryInto,
3 ffi::CStr,
4 fmt::Debug,
5 fmt::{self, Formatter},
6 os::raw::c_char,
7 str,
8};
9
10use crate::{type_id::TypeId, Guid, StructDefinition};
11
12#[repr(C)]
25pub struct TypeDefinition<'a> {
26 pub name: *const c_char,
28 pub(crate) size_in_bits: u32,
30 pub(crate) alignment: u8,
32 pub data: TypeDefinitionData<'a>,
34}
35
36impl<'a> Debug for TypeDefinition<'a> {
37 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
38 f.debug_struct("TypeDefinition")
39 .field("name", &self.name())
40 .field("size_in_bits", &self.size_in_bits)
41 .field("alignment", &self.alignment)
42 .field("data", &self.data)
43 .finish()
44 }
45}
46
47#[cfg(feature = "serde")]
48impl<'a> serde::Serialize for TypeDefinition<'a> {
49 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50 where
51 S: serde::Serializer,
52 {
53 use serde::ser::SerializeStruct;
54
55 let mut s = serializer.serialize_struct("TypeDefinition", 4)?;
56 s.serialize_field("name", self.name())?;
57 s.serialize_field("size_in_bits", &self.size_in_bits)?;
58 s.serialize_field("alignment", &self.alignment)?;
59 s.serialize_field("data", &self.data)?;
60 s.end()
61 }
62}
63
64#[repr(u8)]
66#[derive(Debug, PartialEq, Eq)]
67#[cfg_attr(feature = "serde", derive(serde::Serialize))]
68pub enum TypeDefinitionData<'a> {
69 Struct(StructDefinition<'a>),
71}
72
73impl<'a> TypeDefinition<'a> {
74 pub fn is_instance_of(&self, type_id: &TypeId<'a>) -> bool {
76 match (&self.data, type_id) {
77 (TypeDefinitionData::Struct(s), TypeId::Concrete(guid)) => &s.guid == guid,
78 _ => false,
79 }
80 }
81
82 pub fn name(&self) -> &str {
84 unsafe { str::from_utf8_unchecked(CStr::from_ptr(self.name).to_bytes()) }
85 }
86
87 pub fn as_concrete(&self) -> &Guid {
89 match &self.data {
90 TypeDefinitionData::Struct(s) => &s.guid,
91 }
92 }
93
94 pub fn as_struct(&self) -> Option<&StructDefinition> {
96 let TypeDefinitionData::Struct(s) = &self.data;
97 Some(s)
98 }
99
100 pub fn size_in_bits(&self) -> usize {
102 self.size_in_bits
103 .try_into()
104 .expect("cannot convert size in bits to platform size")
105 }
106
107 pub fn size_in_bytes(&self) -> usize {
109 ((self.size_in_bits + 7) / 8)
110 .try_into()
111 .expect("cannot covert size in bytes to platform size")
112 }
113
114 pub fn alignment(&self) -> usize {
116 self.alignment
117 .try_into()
118 .expect("cannot convert alignment to platform size")
119 }
120}
121
122impl<'a> fmt::Display for TypeDefinition<'a> {
123 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
124 write!(f, "{}", self.name())
125 }
126}
127
128impl<'a> PartialEq for TypeDefinition<'a> {
129 fn eq(&self, other: &Self) -> bool {
130 self.size_in_bits == other.size_in_bits
131 && self.alignment == other.alignment
132 && self.data == other.data
133 }
134}
135
136impl<'a> Eq for TypeDefinition<'a> {}
137
138unsafe impl<'a> Send for TypeDefinition<'a> {}
139unsafe impl<'a> Sync for TypeDefinition<'a> {}
140
141impl<'a> TypeDefinitionData<'a> {
142 pub fn is_struct(&self) -> bool {
144 matches!(self, TypeDefinitionData::Struct(_))
145 }
146}
147
148pub trait HasStaticTypeName {
150 fn type_name() -> &'static CStr;
152}
153
154#[cfg(test)]
155mod tests {
156 use std::ffi::CString;
157
158 use crate::test_utils::{fake_struct_definition, fake_type_definition, FAKE_TYPE_NAME};
159
160 use super::TypeDefinitionData;
161
162 #[test]
163 fn test_type_definition_name() {
164 let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
165 let field_names = &[];
166 let field_types = &[];
167 let field_offsets = &[];
168 let struct_info = fake_struct_definition(
169 &type_name,
170 field_names,
171 field_types,
172 field_offsets,
173 Default::default(),
174 );
175
176 let type_definition =
177 fake_type_definition(&type_name, 1, 1, TypeDefinitionData::Struct(struct_info));
178 assert_eq!(type_definition.name(), FAKE_TYPE_NAME);
179 }
180
181 #[test]
182 fn test_type_definition_size_alignment() {
183 let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
184 let field_names = &[];
185 let field_types = &[];
186 let field_offsets = &[];
187 let struct_info = fake_struct_definition(
188 &type_name,
189 field_names,
190 field_types,
191 field_offsets,
192 Default::default(),
193 );
194
195 let type_definition =
196 fake_type_definition(&type_name, 24, 8, TypeDefinitionData::Struct(struct_info));
197
198 assert_eq!(type_definition.size_in_bits(), 24);
199 assert_eq!(type_definition.size_in_bytes(), 3);
200 assert_eq!(type_definition.alignment(), 8);
201 }
202
203 #[test]
204 fn test_type_definition_group_struct() {
205 let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
206 let field_names = &[];
207 let field_types = &[];
208 let field_offsets = &[];
209 let struct_info = fake_struct_definition(
210 &type_name,
211 field_names,
212 field_types,
213 field_offsets,
214 Default::default(),
215 );
216
217 let type_definition =
218 fake_type_definition(&type_name, 1, 1, TypeDefinitionData::Struct(struct_info));
219 assert!(type_definition.data.is_struct());
220 }
221
222 #[test]
223 fn test_type_definition_eq() {
224 let type_name = CString::new(FAKE_TYPE_NAME).expect("Invalid fake type name.");
225 let field_names = &[];
226 let field_types = &[];
227 let field_offsets = &[];
228 let struct_info = fake_struct_definition(
229 &type_name,
230 field_names,
231 field_types,
232 field_offsets,
233 Default::default(),
234 );
235
236 let type_definition =
237 fake_type_definition(&type_name, 1, 1, TypeDefinitionData::Struct(struct_info));
238 assert_eq!(type_definition, type_definition);
239 }
240}