Skip to content

Commit

Permalink
Put methods behind feature flags
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jan 9, 2023
1 parent 59c6f44 commit 4e367b7
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 11 deletions.
4 changes: 3 additions & 1 deletion crates/header-translator/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl<'a> Cache<'a> {
if let Stmt::Methods {
ty,
availability,
superclasses: _,
methods,
category_name,
description,
Expand Down Expand Up @@ -136,7 +137,7 @@ impl<'a> Cache<'a> {
.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 @@ -161,6 +162,7 @@ impl<'a> Cache<'a> {
Some(Stmt::Methods {
ty: ty.clone(),
availability: cache.availability.clone(),
superclasses: superclasses.clone(),
methods,
category_name: cache.category_name.clone(),
description: Some(format!(
Expand Down
8 changes: 8 additions & 0 deletions crates/header-translator/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ impl Method {

Some(self)
}

pub fn visit_required_features(&self, mut f: impl FnMut(&str, &str)) {
for (_, _, arg) in &self.arguments {
arg.visit_required_features(&mut f);
}

self.result_type.visit_required_features(&mut f);
}
}

#[derive(Debug)]
Expand Down
63 changes: 63 additions & 0 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,18 @@ impl IdType {
_ => panic!("pointee was neither objcinterface nor objcobject: {ty:?}"),
}
}

fn visit_required_features(&self, f: &mut impl FnMut(&str, &str)) {
if let Some(library) = self.library() {
f(&library, self.name());
}

if let Self::Class { generics, .. } = self {
for generic in generics {
generic.visit_required_features(f);
}
}
}
}

impl fmt::Display for IdType {
Expand Down Expand Up @@ -793,6 +805,48 @@ impl RustType {
_ => {}
}
}

fn visit_required_features(&self, f: &mut impl FnMut(&str, &str)) {
match self {
// Objective-C
Self::Id { ty, .. } => {
// f("objc2");
ty.visit_required_features(f);
}
Self::Class { .. } | Self::Sel { .. } | Self::ObjcBool => {
// f("objc2");
}

// Others
Self::Pointer { pointee, .. } | Self::IncompleteArray { pointee, .. } => {
pointee.visit_required_features(f);
}
Self::Array { element_type, .. } => {
element_type.visit_required_features(f);
}
// TODO
// Enum { name } | Struct { name } | TypeDef { name } => {
//
// }
Self::Fn {
arguments,
result_type,
..
}
| Self::Block {
arguments,
result_type,
} => {
// TODO if block
// f("block2");
for arg in arguments {
arg.visit_required_features(f);
}
result_type.visit_required_features(f);
}
_ => {}
}
}
}

/// This is sound to output in (almost, c_void is not a valid return type) any
Expand Down Expand Up @@ -1193,6 +1247,15 @@ impl Ty {
}
}
}

pub fn visit_required_features(&self, f: &mut impl FnMut(&str, &str)) {
match &self.kind {
TyKind::MethodReturnWithError => f("Foundation", "NSError"),
_ => {}
}

self.ty.visit_required_features(f);
}
}

impl Ty {
Expand Down
93 changes: 83 additions & 10 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::collections::HashSet;
use std::fmt;
use std::iter;
Expand Down Expand Up @@ -36,17 +37,25 @@ impl fmt::Display for Derives {

#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ClassDefReference {
pub library: String,
pub name: String,
pub generics: Vec<String>,
}

impl ClassDefReference {
pub fn new(name: String, generics: Vec<String>) -> Self {
Self { name, generics }
pub fn new(library: String, name: String, generics: Vec<String>) -> Self {
Self {
library,
name,
generics,
}
}
}

fn parse_superclass<'ty>(entity: &Entity<'ty>) -> Option<(Entity<'ty>, ClassDefReference)> {
fn parse_superclass<'ty>(
entity: &Entity<'ty>,
context: &Context<'_>,
) -> Option<(Entity<'ty>, ClassDefReference)> {
let mut superclass = None;
let mut generics = Vec::new();

Expand All @@ -62,11 +71,19 @@ fn parse_superclass<'ty>(entity: &Entity<'ty>) -> Option<(Entity<'ty>, ClassDefR
});

superclass.map(|entity| {
let reference = entity
.get_reference()
.expect("ObjCSuperClassRef to reference entity");
let (library, _) = context
.get_library_and_file_name(&reference)
.expect("superclass library");
(
entity
.get_reference()
.expect("ObjCSuperClassRef to reference entity"),
ClassDefReference::new(entity.get_name().expect("superclass name"), generics),
reference,
ClassDefReference::new(
library,
entity.get_name().expect("superclass name"),
generics,
),
)
})
}
Expand Down Expand Up @@ -210,6 +227,7 @@ pub enum Stmt {
Methods {
ty: ClassDefReference,
availability: Availability,
superclasses: Vec<ClassDefReference>,
methods: Vec<Method>,
/// For the categories that have a name (though some don't, see NSClipView)
category_name: Option<String>,
Expand Down Expand Up @@ -360,19 +378,25 @@ impl Stmt {
let (protocols, methods, designated_initializers) =
parse_objc_decl(entity, true, Some(&mut generics), class_data, context);

let ty = ClassDefReference::new(name, generics);
let (library, _) = context
.get_library_and_file_name(entity)
.expect("category library");
let ty = ClassDefReference::new(library, name, generics);

let mut superclass_entity = *entity;
let mut superclasses = vec![];

while let Some((next_entity, superclass)) = parse_superclass(&superclass_entity) {
while let Some((next_entity, superclass)) =
parse_superclass(&superclass_entity, context)
{
superclass_entity = next_entity;
superclasses.push(superclass);
}

let methods = Self::Methods {
ty: ty.clone(),
availability: availability.clone(),
superclasses: superclasses.clone(),
methods,
category_name: None,
description: None,
Expand Down Expand Up @@ -449,11 +473,25 @@ impl Stmt {
)
}

let ty = ClassDefReference::new(class_name, class_generics);
let (library, _) = context
.get_library_and_file_name(entity)
.expect("category library");
let ty = ClassDefReference::new(library, class_name, class_generics);

let mut superclass_entity = *entity;
let mut superclasses = vec![];

while let Some((next_entity, superclass)) =
parse_superclass(&superclass_entity, context)
{
superclass_entity = next_entity;
superclasses.push(superclass);
}

iter::once(Self::Methods {
ty: ty.clone(),
availability: availability.clone(),
superclasses,
methods,
category_name: name,
description: None,
Expand Down Expand Up @@ -949,6 +987,7 @@ impl fmt::Display for Stmt {
Self::Methods {
ty,
availability: _,
superclasses,
methods,
category_name,
description,
Expand All @@ -963,13 +1002,47 @@ impl fmt::Display for Stmt {
if let Some(category_name) = category_name {
writeln!(f, " /// {category_name}")?;
}
writeln!(f, " #[cfg(feature = \"{}_{}\")]", ty.library, ty.name)?;
writeln!(
f,
" unsafe impl{} {} {{",
GenericParamsHelper(&ty.generics),
GenericTyHelper(ty)
)?;
for method in methods {
// Use a set to deduplicate features, and to have them in a consistent order
let mut features = BTreeSet::new();
method.visit_required_features(|library, item| {
if ty.library == library && ty.name == item {
// The feature is guaranteed enabled if the class itself is enabled
return;
}
for superclass in superclasses {
if superclass.library == library && superclass.name == item {
// Same for superclasses
return;
}
}
features.insert(format!("feature = \"{library}_{item}\""));
});
match features.len() {
0 => {}
1 => {
writeln!(f, " #[cfg({})]", features.first().unwrap())?;
}
_ => {
writeln!(
f,
" #[cfg(all({}))]",
features
.iter()
.map(|s| &**s)
.collect::<Vec<&str>>()
.join(",")
)?;
}
}

writeln!(f, "{method}")?;
}
writeln!(f, " }}")?;
Expand Down

0 comments on commit 4e367b7

Please sign in to comment.