Skip to content

Commit

Permalink
Add the ARKit framework
Browse files Browse the repository at this point in the history
Also implement the plumbing required to automatically avoid emitting
things that require simd types.
  • Loading branch information
madsmtm committed Jan 13, 2025
1 parent f0a67ce commit 2b087bc
Show file tree
Hide file tree
Showing 23 changed files with 576 additions and 185 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/header-translator/src/documentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl Documentation {
children: parsed.get_children(),
}
} else {
error!(?entity, comment, "had comment, but not parsed comment");
warn!(?entity, comment, "had comment, but not parsed comment");
Self {
children: Vec::new(),
}
Expand Down
11 changes: 11 additions & 0 deletions crates/header-translator/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ impl Location {
// c_float and c_double
"_float" | "_Builtin_float" => "__core__.ffi".into(),

// Unstable in FFI.
name if name.starts_with("simd") => "__core__.simd".into(),

// `libc`
name if name.starts_with("sys_types") => "__libc__".into(),
"DarwinFoundation.types.sys_types" => "__libc__".into(),
Expand Down Expand Up @@ -426,6 +429,13 @@ impl ItemIdentifier {
}
}

pub fn core_simd_simd() -> Self {
Self {
name: "Simd".into(),
location: Location::new("__core__.simd"),
}
}

pub fn unsafecell() -> Self {
Self {
name: "UnsafeCell".into(),
Expand Down Expand Up @@ -470,6 +480,7 @@ impl ItemIdentifier {
"__core__.ffi" => Some("core::ffi::*".into()),
// HACKs
"__core__.ptr" if self.name == "NonNull" => Some("core::ptr::NonNull".into()),
"__core__.simd" if self.name == "Simd" => Some("core::simd::*".into()),
"__core__.cell" if self.name == "UnsafeCell" => {
Some("core::cell::UnsafeCell".into())
}
Expand Down
10 changes: 10 additions & 0 deletions crates/header-translator/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ impl Method {
let default_nonnull = (selector == "init" && !is_class) || (selector == "new" && is_class);
let mut result_type = Ty::parse_method_return(result_type, default_nonnull, context);

if result_type.needs_simd() || arguments.iter().any(|(_, arg_ty)| arg_ty.needs_simd()) {
debug!("simd types are not yet possible in methods");
return None;
}

let memory_management = MemoryManagement::new(is_class, &selector, &result_type, modifiers);

// Related result types.
Expand Down Expand Up @@ -578,6 +583,11 @@ impl Method {
context,
);

if ty.needs_simd() {
debug!("simd types are not yet possible in properties");
return (None, None);
}

let memory_management = MemoryManagement::new(is_class, &getter_sel, &ty, modifiers);

let mainthreadonly = mainthreadonly_override(
Expand Down
102 changes: 101 additions & 1 deletion crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,14 @@ pub enum Primitive {
ULongLong,
Float,
Double,
/// Not yet supported by `rustc`
/// https://github.com/rust-lang/rust/issues/116909
F16,
F32,
F64,
/// Not yet supported by `rustc`
/// https://github.com/rust-lang/rust/issues/116909
F128,
I8,
U8,
I16,
Expand Down Expand Up @@ -297,8 +303,10 @@ impl Primitive {
Self::ULongLong => "c_ulonglong",
Self::Float => "c_float",
Self::Double => "c_double",
Self::F16 => "f16",
Self::F32 => "f32",
Self::F64 => "f64",
Self::F128 => "f128",
Self::I8 => "i8",
Self::U8 => "u8",
Self::I16 => "i16",
Expand Down Expand Up @@ -327,7 +335,7 @@ impl Primitive {
Self::Char => return None, // Target-specific
Self::SChar | Self::Short | Self::Int | Self::Long | Self::LongLong => true,
Self::UChar | Self::UShort | Self::UInt | Self::ULong | Self::ULongLong => false,
Self::Float | Self::Double | Self::F32 | Self::F64 => true, // Unsure
Self::Float | Self::Double | Self::F16 | Self::F32 | Self::F64 | Self::F128 => true, // Unsure
Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::ISize => true,
Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::USize => false,
Self::PtrDiff => true,
Expand Down Expand Up @@ -420,6 +428,11 @@ impl ItemRef {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Ty {
Primitive(Primitive),
/// Only handle vectors specially, matrixes are "just" structs on top.
Simd {
ty: Primitive,
size: u8,
},
Class {
decl: ItemRef,
generics: Vec<Self>,
Expand Down Expand Up @@ -1068,6 +1081,58 @@ impl Ty {
"Float80" => panic!("can't handle 80 bit MacOS float"),
"Float96" => panic!("can't handle 96 bit 68881 float"),

simd if simd.starts_with("simd_")
| simd.starts_with("vector_")
| simd.starts_with("matrix_") =>
{
let rest = simd
.strip_prefix("simd_")
.or_else(|| simd.strip_prefix("vector_"))
.or_else(|| simd.strip_prefix("matrix_"))
.unwrap();

if let Some(idx) = rest.find(|c: char| c.is_numeric()) {
let (ty_name, rest) = rest.split_at(idx);
// SIMD types are explicitly documented with their
// width in bytes (so it's safe for us to).
let ty = match ty_name {
"char" => Primitive::I8,
"uchar" => Primitive::U8,
"short" => Primitive::I16,
"ushort" => Primitive::U16,
"half" => Primitive::F16,
"int" => Primitive::I32,
"uint" => Primitive::U32,
"float" => Primitive::F32,
// long on 64-bit, long long otherwise
"long" => Primitive::ISize,
"ulong" => Primitive::USize,
"double" => Primitive::F64,
_ => {
error!(typedef_name, ty_name, "unknown simd type");
Primitive::Void
}
};
if !rest.contains('x') {
match rest.parse::<u8>() {
Ok(size) => {
return Self::Simd { ty, size };
}
Err(err) => {
error!(typedef_name, ?err, "could not parse simd size");
}
}
} else {
// Ignore if contains `x`, this is a simd
// matrix (which is just a struct).
}
} else if matches!(rest, "quath" | "quatf" | "quatd") {
// Ignore, a typedef to a normal struct.
} else {
error!(typedef_name, "could not parse simd type");
}
}

// Workaround for this otherwise requiring libc.
"dispatch_qos_class_t" => {
return Self::TypeDef {
Expand Down Expand Up @@ -1197,6 +1262,11 @@ impl Ty {
pub(crate) fn required_items(&self) -> Vec<ItemIdentifier> {
match self {
Self::Primitive(prim) => prim.required_items(),
Self::Simd { ty, .. } => {
let mut items = ty.required_items();
items.push(ItemIdentifier::core_simd_simd());
items
}
Self::Class {
decl,
generics,
Expand Down Expand Up @@ -1308,6 +1378,7 @@ impl Ty {
pub(crate) fn requires_mainthreadmarker(&self, self_requires: bool) -> bool {
match self {
Self::Primitive(_) => false,
Self::Simd { .. } => false,
Self::Class {
decl,
generics,
Expand Down Expand Up @@ -1524,6 +1595,7 @@ impl Ty {
FormatterFn(move |f| {
match self {
Self::Primitive(prim) => write!(f, "{prim}"),
Self::Simd { ty, size } => write!(f, "Simd<{ty}, {size}>"),
Self::Sel { nullability } => {
if *nullability == Nullability::NonNull {
write!(f, "Sel")
Expand Down Expand Up @@ -2357,6 +2429,7 @@ impl Ty {
pub fn is_signed(&self) -> Option<bool> {
match self {
Self::Primitive(prim) => prim.is_signed(),
Self::Simd { ty, .. } => ty.is_signed(),
Self::Enum { ty, .. } => ty.is_signed(),
Self::TypeDef { to, .. } => to.is_signed(),
_ => None,
Expand Down Expand Up @@ -2465,6 +2538,33 @@ impl Ty {
}
}

/// SIMD is not yet possible in FFI, see:
/// https://github.com/rust-lang/rust/issues/63068
pub(crate) fn needs_simd(&self) -> bool {
match self {
Self::Simd { .. } => true,
Self::Pointer { pointee, .. } | Self::IncompleteArray { pointee, .. } => {
pointee.needs_simd()
}
Self::TypeDef { to, .. } => to.needs_simd(),
Self::Array { element_type, .. } => element_type.needs_simd(),
Self::Struct { fields, .. } | Self::Union { fields, .. } => {
fields.iter().any(|field| field.needs_simd())
}
Self::Fn {
result_type,
arguments,
..
}
| Self::Block {
result_type,
arguments,
..
} => result_type.needs_simd() || arguments.iter().any(|arg| arg.needs_simd()),
_ => false,
}
}

pub(crate) fn try_fix_related_result_type(&mut self) {
if let Self::Pointer { pointee, .. } = self {
if let Self::AnyObject { protocols } = &**pointee {
Expand Down
22 changes: 22 additions & 0 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,11 @@ impl Stmt {
.expect("typedef underlying type");
let ty = Ty::parse_typedef(ty, context);

if ty.needs_simd() {
debug!("simd types are not yet possible in typedefs");
return vec![];
}

// No need to output a typedef if it'll just point to the same thing.
//
// TODO: We're discarding a slight bit of availability data this way.
Expand Down Expand Up @@ -1326,6 +1331,11 @@ impl Stmt {
_ => error!(?entity, "unknown struct/union child"),
});

if fields.iter().any(|(_, _, field_ty)| field_ty.needs_simd()) {
debug!("simd types are not yet possible in struct/union");
return res;
}

res.push(Self::RecordDecl {
id,
encoding_name,
Expand Down Expand Up @@ -1516,6 +1526,11 @@ impl Stmt {
let ty = Ty::parse_static(ty, context);
let mut value = None;

if ty.needs_simd() {
debug!("simd types are not yet possible in statics");
return vec![];
}

immediate_children(entity, |entity, _span| match entity.get_kind() {
EntityKind::UnexposedAttr => {
if let Some(attr) = UnexposedAttr::parse(&entity, context) {
Expand Down Expand Up @@ -1648,6 +1663,13 @@ impl Stmt {
_ => error!("unknown"),
});

if result_type.needs_simd()
|| arguments.iter().any(|(_, arg_ty)| arg_ty.needs_simd())
{
debug!("simd types are not yet possible in functions");
return vec![];
}

if let Some((_, first_ty)) = arguments.first_mut() {
first_ty.fix_fn_first_argument_cf_nullability(&id.name);
}
Expand Down
1 change: 1 addition & 0 deletions crates/objc2/src/topics/about_generated/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Added `MTLResourceID::from_raw` and `MTLResourceID::as_raw` to allow
querying the underlying data.
* Added new framework crates:
- `ARKit` / `objc2-ar-kit`.
- `AudioToolbox` / `objc2-audio-toolbox`.
- `AVFAudio` / `objc2-avf-audio`.
- `AVFoundation` / `objc2-av-foundation`.
Expand Down
1 change: 1 addition & 0 deletions crates/objc2/src/topics/about_generated/list_data.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
| Framework | Crate | Documentation |
| --- | --- | --- |
| `ARKit` | [![`objc2-ar-kit`](https://badgen.net/crates/v/objc2-ar-kit)](https://crates.io/crates/objc2-ar-kit) | [![docs.rs](https://docs.rs/objc2-ar-kit/badge.svg)](https://docs.rs/objc2-ar-kit/) |
| `AVFAudio` | [![`objc2-avf-audio`](https://badgen.net/crates/v/objc2-avf-audio)](https://crates.io/crates/objc2-avf-audio) | [![docs.rs](https://docs.rs/objc2-avf-audio/badge.svg)](https://docs.rs/objc2-avf-audio/) |
| `AVFoundation` | [![`objc2-av-foundation`](https://badgen.net/crates/v/objc2-av-foundation)](https://crates.io/crates/objc2-av-foundation) | [![docs.rs](https://docs.rs/objc2-av-foundation/badge.svg)](https://docs.rs/objc2-av-foundation/) |
| `AVKit` | [![`objc2-av-kit`](https://badgen.net/crates/v/objc2-av-kit)](https://crates.io/crates/objc2-av-kit) | [![docs.rs](https://docs.rs/objc2-av-kit/badge.svg)](https://docs.rs/objc2-av-kit/) |
Expand Down
11 changes: 7 additions & 4 deletions crates/test-frameworks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ release = false

[features]
test-frameworks = [
"dep:objc2-ar-kit",
"objc2-ar-kit/all",
"dep:objc2-avf-audio",
"objc2-avf-audio/all",
"dep:objc2-av-foundation",
Expand Down Expand Up @@ -265,6 +267,11 @@ objc2-symbols = { path = "../../framework-crates/objc2-symbols", optional = true
objc2-uniform-type-identifiers = { path = "../../framework-crates/objc2-uniform-type-identifiers", optional = true }
objc2-user-notifications = { path = "../../framework-crates/objc2-user-notifications", optional = true }

[target.'cfg(any(target_os = "ios", target_os = "visionos"))'.dependencies]
objc2-ar-kit = { path = "../../framework-crates/objc2-ar-kit", optional = true }
objc2-event-kit-ui = { path = "../../framework-crates/objc2-event-kit-ui", optional = true }
objc2-message-ui = { path = "../../framework-crates/objc2-message-ui", optional = true }

[target.'cfg(not(any(target_os = "tvos", target_os = "watchos")))'.dependencies]
objc2-av-routing = { path = "../../framework-crates/objc2-av-routing", optional = true }
objc2-ad-services = { path = "../../framework-crates/objc2-ad-services", optional = true }
Expand Down Expand Up @@ -338,10 +345,6 @@ objc2-event-kit = { path = "../../framework-crates/objc2-event-kit", optional =
objc2-health-kit = { path = "../../framework-crates/objc2-health-kit", optional = true }
objc2-local-authentication = { path = "../../framework-crates/objc2-local-authentication", optional = true }

[target.'cfg(any(target_os = "ios", target_os = "visionos"))'.dependencies]
objc2-event-kit-ui = { path = "../../framework-crates/objc2-event-kit-ui", optional = true }
objc2-message-ui = { path = "../../framework-crates/objc2-message-ui", optional = true }

[target.'cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))'.dependencies]
objc2-home-kit = { path = "../../framework-crates/objc2-home-kit", optional = true }
objc2-ui-kit = { path = "../../framework-crates/objc2-ui-kit", optional = true }
Expand Down
Loading

0 comments on commit 2b087bc

Please sign in to comment.