Skip to content

Commit

Permalink
Add support for functions taking NSError as an out parameter
Browse files Browse the repository at this point in the history
Assuming we do #276
  • Loading branch information
madsmtm committed Dec 8, 2022
1 parent 1be4828 commit f05e4cb
Show file tree
Hide file tree
Showing 31 changed files with 381 additions and 485 deletions.
36 changes: 29 additions & 7 deletions crates/header-translator/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,42 +309,64 @@ impl ToTokens for Method {
fn to_tokens(&self, tokens: &mut TokenStream) {
let fn_name = format_ident!("{}", handle_reserved(&self.fn_name));

let arguments: Vec<_> = self
let mut arguments: Vec<_> = self
.arguments
.iter()
.map(|(param, _qualifier, ty)| (format_ident!("{}", handle_reserved(param)), ty))
.collect();

let fn_args = arguments
let is_error =
if self.selector.ends_with("error:") || self.selector.ends_with("AndReturnError:") {
let (_, ty) = arguments.last().expect("arguments last");
ty.is_error_out()
} else {
false
};

if is_error {
arguments.pop();
}

let fn_args: Vec<_> = arguments
.iter()
.map(|(param, arg_ty)| quote!(#param: #arg_ty));
.map(|(param, arg_ty)| quote!(#param: #arg_ty))
.collect();

let method_call = if self.selector.contains(':') {
let split_selector: Vec<_> = self
.selector
.split(':')
.filter(|sel| !sel.is_empty())
.collect();

assert!(
arguments.len() == split_selector.len(),
arguments.len() + (is_error as usize) == split_selector.len(),
"incorrect method argument length",
);

let iter = arguments
.iter()
.into_iter()
.map(|(param, _)| param)
.chain(is_error.then(|| format_ident!("_")))
.zip(split_selector)
.map(|((param, _), sel)| {
.map(|(param, sel)| {
let sel = format_ident!("{}", sel);
quote!(#sel: #param)
});

quote!(#(#iter),*)
} else {
assert_eq!(arguments.len(), 0, "too many arguments");
let sel = format_ident!("{}", self.selector);
quote!(#sel)
};

let ret = &self.result_type;
let ret = if is_error {
self.result_type.as_error()
} else {
let ret = &self.result_type;
quote!(#ret)
};

let macro_name = if self.result_type.is_id() {
format_ident!("msg_send_id")
Expand Down
66 changes: 66 additions & 0 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,53 @@ pub enum RustType {
}

impl RustType {
pub fn is_error_out(&self) -> bool {
if let Self::Pointer {
nullability,
is_const,
pointee,
} = self
{
assert_eq!(
*nullability,
Nullability::Nullable,
"invalid error nullability {self:?}"
);
assert!(!is_const, "expected error not const {self:?}");
if let Self::Id {
type_,
is_const,
lifetime,
nullability,
} = &**pointee
{
if type_.name != "NSError" {
return false;
}
assert!(
type_.generics.is_empty(),
"expected error generics to be empty {self:?}"
);
assert_eq!(
*nullability,
Nullability::Nullable,
"invalid inner error nullability {self:?}"
);
assert!(!is_const, "expected inner error not const {self:?}");
assert_eq!(
*lifetime,
Lifetime::Unspecified,
"invalid error lifetime {self:?}"
);
true
} else {
panic!("invalid error parameter {self:?}")
}
} else {
false
}
}

fn parse(ty: Type<'_>, is_consumed: bool, mut nullability: Nullability) -> Self {
use TypeKind::*;

Expand Down Expand Up @@ -650,6 +697,25 @@ impl RustTypeReturn {
pub fn parse(ty: Type<'_>) -> Self {
Self::new(RustType::parse(ty, false, Nullability::Unspecified))
}

pub fn as_error(&self) -> TokenStream {
match &self.inner {
RustType::Id {
type_,
lifetime: Lifetime::Unspecified,
is_const: false,
nullability: Nullability::Nullable,
} => {
// NULL -> error
quote!(-> Result<Id<#type_, Shared>, Id<NSError, Shared>>)
}
RustType::ObjcBool => {
// NO -> error
quote!(-> Result<(), Id<NSError, Shared>>)
}
_ => panic!("unknown error result type {self:?}"),
}
}
}

impl ToTokens for RustTypeReturn {
Expand Down
6 changes: 6 additions & 0 deletions crates/icrate/src/Foundation.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,9 @@ getInputStream_outputStream = { skipped = true }
[class.NSPropertyListSerialization.methods]
dataFromPropertyList_format_errorDescription = { skipped = true }
propertyListFromData_mutabilityOption_format_errorDescription = { skipped = true }

# Has `error:` parameter, but returns NSInteger (where 0 means error)
[class.NSJSONSerialization.methods.writeJSONObject_toStream_options_error]
skipped = true
[class.NSPropertyListSerialization.methods.writePropertyList_toStream_format_options_error]
skipped = true
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,12 @@ impl NSAppleEventDescriptor {
&self,
sendOptions: NSAppleEventSendOptions,
timeoutInSeconds: NSTimeInterval,
error: *mut *mut NSError,
) -> Option<Id<NSAppleEventDescriptor, Shared>> {
) -> Result<Id<NSAppleEventDescriptor, Shared>, Id<NSError, Shared>> {
msg_send_id![
self,
sendEventWithOptions: sendOptions,
timeout: timeoutInSeconds,
error: error
error: _
]
}
pub unsafe fn isRecordDescriptor(&self) -> bool {
Expand Down
14 changes: 6 additions & 8 deletions crates/icrate/src/generated/Foundation/NSArray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ impl<ObjectType: Message> NSArray<ObjectType> {
pub unsafe fn subarrayWithRange(&self, range: NSRange) -> Id<NSArray<ObjectType>, Shared> {
msg_send_id![self, subarrayWithRange: range]
}
pub unsafe fn writeToURL_error(&self, url: &NSURL, error: *mut *mut NSError) -> bool {
msg_send![self, writeToURL: url, error: error]
pub unsafe fn writeToURL_error(&self, url: &NSURL) -> Result<(), Id<NSError, Shared>> {
msg_send![self, writeToURL: url, error: _]
}
pub unsafe fn makeObjectsPerformSelector(&self, aSelector: Sel) {
msg_send![self, makeObjectsPerformSelector: aSelector]
Expand Down Expand Up @@ -303,15 +303,13 @@ impl<ObjectType: Message> NSArray<ObjectType> {
pub unsafe fn initWithContentsOfURL_error(
&self,
url: &NSURL,
error: *mut *mut NSError,
) -> Option<Id<NSArray<ObjectType>, Shared>> {
msg_send_id![self, initWithContentsOfURL: url, error: error]
) -> Result<Id<NSArray<ObjectType>, Shared>, Id<NSError, Shared>> {
msg_send_id![self, initWithContentsOfURL: url, error: _]
}
pub unsafe fn arrayWithContentsOfURL_error(
url: &NSURL,
error: *mut *mut NSError,
) -> Option<Id<NSArray<ObjectType>, Shared>> {
msg_send_id![Self::class(), arrayWithContentsOfURL: url, error: error]
) -> Result<Id<NSArray<ObjectType>, Shared>, Id<NSError, Shared>> {
msg_send_id![Self::class(), arrayWithContentsOfURL: url, error: _]
}
}
#[doc = "NSArrayDiffing"]
Expand Down
15 changes: 6 additions & 9 deletions crates/icrate/src/generated/Foundation/NSAttributedString.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,44 +249,41 @@ impl NSAttributedString {
markdownFile: &NSURL,
options: Option<&NSAttributedStringMarkdownParsingOptions>,
baseURL: Option<&NSURL>,
error: *mut *mut NSError,
) -> Option<Id<Self, Shared>> {
) -> Result<Id<Self, Shared>, Id<NSError, Shared>> {
msg_send_id![
self,
initWithContentsOfMarkdownFileAtURL: markdownFile,
options: options,
baseURL: baseURL,
error: error
error: _
]
}
pub unsafe fn initWithMarkdown_options_baseURL_error(
&self,
markdown: &NSData,
options: Option<&NSAttributedStringMarkdownParsingOptions>,
baseURL: Option<&NSURL>,
error: *mut *mut NSError,
) -> Option<Id<Self, Shared>> {
) -> Result<Id<Self, Shared>, Id<NSError, Shared>> {
msg_send_id![
self,
initWithMarkdown: markdown,
options: options,
baseURL: baseURL,
error: error
error: _
]
}
pub unsafe fn initWithMarkdownString_options_baseURL_error(
&self,
markdownString: &NSString,
options: Option<&NSAttributedStringMarkdownParsingOptions>,
baseURL: Option<&NSURL>,
error: *mut *mut NSError,
) -> Option<Id<Self, Shared>> {
) -> Result<Id<Self, Shared>, Id<NSError, Shared>> {
msg_send_id![
self,
initWithMarkdownString: markdownString,
options: options,
baseURL: baseURL,
error: error
error: _
]
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/icrate/src/generated/Foundation/NSBundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ impl NSBundle {
pub unsafe fn unload(&self) -> bool {
msg_send![self, unload]
}
pub unsafe fn preflightAndReturnError(&self, error: *mut *mut NSError) -> bool {
msg_send![self, preflightAndReturnError: error]
pub unsafe fn preflightAndReturnError(&self) -> Result<(), Id<NSError, Shared>> {
msg_send![self, preflightAndReturnError: _]
}
pub unsafe fn loadAndReturnError(&self, error: *mut *mut NSError) -> bool {
msg_send![self, loadAndReturnError: error]
pub unsafe fn loadAndReturnError(&self) -> Result<(), Id<NSError, Shared>> {
msg_send![self, loadAndReturnError: _]
}
pub unsafe fn bundleURL(&self) -> Id<NSURL, Shared> {
msg_send_id![self, bundleURL]
Expand Down
20 changes: 8 additions & 12 deletions crates/icrate/src/generated/Foundation/NSCoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ impl NSCoder {
}
pub unsafe fn decodeTopLevelObjectAndReturnError(
&self,
error: *mut *mut NSError,
) -> Option<Id<Object, Shared>> {
msg_send_id![self, decodeTopLevelObjectAndReturnError: error]
) -> Result<Id<Object, Shared>, Id<NSError, Shared>> {
msg_send_id![self, decodeTopLevelObjectAndReturnError: _]
}
pub unsafe fn decodeArrayOfObjCType_count_at(
&self,
Expand Down Expand Up @@ -150,9 +149,8 @@ impl NSCoder {
pub unsafe fn decodeTopLevelObjectForKey_error(
&self,
key: &NSString,
error: *mut *mut NSError,
) -> Option<Id<Object, Shared>> {
msg_send_id![self, decodeTopLevelObjectForKey: key, error: error]
) -> Result<Id<Object, Shared>, Id<NSError, Shared>> {
msg_send_id![self, decodeTopLevelObjectForKey: key, error: _]
}
pub unsafe fn decodeBoolForKey(&self, key: &NSString) -> bool {
msg_send![self, decodeBoolForKey: key]
Expand Down Expand Up @@ -199,13 +197,12 @@ impl NSCoder {
&self,
aClass: &Class,
key: &NSString,
error: *mut *mut NSError,
) -> Option<Id<Object, Shared>> {
) -> Result<Id<Object, Shared>, Id<NSError, Shared>> {
msg_send_id![
self,
decodeTopLevelObjectOfClass: aClass,
forKey: key,
error: error
error: _
]
}
pub unsafe fn decodeArrayOfObjectsOfClass_forKey(
Expand Down Expand Up @@ -239,13 +236,12 @@ impl NSCoder {
&self,
classes: Option<&NSSet<TodoClass>>,
key: &NSString,
error: *mut *mut NSError,
) -> Option<Id<Object, Shared>> {
) -> Result<Id<Object, Shared>, Id<NSError, Shared>> {
msg_send_id![
self,
decodeTopLevelObjectOfClasses: classes,
forKey: key,
error: error
error: _
]
}
pub unsafe fn decodeArrayOfObjectsOfClasses_forKey(
Expand Down
Loading

0 comments on commit f05e4cb

Please sign in to comment.