Skip to content

Commit d49a190

Browse files
committed
Avoid issues with having two nesting levels when comparing encodings
1 parent 06a5949 commit d49a190

File tree

5 files changed

+127
-137
lines changed

5 files changed

+127
-137
lines changed

crates/objc2-encode/src/encoding.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl Encoding {
206206
/// For example, you should not rely on two equivalent encodings to have
207207
/// the same size or ABI - that is provided on a best-effort basis.
208208
pub fn equivalent_to(&self, other: &Self) -> bool {
209-
compare_encodings(self, NestingLevel::new(), other, NestingLevel::new(), false)
209+
compare_encodings(self, other, NestingLevel::new(), false)
210210
}
211211

212212
/// Check if an encoding is equivalent to the given string representation.
@@ -232,7 +232,7 @@ impl Encoding {
232232
/// See [`Encoding::equivalent_to`] for details about the meaning of
233233
/// "equivalence".
234234
pub fn equivalent_to_box(&self, other: &EncodingBox) -> bool {
235-
compare_encodings(self, NestingLevel::new(), other, NestingLevel::new(), false)
235+
compare_encodings(self, other, NestingLevel::new(), false)
236236
}
237237
}
238238

@@ -244,7 +244,7 @@ impl Encoding {
244244
/// Objective-C compilers.
245245
impl fmt::Display for Encoding {
246246
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247-
write!(f, "{}", Helper::new(self, NestingLevel::new()))
247+
Helper::new(self).fmt(f, NestingLevel::new())
248248
}
249249
}
250250

crates/objc2-encode/src/encoding_box.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,13 @@ impl EncodingBox {
135135
/// Same formatting as [`Encoding`]'s `Display` implementation.
136136
impl fmt::Display for EncodingBox {
137137
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138-
write!(f, "{}", Helper::from_box(self, NestingLevel::new()))
138+
Helper::from_box(self).fmt(f, NestingLevel::new())
139139
}
140140
}
141141

142142
impl PartialEq<Encoding> for EncodingBox {
143143
fn eq(&self, other: &Encoding) -> bool {
144-
compare_encodings(self, NestingLevel::new(), other, NestingLevel::new(), true)
144+
compare_encodings(self, other, NestingLevel::new(), true)
145145
}
146146
}
147147

crates/objc2-encode/src/helper.rs

Lines changed: 92 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -17,116 +17,95 @@ impl NestingLevel {
1717
Self::Top
1818
}
1919

20-
const fn bitfield(self) -> Self {
20+
pub(crate) const fn bitfield(self) -> Self {
2121
// This is a bit irrelevant, since bitfields can only contain integral
2222
// types
2323
self
2424
}
2525

26-
const fn atomic(self) -> Self {
27-
// Move all the way down
28-
Self::Bottom
29-
}
30-
31-
const fn pointer(self) -> Self {
32-
// Move one step down
33-
match self {
34-
Self::Top => Self::Within,
35-
Self::Bottom | Self::Within => Self::Bottom,
26+
pub(crate) const fn indirection(self, kind: IndirectionKind) -> Self {
27+
match kind {
28+
// Move all the way down
29+
IndirectionKind::Atomic => Self::Bottom,
30+
// Move one step down
31+
IndirectionKind::Pointer => match self {
32+
Self::Top => Self::Within,
33+
Self::Bottom | Self::Within => Self::Bottom,
34+
},
3635
}
3736
}
3837

39-
const fn array(self) -> Self {
38+
pub(crate) const fn array(self) -> Self {
4039
// TODO: Is this correct?
4140
self
4241
}
4342

44-
const fn container(self) -> Self {
43+
pub(crate) const fn container_include_fields(self) -> Option<Self> {
4544
match self {
46-
// Move top one step down
47-
Self::Top | Self::Within => Self::Within,
48-
Self::Bottom => Self::Bottom,
49-
}
50-
}
51-
52-
pub(crate) const fn include_container_fields(self) -> bool {
53-
match self {
54-
Self::Top | Self::Within => true,
55-
Self::Bottom => false,
45+
Self::Top | Self::Within => {
46+
// Move top one step down
47+
Some(Self::Within)
48+
}
49+
Self::Bottom => None,
5650
}
5751
}
5852
}
5953

6054
pub(crate) fn compare_encodings<E1: EncodingType, E2: EncodingType>(
6155
enc1: &E1,
62-
level1: NestingLevel,
6356
enc2: &E2,
64-
level2: NestingLevel,
57+
level: NestingLevel,
6558
include_all: bool,
6659
) -> bool {
6760
use Helper::*;
6861
// Note: Ideally `Block` and sequence of `Object, Unknown` in struct
6962
// should compare equivalent, but we don't bother since in practice a
7063
// plain `Unknown` will never appear.
7164

72-
let level1 = if include_all {
73-
NestingLevel::new()
74-
} else {
75-
level1
76-
};
77-
let level2 = if include_all {
65+
let level = if include_all {
7866
NestingLevel::new()
7967
} else {
80-
level2
68+
level
8169
};
8270

83-
// TODO: Are level1 and level2 ever different?
84-
85-
match (enc1.helper(level1), enc2.helper(level2)) {
71+
match (enc1.helper(), enc2.helper()) {
8672
(Primitive(p1), Primitive(p2)) => p1 == p2,
87-
(
88-
BitField(size1, Some((offset1, type1)), level1),
89-
BitField(size2, Some((offset2, type2)), level2),
90-
) => {
73+
(BitField(size1, Some((offset1, type1))), BitField(size2, Some((offset2, type2)))) => {
9174
size1 == size2
9275
&& offset1 == offset2
93-
&& compare_encodings(type1, level1, type2, level2, include_all)
76+
&& compare_encodings(type1, type2, level.bitfield(), include_all)
9477
}
95-
(BitField(size1, None, _level1), BitField(size2, None, _level2)) => size1 == size2,
78+
(BitField(size1, None), BitField(size2, None)) => size1 == size2,
9679
// The type-encoding of a bitfield is always either available, or it
9780
// is not (depends on platform); so if it was available in one, but
9881
// not the other, we should compare the encodings unequal.
99-
(BitField(_, _, _), BitField(_, _, _)) => false,
100-
(Indirection(kind1, t1, level1), Indirection(kind2, t2, level2)) => {
101-
kind1 == kind2 && compare_encodings(t1, level1, t2, level2, include_all)
82+
(BitField(_, _), BitField(_, _)) => false,
83+
(Indirection(kind1, t1), Indirection(kind2, t2)) => {
84+
kind1 == kind2 && compare_encodings(t1, t2, level.indirection(kind1), include_all)
10285
}
103-
(Array(len1, item1, level1), Array(len2, item2, level2)) => {
104-
len1 == len2 && compare_encodings(item1, level1, item2, level2, include_all)
86+
(Array(len1, item1), Array(len2, item2)) => {
87+
len1 == len2 && compare_encodings(item1, item2, level.array(), include_all)
10588
}
106-
(Container(kind1, name1, items1, level1), Container(kind2, name2, items2, level2)) => {
107-
kind1 == kind2
108-
&& name1 == name2
109-
&& match (
110-
items1,
111-
items2,
112-
level1.include_container_fields() && level2.include_container_fields(),
113-
) {
114-
(_, _, false) => true,
115-
// If one container is empty, then they are equivalent
116-
([], _, true) => true,
117-
(_, [], true) => true,
118-
(items1, items2, true) => {
119-
if items1.len() != items2.len() {
89+
(Container(kind1, name1, items1), Container(kind2, name2, items2)) => {
90+
kind1 == kind2 && name1 == name2 && {
91+
if let Some(level) = level.container_include_fields() {
92+
// If either container is empty, then they are equivalent
93+
if items1.is_empty() || items2.is_empty() {
94+
return true;
95+
}
96+
if items1.len() != items2.len() {
97+
return false;
98+
}
99+
for (item1, item2) in items1.iter().zip(items2.iter()) {
100+
if !compare_encodings(item1, item2, level, include_all) {
120101
return false;
121102
}
122-
for (item1, item2) in items1.iter().zip(items2.iter()) {
123-
if !compare_encodings(item1, level1, item2, level2, include_all) {
124-
return false;
125-
}
126-
}
127-
true
128103
}
104+
true
105+
} else {
106+
true
129107
}
108+
}
130109
}
131110
(_, _) => false,
132111
}
@@ -252,52 +231,61 @@ impl fmt::Display for ContainerKind {
252231
}
253232

254233
pub(crate) trait EncodingType: Sized + fmt::Debug {
255-
fn helper(&self, level: NestingLevel) -> Helper<'_, Self>;
234+
fn helper(&self) -> Helper<'_, Self>;
256235
}
257236

258237
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
259238
#[non_exhaustive]
260239
pub(crate) enum Helper<'a, E = Encoding> {
261240
Primitive(Primitive),
262-
BitField(u8, Option<&'a (u64, E)>, NestingLevel),
263-
Indirection(IndirectionKind, &'a E, NestingLevel),
264-
Array(u64, &'a E, NestingLevel),
265-
Container(ContainerKind, &'a str, &'a [E], NestingLevel),
241+
BitField(u8, Option<&'a (u64, E)>),
242+
Indirection(IndirectionKind, &'a E),
243+
Array(u64, &'a E),
244+
Container(ContainerKind, &'a str, &'a [E]),
266245
}
267246

268-
impl<E: EncodingType> fmt::Display for Helper<'_, E> {
269-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247+
impl<E: EncodingType> Helper<'_, E> {
248+
pub(crate) fn fmt(&self, f: &mut fmt::Formatter<'_>, level: NestingLevel) -> fmt::Result {
270249
match self {
271-
Self::Primitive(primitive) => write!(f, "{}", primitive.to_str()),
272-
Self::BitField(size, None, _level) => {
273-
write!(f, "b{size}")
250+
Self::Primitive(primitive) => {
251+
write!(f, "{}", primitive.to_str())?;
252+
}
253+
Self::BitField(size, None) => {
254+
write!(f, "b{size}")?;
274255
}
275-
Self::BitField(size, Some((offset, t)), level) => {
276-
write!(f, "b{offset}{}{size}", t.helper(*level))
256+
Self::BitField(size, Some((offset, t))) => {
257+
write!(f, "b{offset}")?;
258+
t.helper().fmt(f, level.bitfield())?;
259+
write!(f, "{size}")?;
277260
}
278-
Self::Indirection(kind, t, level) => {
279-
write!(f, "{}{}", kind.prefix(), t.helper(*level))
261+
Self::Indirection(kind, t) => {
262+
write!(f, "{}", kind.prefix())?;
263+
t.helper().fmt(f, level.indirection(*kind))?;
280264
}
281-
Self::Array(len, item, level) => {
282-
write!(f, "[{}{}]", len, item.helper(*level))
265+
Self::Array(len, item) => {
266+
write!(f, "[")?;
267+
write!(f, "{len}")?;
268+
item.helper().fmt(f, level.array())?;
269+
write!(f, "]")?;
283270
}
284-
Self::Container(kind, name, items, level) => {
271+
Self::Container(kind, name, items) => {
285272
write!(f, "{}", kind.start())?;
286273
write!(f, "{name}")?;
287-
if level.include_container_fields() {
274+
if let Some(level) = level.container_include_fields() {
288275
write!(f, "=")?;
289276
for item in *items {
290-
write!(f, "{}", item.helper(*level))?;
277+
item.helper().fmt(f, level)?;
291278
}
292279
}
293-
write!(f, "{}", kind.end())
280+
write!(f, "{}", kind.end())?;
294281
}
295282
}
283+
Ok(())
296284
}
297285
}
298286

299287
impl Helper<'_> {
300-
pub(crate) const fn new(encoding: &Encoding, level: NestingLevel) -> Self {
288+
pub(crate) const fn new(encoding: &Encoding) -> Self {
301289
use Encoding::*;
302290
match encoding {
303291
Char => Self::Primitive(Primitive::Char),
@@ -324,28 +312,28 @@ impl Helper<'_> {
324312
Class => Self::Primitive(Primitive::Class),
325313
Sel => Self::Primitive(Primitive::Sel),
326314
Unknown => Self::Primitive(Primitive::Unknown),
327-
BitField(b, t) => Self::BitField(*b, *t, level.bitfield()),
328-
Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t, level.pointer()),
329-
Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t, level.atomic()),
330-
Array(len, item) => Self::Array(*len, item, level.array()),
315+
BitField(b, t) => Self::BitField(*b, *t),
316+
Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t),
317+
Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t),
318+
Array(len, item) => Self::Array(*len, item),
331319
Struct(name, fields) => {
332320
if !verify_name(name) {
333321
panic!("Struct name was not a valid identifier");
334322
}
335-
Self::Container(ContainerKind::Struct, name, fields, level.container())
323+
Self::Container(ContainerKind::Struct, name, fields)
336324
}
337325
Union(name, members) => {
338326
if !verify_name(name) {
339327
panic!("Union name was not a valid identifier");
340328
}
341-
Self::Container(ContainerKind::Union, name, members, level.container())
329+
Self::Container(ContainerKind::Union, name, members)
342330
}
343331
}
344332
}
345333
}
346334

347335
impl<'a> Helper<'a, EncodingBox> {
348-
pub(crate) fn from_box(encoding: &'a EncodingBox, level: NestingLevel) -> Self {
336+
pub(crate) fn from_box(encoding: &'a EncodingBox) -> Self {
349337
use EncodingBox::*;
350338
match encoding {
351339
Char => Self::Primitive(Primitive::Char),
@@ -372,34 +360,34 @@ impl<'a> Helper<'a, EncodingBox> {
372360
Class => Self::Primitive(Primitive::Class),
373361
Sel => Self::Primitive(Primitive::Sel),
374362
Unknown => Self::Primitive(Primitive::Unknown),
375-
BitField(b, t) => Self::BitField(*b, t.as_deref(), level.bitfield()),
376-
Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t, level.pointer()),
377-
Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t, level.atomic()),
378-
Array(len, item) => Self::Array(*len, item, level.array()),
363+
BitField(b, t) => Self::BitField(*b, t.as_deref()),
364+
Pointer(t) => Self::Indirection(IndirectionKind::Pointer, t),
365+
Atomic(t) => Self::Indirection(IndirectionKind::Atomic, t),
366+
Array(len, item) => Self::Array(*len, item),
379367
Struct(name, fields) => {
380368
if !verify_name(name) {
381369
panic!("Struct name was not a valid identifier");
382370
}
383-
Self::Container(ContainerKind::Struct, name, fields, level.container())
371+
Self::Container(ContainerKind::Struct, name, fields)
384372
}
385373
Union(name, members) => {
386374
if !verify_name(name) {
387375
panic!("Union name was not a valid identifier");
388376
}
389-
Self::Container(ContainerKind::Union, name, members, level.container())
377+
Self::Container(ContainerKind::Union, name, members)
390378
}
391379
}
392380
}
393381
}
394382

395383
impl EncodingType for Encoding {
396-
fn helper(&self, level: NestingLevel) -> Helper<'_, Self> {
397-
Helper::new(self, level)
384+
fn helper(&self) -> Helper<'_, Self> {
385+
Helper::new(self)
398386
}
399387
}
400388

401389
impl EncodingType for EncodingBox {
402-
fn helper(&self, level: NestingLevel) -> Helper<'_, Self> {
403-
Helper::from_box(self, level)
390+
fn helper(&self) -> Helper<'_, Self> {
391+
Helper::from_box(self)
404392
}
405393
}

0 commit comments

Comments
 (0)