From 2d47b81e678f681bb1a794d2f508b3935e0db09b Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Sat, 3 Jun 2023 09:14:11 +0300 Subject: [PATCH] Parse and ignore extended encoding type information See more details in https://bou.io/ExtendedTypeInfoInObjC.html --- crates/objc2-encode/src/encoding.rs | 12 ++++++++++++ crates/objc2-encode/src/parse.rs | 20 ++++++++++++++++++-- crates/objc2/src/runtime/mod.rs | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/crates/objc2-encode/src/encoding.rs b/crates/objc2-encode/src/encoding.rs index 23dd312ca..2f075292d 100644 --- a/crates/objc2-encode/src/encoding.rs +++ b/crates/objc2-encode/src/encoding.rs @@ -84,6 +84,14 @@ pub enum Encoding { /// A C `char *`. Corresponds to the `"*"` code. String, /// An Objective-C object (`id`). Corresponds to the `"@"` code. + /// + /// Some compilers may choose to store the name of the class in instance + /// variables and properties as `"@" class_name`, see [Extended Type Info + /// in Objective-C][ext] (note that this does not include generics). + /// + /// Such class names are currently ignored by `objc2-encode`. + /// + /// [ext]: https://bou.io/ExtendedTypeInfoInObjC.html Object, /// An Objective-C block. Corresponds to the `"@" "?"` code. Block, @@ -378,6 +386,10 @@ mod tests { Encoding::Object; !Encoding::Block; "@"; + ~"@\"AnyClassName\""; + ~"@\"\""; // Empty class name + !"@\"MyClassName"; + !"@MyClassName\""; !"@?"; } diff --git a/crates/objc2-encode/src/parse.rs b/crates/objc2-encode/src/parse.rs index cb4788756..30b29bc0d 100644 --- a/crates/objc2-encode/src/parse.rs +++ b/crates/objc2-encode/src/parse.rs @@ -5,7 +5,7 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::fmt; -use crate::helper::{ContainerKind, EncodingType, Helper, NestingLevel}; +use crate::helper::{ContainerKind, EncodingType, Helper, NestingLevel, Primitive}; use crate::{Encoding, EncodingBox}; /// Check whether a struct or union name is a valid identifier @@ -251,7 +251,16 @@ impl Parser<'_> { pub(crate) fn expect_encoding(&mut self, enc: &Encoding, level: NestingLevel) -> Option<()> { match enc.helper() { - Helper::Primitive(primitive) => self.expect_str(primitive.to_str()), + Helper::Primitive(primitive) => { + self.expect_str(primitive.to_str())?; + + if primitive == Primitive::Object && self.try_peek() == Some(b'"') { + self.advance(); + self.consume_while(|b| b != b'"'); + self.expect_byte(b'"')?; + } + Some(()) + } Helper::BitField(size, Some((offset, t))) => { self.expect_byte(b'b')?; self.expect_u64(*offset)?; @@ -388,6 +397,13 @@ impl Parser<'_> { self.advance(); EncodingBox::Block } + // Parse class name if present + Some(b'"') => { + self.advance(); + self.consume_while(|b| b != b'"'); + self.expect_byte(b'"').ok_or(ErrorKind::UnexpectedEnd)?; + EncodingBox::Object + } _ => EncodingBox::Object, }, b'#' => EncodingBox::Class, diff --git a/crates/objc2/src/runtime/mod.rs b/crates/objc2/src/runtime/mod.rs index d54ccaa2a..5305be82a 100644 --- a/crates/objc2/src/runtime/mod.rs +++ b/crates/objc2/src/runtime/mod.rs @@ -917,6 +917,7 @@ impl AnyClass { Bool::from_raw(res).as_bool() } + // // fn property(&self, name: &str) -> Option<&Property>; // fn properties(&self) -> Malloc<[&Property]>; // unsafe fn replace_method(&self, name: Sel, imp: Imp, types: &str) -> Imp;