Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Put methods behind feature flags #328

Merged
merged 30 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ea1b545
Put methods behind feature flags
madsmtm Jan 10, 2023
123bf9f
Fix Class { params } type
madsmtm Jan 10, 2023
c2d36c0
Add feature section for icrates Cargo.toml
silvanshade Jan 10, 2023
5f1f99b
Properly emit cargo features
madsmtm Jan 10, 2023
f1f5c3a
Handle builtin NSObject differently
madsmtm Jan 10, 2023
365d3ea
Add "_all" cargo features to help with testing / for convenience
madsmtm Jan 10, 2023
a489e25
Refactor identifier handling
madsmtm Jan 10, 2023
39fda4f
Access items in a namespaced fasion instead of directly
madsmtm Jan 10, 2023
0274b5f
Properly rename QuartzCore to CoreAnimation
madsmtm Jan 10, 2023
10203a5
Fix required features
madsmtm Jan 10, 2023
e5c59df
Add base cargo features to "_all" cargo features
madsmtm Jan 10, 2023
d2c5c28
Fix NSError paths
madsmtm Jan 10, 2023
4b45ebd
Fix typedef, enum and struct paths
madsmtm Jan 10, 2023
c7db248
Fix the core graphics types
madsmtm Jan 10, 2023
44612ba
Refactor Expr slightly
madsmtm Jan 10, 2023
a7fba3d
Use wildcard imports again until we've resolved some more details
madsmtm Jan 10, 2023
127ebca
Fix the manual code we've written to match the new feature flags
madsmtm Jan 10, 2023
6bc5c92
Fix more feature flags and refactor tests
madsmtm Jan 11, 2023
9bf999c
cfg-gate functions
madsmtm Jan 11, 2023
b2a38fb
cfg-gate class declarations
madsmtm Jan 11, 2023
60d902e
cfg-gate protocol methods
madsmtm Jan 11, 2023
6f131aa
Fix remaining Foundation compilation errors
madsmtm Jan 11, 2023
2d0e590
Create potentially missing directories in header-translator
madsmtm Jan 11, 2023
8717fad
Fix compilation errors in tests and examples
madsmtm Jan 11, 2023
a560f5e
Fix remaining icrate compilation errors
madsmtm Jan 11, 2023
bea5c51
Appease clippy
madsmtm Jan 11, 2023
fd61fe6
Add CI step for checking each icrate feature separately
madsmtm Jan 11, 2023
41399c7
Improve check_icrate_features script
madsmtm Jan 11, 2023
4df93f0
Fix a few more mistakes regarding feature checks
madsmtm Jan 11, 2023
933b09c
Fix Apple CI step
madsmtm Jan 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 38 additions & 34 deletions crates/header-translator/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ use std::mem;
use crate::availability::Availability;
use crate::config::{ClassData, Config};
use crate::file::File;
use crate::id::ItemIdentifier;
use crate::method::Method;
use crate::output::Output;
use crate::rust_type::Ownership;
use crate::stmt::{ClassDefReference, Stmt};
use crate::stmt::Stmt;

#[derive(Debug, PartialEq, Clone)]
struct MethodCache {
availability: Availability,
methods: Vec<Method>,
category_name: Option<String>,
category: ItemIdentifier<Option<String>>,
}

#[derive(Debug, PartialEq, Clone, Default)]
Expand All @@ -35,7 +36,7 @@ impl ClassCache {
/// A helper struct for doing global analysis on the output.
#[derive(Debug, PartialEq, Clone)]
pub struct Cache<'a> {
classes: BTreeMap<ClassDefReference, ClassCache>,
classes: BTreeMap<ItemIdentifier, ClassCache>,
ownership_map: BTreeMap<String, Ownership>,
config: &'a Config,
}
Expand All @@ -50,13 +51,13 @@ impl<'a> Cache<'a> {
for (name, file) in &library.files {
let _span = debug_span!("file", name).entered();
for stmt in &file.stmts {
if let Some((ty, method_cache)) = Self::cache_stmt(stmt) {
let cache = classes.entry(ty.clone()).or_default();
if let Some((cls, method_cache)) = Self::cache_stmt(stmt) {
let cache = classes.entry(cls.clone()).or_default();
cache.to_emit.push(method_cache);
}
if let Stmt::ClassDecl { ty, ownership, .. } = stmt {
if let Stmt::ClassDecl { id, ownership, .. } = stmt {
if *ownership != Ownership::default() {
ownership_map.insert(ty.name.clone(), ownership.clone());
ownership_map.insert(id.name.clone(), ownership.clone());
}
}
}
Expand All @@ -70,16 +71,18 @@ impl<'a> Cache<'a> {
}
}

fn cache_stmt(stmt: &Stmt) -> Option<(&ClassDefReference, MethodCache)> {
fn cache_stmt(stmt: &Stmt) -> Option<(&ItemIdentifier, MethodCache)> {
if let Stmt::Methods {
ty,
cls,
generics: _,
category,
availability,
superclasses: _,
methods,
category_name,
description,
} = stmt
{
let _span = debug_span!("Stmt::Methods", ?ty).entered();
let _span = debug_span!("Stmt::Methods", ?cls).entered();
let methods: Vec<Method> = methods
.iter()
.filter(|method| method.emit_on_subclasses())
Expand All @@ -91,12 +94,13 @@ impl<'a> Cache<'a> {
if description.is_some() {
warn!(description, "description was set");
}
let category = category.clone().with_new_path(&cls);
Some((
ty,
cls,
MethodCache {
availability: availability.clone(),
methods,
category_name: category_name.clone(),
category,
},
))
} else {
Expand All @@ -119,22 +123,25 @@ impl<'a> Cache<'a> {
for stmt in &mut file.stmts {
match stmt {
Stmt::ClassDecl {
ty, superclasses, ..
id,
generics,
superclasses,
..
} => {
let _span = debug_span!("Stmt::ClassDecl", ?ty).entered();
let data = self.config.class_data.get(&ty.name);
let _span = debug_span!("Stmt::ClassDecl", ?id).entered();
let data = self.config.class_data.get(&id.name);

// Used for duplicate checking (sometimes the subclass
// defines the same method that the superclass did).
let mut seen_methods: Vec<_> = self
.classes
.get(ty)
.get(id)
.map(|cache| cache.all_methods_data())
.into_iter()
.flatten()
.collect();

for superclass in superclasses {
for (superclass, _) in &*superclasses {
if let Some(cache) = self.classes.get(superclass) {
new_stmts.extend(cache.to_emit.iter().filter_map(|cache| {
let mut methods: Vec<_> = cache
Expand All @@ -154,13 +161,15 @@ impl<'a> Cache<'a> {
return None;
}

self.update_methods(&mut methods, &ty.name);
self.update_methods(&mut methods, &id.name);

Some(Stmt::Methods {
ty: ty.clone(),
cls: id.clone(),
generics: generics.clone(),
category: cache.category.clone(),
availability: cache.availability.clone(),
superclasses: superclasses.clone(),
methods,
category_name: cache.category_name.clone(),
description: Some(format!(
"Methods declared on superclass `{}`",
superclass.name
Expand All @@ -172,11 +181,11 @@ impl<'a> Cache<'a> {
}
}
}
Stmt::Methods { ty, methods, .. } => {
self.update_methods(methods, &ty.name);
Stmt::Methods { cls, methods, .. } => {
self.update_methods(methods, &cls.name);
}
Stmt::ProtocolDecl { name, methods, .. } => {
self.update_methods(methods, name);
Stmt::ProtocolDecl { id, methods, .. } => {
self.update_methods(methods, &id.name);
}
_ => {}
}
Expand All @@ -186,20 +195,15 @@ impl<'a> Cache<'a> {
// Fix up a few typedef + enum declarations
let mut iter = mem::take(&mut file.stmts).into_iter().peekable();
while let Some(stmt) = iter.next() {
if let Stmt::AliasDecl {
name,
ty,
kind: None,
} = &stmt
{
if let Stmt::AliasDecl { id, ty, kind: None } = &stmt {
if let Some(Stmt::EnumDecl {
name: enum_name,
id: enum_id,
ty: enum_ty,
..
}) = iter.peek_mut()
{
if enum_ty.is_typedef_to(name) {
*enum_name = Some(name.clone());
if enum_ty.is_typedef_to(&id.name) {
*enum_id = id.clone().to_some();
*enum_ty = ty.clone();
// Skip adding the now-redundant alias to the list of statements
continue;
Expand Down
17 changes: 17 additions & 0 deletions crates/header-translator/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,26 @@ pub struct Config {
pub libraries: HashMap<String, LibraryData>,
}

impl Config {
pub fn get_library_alias(&self, library_name: String) -> String {
self.libraries
.iter()
.find_map(|(n, data)| {
if let Some(name) = &data.name {
if n == &library_name {
return Some(name.clone());
}
}
None
})
.unwrap_or_else(|| library_name)
}
}

#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct LibraryData {
pub name: Option<String>,
pub imports: Vec<String>,
}

Expand Down
27 changes: 19 additions & 8 deletions crates/header-translator/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::ops;
use std::path::{Path, PathBuf};

Expand All @@ -12,7 +12,8 @@ pub struct Context<'a> {
config: &'a Config,
pub macro_invocations: HashMap<Location<'a>, String>,
framework_dir: PathBuf,
nsobject_dir: PathBuf,
include_dir: PathBuf,
system_headers: HashSet<&'static Path>,
}

impl<'a> Context<'a> {
Expand All @@ -21,18 +22,28 @@ impl<'a> Context<'a> {
config,
macro_invocations: Default::default(),
framework_dir: sdk.path.join("System/Library/Frameworks"),
nsobject_dir: sdk.path.join("usr/include/objc/NSObject.h"),
include_dir: sdk.path.join("usr/include"),
system_headers: HashSet::from([
Path::new("MacTypes.h"),
Path::new("objc/NSObject.h"),
Path::new("objc/NSObjCRuntime.h"),
]),
}
}

pub fn get_library_and_file_name(&self, entity: &Entity<'_>) -> Option<(String, String)> {
pub fn get_library_and_file_name(
&self,
entity: &Entity<'_>,
) -> Option<(String, Option<String>)> {
if let Some(location) = entity.get_location() {
if let Some(file) = location.get_file_location().file {
let path = file.get_path();
if let Ok(path) = path.strip_prefix(&self.framework_dir) {
return Some(split_path(path));
} else if path == self.nsobject_dir {
return Some(("Foundation".to_string(), "NSObject".to_string()));
} else if let Ok(path) = path.strip_prefix(&self.include_dir) {
if self.system_headers.contains(path) {
return Some(("System".to_string(), None));
}
}
}
}
Expand All @@ -48,7 +59,7 @@ impl ops::Deref for Context<'_> {
}
}

fn split_path(path: &Path) -> (String, String) {
fn split_path(path: &Path) -> (String, Option<String>) {
let mut components = path.components();
let library_name = components
.next()
Expand All @@ -67,5 +78,5 @@ fn split_path(path: &Path) -> (String, String) {
.to_string_lossy()
.to_string();

(library_name, file_name)
(library_name, Some(file_name))
}
31 changes: 20 additions & 11 deletions crates/header-translator/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ use crate::immediate_children;
use crate::unexposed_macro::UnexposedMacro;

#[derive(Clone, Debug, PartialEq)]
pub struct Expr {
s: String,
pub enum Expr {
NSUIntegerMax,
NSIntegerMax,
Signed(i64),
Unsigned(u64),
String(String),
}

impl Expr {
Expand All @@ -21,16 +25,15 @@ impl Expr {
pw => panic!("unhandled pointer width {pw}"),
};

let s = if unsigned == unsigned_max {
"NSUIntegerMax as _".to_string()
if unsigned == unsigned_max {
Expr::NSUIntegerMax
} else if signed == signed_max {
"NSIntegerMax as _".to_string()
Expr::NSIntegerMax
} else if is_signed {
format!("{signed}")
Expr::Signed(signed)
} else {
format!("{unsigned}")
};
Expr { s }
Expr::Unsigned(unsigned)
}
}

pub fn parse_enum_constant(entity: &Entity<'_>) -> Option<Self> {
Expand Down Expand Up @@ -128,12 +131,18 @@ impl Expr {
s = s.trim_start_matches('(').trim_end_matches(')').to_string();
}

Some(Self { s })
Some(Self::String(s))
}
}

impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.s)
match self {
Self::NSUIntegerMax => write!(f, "NSUIntegerMax as _"),
Self::NSIntegerMax => write!(f, "NSIntegerMax as _"),
Self::Signed(signed) => write!(f, "{signed}"),
Self::Unsigned(unsigned) => write!(f, "{unsigned}"),
Self::String(s) => write!(f, "{s}"),
}
}
}
14 changes: 7 additions & 7 deletions crates/header-translator/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ impl File {
self.stmts
.iter()
.filter_map(|stmt| match stmt {
Stmt::ClassDecl { ty, .. } => Some(&*ty.name),
Stmt::ClassDecl { id, .. } => Some(&*id.name),
Stmt::Methods { .. } => None,
Stmt::ProtocolDecl { name, .. } => Some(name),
Stmt::ProtocolDecl { id, .. } => Some(&*id.name),
Stmt::ProtocolImpl { .. } => None,
Stmt::StructDecl { name, .. } => Some(name),
Stmt::EnumDecl { name, .. } => name.as_deref(),
Stmt::VarDecl { name, .. } => Some(name),
Stmt::FnDecl { name, body, .. } if body.is_none() => Some(name),
Stmt::StructDecl { id, .. } => Some(&*id.name),
Stmt::EnumDecl { id, .. } => id.name.as_deref(),
Stmt::VarDecl { id, .. } => Some(&*id.name),
Stmt::FnDecl { id, body, .. } if body.is_none() => Some(&id.name),
// TODO
Stmt::FnDecl { .. } => None,
Stmt::AliasDecl { name, .. } => Some(name),
Stmt::AliasDecl { id, .. } => Some(&*id.name),
})
.chain(self.stmts.iter().flat_map(|stmt| {
if let Stmt::EnumDecl { variants, .. } = stmt {
Expand Down
Loading