1use core::ffi;
2use core::fmt;
3use core::mem;
4use core::slice;
5use core::write;
6
7use crate::parse::verify_name;
8use crate::Encoding;
9use crate::EncodingBox;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12pub(crate) enum NestingLevel {
13 Top,
14 Within,
15 Bottom,
16}
17
18impl NestingLevel {
19 pub(crate) const fn new() -> Self {
20 Self::Top
21 }
22
23 pub(crate) const fn bitfield(self) -> Self {
24 self
27 }
28
29 pub(crate) const fn indirection(self, kind: IndirectionKind) -> Self {
30 match kind {
31 IndirectionKind::Atomic => Self::Bottom,
33 IndirectionKind::Pointer => match self {
35 Self::Top => Self::Within,
36 Self::Bottom | Self::Within => Self::Bottom,
37 },
38 }
39 }
40
41 pub(crate) const fn array(self) -> Self {
42 self
44 }
45
46 pub(crate) const fn container_include_fields(self) -> Option<Self> {
47 match self {
48 Self::Top | Self::Within => {
49 Some(Self::Within)
51 }
52 Self::Bottom => None,
53 }
54 }
55}
56
57pub(crate) fn compare_encodings<E1: EncodingType, E2: EncodingType>(
58 enc1: &E1,
59 enc2: &E2,
60 level: NestingLevel,
61 include_all: bool,
62) -> bool {
63 use Helper::*;
64 let level = if include_all {
69 NestingLevel::new()
70 } else {
71 level
72 };
73
74 match (enc1.helper(), enc2.helper()) {
75 (Primitive(p1), Primitive(p2)) => p1.equivalents().contains(&p2),
76 (BitField(size1, Some((offset1, type1))), BitField(size2, Some((offset2, type2)))) => {
77 size1 == size2
78 && offset1 == offset2
79 && compare_encodings(type1, type2, level.bitfield(), include_all)
80 }
81 (BitField(size1, None), BitField(size2, None)) => size1 == size2,
82 (BitField(_, _), BitField(_, _)) => false,
86 (Indirection(kind1, t1), Indirection(kind2, t2)) => {
87 kind1 == kind2 && compare_encodings(t1, t2, level.indirection(kind1), include_all)
88 }
89 (Array(len1, item1), Array(len2, item2)) => {
90 len1 == len2 && compare_encodings(item1, item2, level.array(), include_all)
91 }
92 (Container(kind1, name1, items1), Container(kind2, name2, items2)) => {
93 kind1 == kind2 && name1 == name2 && {
94 if let Some(level) = level.container_include_fields() {
95 if items1.is_empty() || items2.is_empty() {
97 return true;
98 }
99 if items1.len() != items2.len() {
100 return false;
101 }
102 for (item1, item2) in items1.iter().zip(items2.iter()) {
103 if !compare_encodings(item1, item2, level, include_all) {
104 return false;
105 }
106 }
107 true
108 } else {
109 true
110 }
111 }
112 }
113 (NoneInvalid, NoneInvalid) => true,
114 (_, _) => false,
115 }
116}
117
118#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
119#[non_exhaustive]
120pub(crate) enum Primitive {
121 Char,
122 Short,
123 Int,
124 Long,
125 LongLong,
126 UChar,
127 UShort,
128 UInt,
129 ULong,
130 ULongLong,
131 Float,
132 Double,
133 LongDouble,
134 FloatComplex,
135 DoubleComplex,
136 LongDoubleComplex,
137 Bool,
138 Void,
139 String,
140 Object,
141 Block,
142 Class,
143 Sel,
144 Unknown,
145}
146
147impl Primitive {
148 pub(crate) const fn to_str(self) -> &'static str {
149 use Primitive::*;
150 match self {
151 Char => "c",
152 Short => "s",
153 Int => "i",
154 Long => "l",
155 LongLong => "q",
156 UChar => "C",
157 UShort => "S",
158 UInt => "I",
159 ULong => "L",
160 ULongLong => "Q",
161 Float => "f",
162 Double => "d",
163 LongDouble => "D",
164 FloatComplex => "jf",
165 DoubleComplex => "jd",
166 LongDoubleComplex => "jD",
167 Bool => "B",
168 Void => "v",
169 String => "*",
170 Object => "@",
171 Block => "@?",
172 Class => "#",
173 Sel => ":",
174 Unknown => "?",
175 }
176 }
177
178 pub(crate) fn equivalents(&self) -> &[Self] {
183 match self {
184 Self::Block | Self::Object | Self::Class => &[Self::Block, Self::Object, Self::Class],
185 _ => slice::from_ref(self),
186 }
187 }
188
189 pub(crate) const fn size(self) -> Option<usize> {
190 match self {
191 Self::Bool => Some(1),
197 Self::Char => Some(mem::size_of::<ffi::c_char>()),
199 Self::UChar => Some(mem::size_of::<ffi::c_uchar>()),
200 Self::Short => Some(mem::size_of::<ffi::c_short>()),
201 Self::UShort => Some(mem::size_of::<ffi::c_ushort>()),
202 Self::Int => Some(mem::size_of::<ffi::c_int>()),
203 Self::UInt => Some(mem::size_of::<ffi::c_uint>()),
204 Self::Long => Some(mem::size_of::<ffi::c_long>()),
205 Self::ULong => Some(mem::size_of::<ffi::c_ulong>()),
206 Self::LongLong => Some(mem::size_of::<ffi::c_longlong>()),
207 Self::ULongLong => Some(mem::size_of::<ffi::c_ulonglong>()),
208 Self::Float => Some(mem::size_of::<ffi::c_float>()),
209 Self::Double => Some(mem::size_of::<ffi::c_double>()),
210 #[cfg(any(
212 target_arch = "x86_64",
213 all(target_arch = "x86", target_vendor = "apple"),
214 all(target_arch = "aarch64", not(target_vendor = "apple")),
215 ))]
216 Self::LongDouble => Some(16),
217 #[cfg(all(target_arch = "x86", not(target_vendor = "apple")))]
218 Self::LongDouble => Some(12),
219 #[cfg(any(
220 target_arch = "arm",
221 all(target_arch = "aarch64", target_vendor = "apple"),
222 ))]
223 Self::LongDouble => Some(8),
224 Self::FloatComplex => Some(mem::size_of::<ffi::c_float>() * 2),
225 Self::DoubleComplex => Some(mem::size_of::<ffi::c_double>() * 2),
226 Self::LongDoubleComplex => match Self::LongDouble.size() {
227 Some(size) => Some(size * 2),
228 None => None,
229 },
230 Self::String | Self::Object | Self::Block | Self::Class | Self::Sel => {
232 Some(mem::size_of::<*const ()>())
233 }
234 Self::Void | Self::Unknown => None,
236 }
237 }
238}
239
240#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
241pub(crate) enum IndirectionKind {
242 Atomic,
243 Pointer,
244}
245
246impl IndirectionKind {
247 pub(crate) const fn prefix(self) -> char {
248 self.prefix_byte() as char
249 }
250
251 pub(crate) const fn prefix_byte(self) -> u8 {
252 match self {
253 Self::Atomic => b'A',
254 Self::Pointer => b'^',
255 }
256 }
257}
258
259#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
260pub(crate) enum ContainerKind {
261 Struct,
262 Union,
263}
264
265impl ContainerKind {
266 pub(crate) const fn start(self) -> char {
267 self.start_byte() as char
268 }
269
270 pub(crate) const fn end(self) -> char {
271 self.end_byte() as char
272 }
273
274 pub(crate) const fn start_byte(self) -> u8 {
275 match self {
276 Self::Struct => b'{',
277 Self::Union => b'(',
278 }
279 }
280
281 pub(crate) const fn end_byte(self) -> u8 {
282 match self {
283 Self::Struct => b'}',
284 Self::Union => b')',
285 }
286 }
287}
288
289impl fmt::Display for ContainerKind {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 match self {
292 Self::Struct => write!(f, "struct"),
293 Self::Union => write!(f, "union"),
294 }
295 }
296}
297
298pub(crate) trait EncodingType: Sized + fmt::Debug {
299 fn helper(&self) -> Helper<'_, Self>;
300}
301
302#[derive(Clone, Debug, PartialEq, Eq, Hash)]
303#[non_exhaustive]
304pub(crate) enum Helper<'a, E = Encoding> {
305 Primitive(Primitive),
306 BitField(u8, Option<&'a (u64, E)>),
307 Indirection(IndirectionKind, &'a E),
308 Array(u64, &'a E),
309 Container(ContainerKind, &'a str, &'a [E]),
310 NoneInvalid,
311}
312
313impl<E: EncodingType> Helper<'_, E> {
314 pub(crate) fn fmt(&self, f: &mut fmt::Formatter<'_>, level: NestingLevel) -> fmt::Result {
315 match self {
316 Self::Primitive(primitive) => {
317 write!(f, "{}", primitive.to_str())?;
318 }
319 Self::BitField(size, None) => {
320 write!(f, "b{size}")?;
321 }
322 Self::BitField(size, Some((offset, t))) => {
323 write!(f, "b{offset}")?;
324 t.helper().fmt(f, level.bitfield())?;
325 write!(f, "{size}")?;
326 }
327 Self::Indirection(kind, t) => {
328 write!(f, "{}", kind.prefix())?;
329 t.helper().fmt(f, level.indirection(*kind))?;
330 }
331 Self::Array(len, item) => {
332 write!(f, "[")?;
333 write!(f, "{len}")?;
334 item.helper().fmt(f, level.array())?;
335 write!(f, "]")?;
336 }
337 Self::Container(kind, name, items) => {
338 write!(f, "{}", kind.start())?;
339 write!(f, "{name}")?;
340 if let Some(level) = level.container_include_fields() {
341 write!(f, "=")?;
342 for item in *items {
343 item.helper().fmt(f, level)?;
344 }
345 }
346 write!(f, "{}", kind.end())?;
347 }
348 Self::NoneInvalid => {}
349 }
350 Ok(())
351 }
352
353 pub(crate) fn size(&self, level: NestingLevel) -> Option<usize> {
354 match self {
356 Self::NoneInvalid => None,
357 Self::Primitive(prim) => prim.size(),
358 Self::BitField(size_bits, off_typ) => Some(
359 (usize::from(*size_bits).next_power_of_two().max(8) / 8).max(
360 off_typ
361 .and_then(|(_, typ)| typ.helper().size(level.bitfield()))
362 .unwrap_or_default(),
363 ),
364 ),
365 Self::Indirection(kind, typ) => match kind {
366 IndirectionKind::Pointer => Some(mem::size_of::<*const ()>()),
367 IndirectionKind::Atomic => typ.helper().size(level.indirection(*kind)),
368 },
369 Self::Array(len, typ) => typ
370 .helper()
371 .size(level.array())
372 .map(|typ_size| *len as usize * typ_size),
373 Self::Container(kind, _, fields) => {
374 level
375 .container_include_fields()
376 .and_then(|level| match kind {
377 ContainerKind::Struct => {
378 fields.iter().map(|field| field.helper().size(level)).sum()
379 }
380 ContainerKind::Union => fields
381 .iter()
382 .map(|field| field.helper().size(level))
383 .max()
384 .flatten(),
385 })
386 }
387 }
388 }
389}
390
391impl Helper<'_> {
392 pub(crate) const fn new(encoding: &Encoding) -> Self {
393 use Encoding::*;
394 match encoding {
395 Char => Self::Primitive(Primitive::Char),
396 Short => Self::Primitive(Primitive::Short),
397 Int => Self::Primitive(Primitive::Int),
398 Long => Self::Primitive(Primitive::Long),
399 LongLong => Self::Primitive(Primitive::LongLong),
400 UChar => Self::Primitive(Primitive::UChar),
401 UShort => Self::Primitive(Primitive::UShort),
402 UInt => Self::Primitive(Primitive::UInt),
403 ULong => Self::Primitive(Primitive::ULong),
404 ULongLong => Self::Primitive(Primitive::ULongLong),
405 Float => Self::Primitive(Primitive::Float),
406 Double => Self::Primitive(Primitive::Double),
407 LongDouble => Self::Primitive(Primitive::LongDouble),
408 FloatComplex => Self::Primitive(Primitive::FloatComplex),
409 DoubleComplex => Self::Primitive(Primitive::DoubleComplex),
410 LongDoubleComplex => Self::Primitive(Primitive::LongDoubleComplex),
411 Bool => Self::Primitive(Primitive::Bool),
412 Void => Self::Primitive(Primitive::Void),
413 String => Self::Primitive(Primitive::String),
414 Object => Self::Primitive(Primitive::Object),
415 Block => Self::Primitive(Primitive::Block),
416 Class => Self::Primitive(Primitive::Class),
417 Sel => Self::Primitive(Primitive::Sel),
418 Unknown => Self::Primitive(Primitive::Unknown),
419 BitField(b, t) => Self::BitField(*b, *t),
420 Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t),
421 Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t),
422 Array(len, item) => Self::Array(*len, item),
423 Struct(name, fields) => {
424 if !verify_name(name) {
425 panic!("Struct name was not a valid identifier");
426 }
427 Self::Container(ContainerKind::Struct, name, fields)
428 }
429 Union(name, members) => {
430 if !verify_name(name) {
431 panic!("Union name was not a valid identifier");
432 }
433 Self::Container(ContainerKind::Union, name, members)
434 }
435 None => Self::NoneInvalid,
436 }
437 }
438}
439
440impl<'a> Helper<'a, EncodingBox> {
441 pub(crate) fn from_box(encoding: &'a EncodingBox) -> Self {
442 use EncodingBox::*;
443 match encoding {
444 Char => Self::Primitive(Primitive::Char),
445 Short => Self::Primitive(Primitive::Short),
446 Int => Self::Primitive(Primitive::Int),
447 Long => Self::Primitive(Primitive::Long),
448 LongLong => Self::Primitive(Primitive::LongLong),
449 UChar => Self::Primitive(Primitive::UChar),
450 UShort => Self::Primitive(Primitive::UShort),
451 UInt => Self::Primitive(Primitive::UInt),
452 ULong => Self::Primitive(Primitive::ULong),
453 ULongLong => Self::Primitive(Primitive::ULongLong),
454 Float => Self::Primitive(Primitive::Float),
455 Double => Self::Primitive(Primitive::Double),
456 LongDouble => Self::Primitive(Primitive::LongDouble),
457 FloatComplex => Self::Primitive(Primitive::FloatComplex),
458 DoubleComplex => Self::Primitive(Primitive::DoubleComplex),
459 LongDoubleComplex => Self::Primitive(Primitive::LongDoubleComplex),
460 Bool => Self::Primitive(Primitive::Bool),
461 Void => Self::Primitive(Primitive::Void),
462 String => Self::Primitive(Primitive::String),
463 Object => Self::Primitive(Primitive::Object),
464 Block => Self::Primitive(Primitive::Block),
465 Class => Self::Primitive(Primitive::Class),
466 Sel => Self::Primitive(Primitive::Sel),
467 Unknown => Self::Primitive(Primitive::Unknown),
468 BitField(b, t) => Self::BitField(*b, t.as_deref()),
469 Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t),
470 Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t),
471 Array(len, item) => Self::Array(*len, item),
472 Struct(name, fields) => {
473 if !verify_name(name) {
474 panic!("Struct name was not a valid identifier");
475 }
476 Self::Container(ContainerKind::Struct, name, fields)
477 }
478 Union(name, members) => {
479 if !verify_name(name) {
480 panic!("Union name was not a valid identifier");
481 }
482 Self::Container(ContainerKind::Union, name, members)
483 }
484 None => Self::NoneInvalid,
485 }
486 }
487}
488
489impl EncodingType for Encoding {
490 fn helper(&self) -> Helper<'_, Self> {
491 Helper::new(self)
492 }
493}
494
495impl EncodingType for EncodingBox {
496 fn helper(&self) -> Helper<'_, Self> {
497 Helper::from_box(self)
498 }
499}