From b49662737d6eaeba674d219b2dc5e79fa0ff1ad2 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 6 Dec 2014 00:43:29 -0800 Subject: [PATCH 001/125] Added WIP block module. --- src/lib.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/lib.rs diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..f5a8076ca --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,86 @@ +#![allow(dead_code)] + +use std::mem; +use std::ptr; +use libc::{c_int, c_ulong}; + +use runtime::Class; +use {Id, Message}; + +#[allow(improper_ctypes)] +#[link(name = "Foundation", kind = "framework")] +extern { + static _NSConcreteStackBlock: Class; +} + +#[repr(C)] +struct Block { + isa: *const Class, + flags: c_int, + _reserved: c_int, + pub invoke: unsafe extern fn(&mut Block, ...), + descriptor: *const BlockDescriptor, + pub context: C, +} + +impl Block { + pub fn new(invoke: unsafe extern fn(&mut Block, ...), context: C) -> Block { + println!("{}", _NSConcreteStackBlock.name()); + Block { + isa: &_NSConcreteStackBlock, + // 1 << 25 = BLOCK_HAS_COPY_DISPOSE + flags: 1 << 25, + _reserved: 0, + invoke: invoke, + // TODO: don't leak memory here + descriptor: unsafe { + mem::transmute(box BlockDescriptor::::new()) + }, + context: context, + } + } + + pub fn copy(&self) -> Id> { + unsafe { + let block = msg_send![self copy] as *mut Block; + Id::from_retained_ptr(block) + } + } +} + +impl Message for Block { } + +impl Clone for Block { + fn clone(&self) -> Block { + Block::new(self.invoke, self.context.clone()) + } +} + +unsafe extern fn block_context_dispose(block: &mut Block) { + let mut context = mem::uninitialized(); + ptr::copy_nonoverlapping_memory(&mut context, &block.context, 1); + drop(context); +} + +unsafe extern fn block_context_copy(dst: &mut Block, src: &Block) { + dst.context = src.context.clone(); +} + +#[repr(C)] +struct BlockDescriptor { + _reserved: c_ulong, + block_size: c_ulong, + copy_helper: unsafe extern fn(&mut Block, &Block), + dispose_helper: unsafe extern fn(&mut Block), +} + +impl BlockDescriptor { + pub fn new() -> BlockDescriptor { + BlockDescriptor { + _reserved: 0, + block_size: mem::size_of::>() as c_ulong, + copy_helper: block_context_copy::, + dispose_helper: block_context_dispose::, + } + } +} From 1cece3bf5e8b0df83d5ac24d29b620972c908d76 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 6 Dec 2014 00:52:24 -0800 Subject: [PATCH 002/125] Added empty objc_test_utils crate. --- test_utils/Cargo.toml | 8 ++++++++ test_utils/lib.rs | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 test_utils/Cargo.toml create mode 100644 test_utils/lib.rs diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml new file mode 100644 index 000000000..4602653a3 --- /dev/null +++ b/test_utils/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "objc_test_utils" +version = "0.0.0" +authors = ["Steven Sheldon"] + +[lib] +name = "objc_test_utils" +path = "lib.rs" diff --git a/test_utils/lib.rs b/test_utils/lib.rs new file mode 100644 index 000000000..c1d0bfc99 --- /dev/null +++ b/test_utils/lib.rs @@ -0,0 +1,2 @@ +#![crate_name = "objc_test_utils"] +#![crate_type = "lib"] From 42a8f8a6a38c720f2d5ea4b6610f70a0a721f6f4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 6 Dec 2014 01:39:23 -0800 Subject: [PATCH 003/125] Added a block test. --- src/lib.rs | 20 ++++++++++++++++++++ test_utils/Cargo.toml | 5 +++++ test_utils/block_utils.m | 28 ++++++++++++++++++++++++++++ test_utils/build.rs | 8 ++++++++ test_utils/lib.rs | 15 +++++++++++++++ 5 files changed, 76 insertions(+) create mode 100644 test_utils/block_utils.m create mode 100644 test_utils/build.rs diff --git a/src/lib.rs b/src/lib.rs index f5a8076ca..e16a57a5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,3 +84,23 @@ impl BlockDescriptor { } } } + +#[cfg(test)] +mod tests { + use std::mem; + use objc_test_utils::invoke_int_block; + use super::Block; + + #[test] + fn test_create_block() { + extern fn block_get_int(block: &Block) -> int { + block.context + } + + let result = unsafe { + let block = Block::new(mem::transmute(block_get_int), 13i); + invoke_int_block(mem::transmute(&block)) + }; + assert!(result == 13); + } +} diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 4602653a3..a298960f9 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -3,6 +3,11 @@ name = "objc_test_utils" version = "0.0.0" authors = ["Steven Sheldon"] +build = "build.rs" + [lib] name = "objc_test_utils" path = "lib.rs" + +[build-dependencies] +gcc = "0.1.0" diff --git a/test_utils/block_utils.m b/test_utils/block_utils.m new file mode 100644 index 000000000..506a7dd5e --- /dev/null +++ b/test_utils/block_utils.m @@ -0,0 +1,28 @@ +#import + +typedef NSInteger (^IntBlock)(); +typedef NSInteger (^AddBlock)(NSInteger); + +IntBlock get_int_block() { + return ^{ return (NSInteger)7; }; +} + +IntBlock get_int_block_with(NSInteger i) { + return [^{ return i; } copy]; +} + +AddBlock get_add_block() { + return ^(NSInteger a) { return a + 7; }; +} + +AddBlock get_add_block_with(NSInteger i) { + return [^(NSInteger a) { return a + i; } copy]; +} + +NSInteger invoke_int_block(IntBlock block) { + return block(); +} + +NSInteger invoke_add_block(AddBlock block, NSInteger a) { + return block(a); +} diff --git a/test_utils/build.rs b/test_utils/build.rs new file mode 100644 index 000000000..57b060eb5 --- /dev/null +++ b/test_utils/build.rs @@ -0,0 +1,8 @@ +extern crate gcc; + +use std::default::Default; + +fn main() { + let config = Default::default(); + gcc::compile_library("libblock_utils.a", &config, &["block_utils.m"]); +} diff --git a/test_utils/lib.rs b/test_utils/lib.rs index c1d0bfc99..c8d94ab43 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -1,2 +1,17 @@ #![crate_name = "objc_test_utils"] #![crate_type = "lib"] + +extern crate libc; + +use libc::c_void; + +#[allow(improper_ctypes)] +#[link(name="block_utils", kind="static")] +extern { + pub fn get_int_block() -> *mut c_void; + pub fn get_int_block_with() -> *mut c_void; + pub fn get_add_block() -> *mut c_void; + pub fn get_add_block_with() -> *mut c_void; + pub fn invoke_int_block(block: *mut c_void) -> int; + pub fn invoke_add_block(block: *mut c_void, a: int) -> int; +} From 5b6ea3937edd08e1d2dd07fd3bf9a6f157cb7804 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 6 Dec 2014 02:47:48 -0800 Subject: [PATCH 004/125] Remove debug print. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e16a57a5a..4eef35f12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ struct Block { impl Block { pub fn new(invoke: unsafe extern fn(&mut Block, ...), context: C) -> Block { - println!("{}", _NSConcreteStackBlock.name()); Block { isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE From 046bb7967f11940b12eee895065eb49be13f8e3f Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 10 Dec 2014 23:50:59 -0800 Subject: [PATCH 005/125] Fixed warnings for the latest rust. --- test_utils/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index a298960f9..a7b62047f 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -10,4 +10,4 @@ name = "objc_test_utils" path = "lib.rs" [build-dependencies] -gcc = "0.1.0" +gcc = "0.1.1" From ad4f35cb159b2493f74286e0d0357296bd293de0 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 03:00:42 -0600 Subject: [PATCH 006/125] Renamed Block to ConcreteBlock. --- src/lib.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4eef35f12..875d30603 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,18 +14,18 @@ extern { } #[repr(C)] -struct Block { +struct ConcreteBlock { isa: *const Class, flags: c_int, _reserved: c_int, - pub invoke: unsafe extern fn(&mut Block, ...), + pub invoke: unsafe extern fn(&mut ConcreteBlock, ...), descriptor: *const BlockDescriptor, pub context: C, } -impl Block { - pub fn new(invoke: unsafe extern fn(&mut Block, ...), context: C) -> Block { - Block { +impl ConcreteBlock { + pub fn new(invoke: unsafe extern fn(&mut ConcreteBlock, ...), context: C) -> ConcreteBlock { + ConcreteBlock { isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE flags: 1 << 25, @@ -39,29 +39,29 @@ impl Block { } } - pub fn copy(&self) -> Id> { + pub fn copy(&self) -> Id> { unsafe { - let block = msg_send![self copy] as *mut Block; + let block = msg_send![self copy] as *mut ConcreteBlock; Id::from_retained_ptr(block) } } } -impl Message for Block { } +impl Message for ConcreteBlock { } -impl Clone for Block { - fn clone(&self) -> Block { - Block::new(self.invoke, self.context.clone()) +impl Clone for ConcreteBlock { + fn clone(&self) -> ConcreteBlock { + ConcreteBlock::new(self.invoke, self.context.clone()) } } -unsafe extern fn block_context_dispose(block: &mut Block) { +unsafe extern fn block_context_dispose(block: &mut ConcreteBlock) { let mut context = mem::uninitialized(); ptr::copy_nonoverlapping_memory(&mut context, &block.context, 1); drop(context); } -unsafe extern fn block_context_copy(dst: &mut Block, src: &Block) { +unsafe extern fn block_context_copy(dst: &mut ConcreteBlock, src: &ConcreteBlock) { dst.context = src.context.clone(); } @@ -69,15 +69,15 @@ unsafe extern fn block_context_copy(dst: &mut Block, src: &Block struct BlockDescriptor { _reserved: c_ulong, block_size: c_ulong, - copy_helper: unsafe extern fn(&mut Block, &Block), - dispose_helper: unsafe extern fn(&mut Block), + copy_helper: unsafe extern fn(&mut ConcreteBlock, &ConcreteBlock), + dispose_helper: unsafe extern fn(&mut ConcreteBlock), } impl BlockDescriptor { pub fn new() -> BlockDescriptor { BlockDescriptor { _reserved: 0, - block_size: mem::size_of::>() as c_ulong, + block_size: mem::size_of::>() as c_ulong, copy_helper: block_context_copy::, dispose_helper: block_context_dispose::, } @@ -88,16 +88,16 @@ impl BlockDescriptor { mod tests { use std::mem; use objc_test_utils::invoke_int_block; - use super::Block; + use super::ConcreteBlock; #[test] fn test_create_block() { - extern fn block_get_int(block: &Block) -> int { + extern fn block_get_int(block: &ConcreteBlock) -> int { block.context } let result = unsafe { - let block = Block::new(mem::transmute(block_get_int), 13i); + let block = ConcreteBlock::new(mem::transmute(block_get_int), 13i); invoke_int_block(mem::transmute(&block)) }; assert!(result == 13); From d6ea81744c984652eeedd11d73efe7760a790fdf Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 03:31:07 -0600 Subject: [PATCH 007/125] Added new Block struct. --- src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 875d30603..6e6ec6712 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,14 @@ extern { static _NSConcreteStackBlock: Class; } +#[repr(C)] +pub struct Block { + isa: *const Class, + flags: c_int, + _reserved: c_int, + invoke: unsafe extern fn(*mut Block, ...) -> R, +} + #[repr(C)] struct ConcreteBlock { isa: *const Class, From 1822be408935fee4e0295479984129633c115202 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 03:47:14 -0600 Subject: [PATCH 008/125] Added BlockArguments trait. --- src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6e6ec6712..e041e51d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,14 +13,24 @@ extern { static _NSConcreteStackBlock: Class; } +pub trait BlockArguments { + fn invoke_block(self, block: &Block) -> R; +} + #[repr(C)] -pub struct Block { +pub struct Block { isa: *const Class, flags: c_int, _reserved: c_int, invoke: unsafe extern fn(*mut Block, ...) -> R, } +impl Block { + pub fn call(&self, args: A) -> R { + args.invoke_block(self) + } +} + #[repr(C)] struct ConcreteBlock { isa: *const Class, From 993f5dd33bc7fa2596f8c30754bceaeb0dbe0f30 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 04:22:54 -0600 Subject: [PATCH 009/125] Implemented BlockArguments for empty tuple. --- src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e041e51d5..f1dc0793c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,18 @@ pub trait BlockArguments { fn invoke_block(self, block: &Block) -> R; } +impl BlockArguments for () { + fn invoke_block(self, block: &Block<(), R>) -> R { + let invoke: unsafe extern fn(*mut Block<(), R>) -> R = unsafe { + mem::transmute(block.invoke) + }; + let block_ptr = block as *const _ as *mut _; + unsafe { + invoke(block_ptr) + } + } +} + #[repr(C)] pub struct Block { isa: *const Class, From 78c4a00bf74546eb71082e55ecfc99204b8d5079 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 04:23:48 -0600 Subject: [PATCH 010/125] Implemented Message and a copy method for Block. --- src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f1dc0793c..897b6fa37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,11 +38,20 @@ pub struct Block { } impl Block { + pub fn copy(&self) -> Id> { + unsafe { + let block = msg_send![self copy] as *mut Block; + Id::from_retained_ptr(block) + } + } + pub fn call(&self, args: A) -> R { args.invoke_block(self) } } +impl Message for Block { } + #[repr(C)] struct ConcreteBlock { isa: *const Class, From 7b94de27b3ccbdb41a014f6f13302480c1f87d37 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 04:27:47 -0600 Subject: [PATCH 011/125] Refactor ConcreteBlock to have a base Block. --- src/lib.rs | 70 +++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 897b6fa37..331c97558 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,72 +53,65 @@ impl Block { impl Message for Block { } #[repr(C)] -struct ConcreteBlock { - isa: *const Class, - flags: c_int, - _reserved: c_int, - pub invoke: unsafe extern fn(&mut ConcreteBlock, ...), - descriptor: *const BlockDescriptor, +struct ConcreteBlock { + base: Block, + descriptor: *const BlockDescriptor>, pub context: C, } -impl ConcreteBlock { - pub fn new(invoke: unsafe extern fn(&mut ConcreteBlock, ...), context: C) -> ConcreteBlock { +impl ConcreteBlock { + pub fn new(invoke: unsafe extern fn(&ConcreteBlock, ...) -> R, context: C) -> ConcreteBlock { ConcreteBlock { - isa: &_NSConcreteStackBlock, - // 1 << 25 = BLOCK_HAS_COPY_DISPOSE - flags: 1 << 25, - _reserved: 0, - invoke: invoke, + base: Block { + isa: &_NSConcreteStackBlock, + // 1 << 25 = BLOCK_HAS_COPY_DISPOSE + flags: 1 << 25, + _reserved: 0, + invoke: unsafe { mem::transmute(invoke) }, + }, // TODO: don't leak memory here descriptor: unsafe { - mem::transmute(box BlockDescriptor::::new()) + mem::transmute(box BlockDescriptor::::new()) }, context: context, } } - - pub fn copy(&self) -> Id> { - unsafe { - let block = msg_send![self copy] as *mut ConcreteBlock; - Id::from_retained_ptr(block) - } - } } -impl Message for ConcreteBlock { } - -impl Clone for ConcreteBlock { - fn clone(&self) -> ConcreteBlock { - ConcreteBlock::new(self.invoke, self.context.clone()) +impl Clone for ConcreteBlock { + fn clone(&self) -> ConcreteBlock { + let invoke = unsafe { mem::transmute(self.base.invoke) }; + ConcreteBlock::new(invoke, self.context.clone()) } } -unsafe extern fn block_context_dispose(block: &mut ConcreteBlock) { +unsafe extern fn block_context_dispose( + block: &mut ConcreteBlock) { let mut context = mem::uninitialized(); ptr::copy_nonoverlapping_memory(&mut context, &block.context, 1); drop(context); } -unsafe extern fn block_context_copy(dst: &mut ConcreteBlock, src: &ConcreteBlock) { +unsafe extern fn block_context_copy( + dst: &mut ConcreteBlock, src: &ConcreteBlock) { dst.context = src.context.clone(); } #[repr(C)] -struct BlockDescriptor { +struct BlockDescriptor { _reserved: c_ulong, block_size: c_ulong, - copy_helper: unsafe extern fn(&mut ConcreteBlock, &ConcreteBlock), - dispose_helper: unsafe extern fn(&mut ConcreteBlock), + copy_helper: unsafe extern fn(&mut B, &B), + dispose_helper: unsafe extern fn(&mut B), } -impl BlockDescriptor { - pub fn new() -> BlockDescriptor { +impl BlockDescriptor> { + pub fn new() -> BlockDescriptor> { BlockDescriptor { _reserved: 0, - block_size: mem::size_of::>() as c_ulong, - copy_helper: block_context_copy::, - dispose_helper: block_context_dispose::, + block_size: mem::size_of::>() as c_ulong, + copy_helper: block_context_copy::, + dispose_helper: block_context_dispose::, } } } @@ -131,12 +124,13 @@ mod tests { #[test] fn test_create_block() { - extern fn block_get_int(block: &ConcreteBlock) -> int { + extern fn block_get_int(block: &ConcreteBlock<(), int, int>) -> int { block.context } let result = unsafe { - let block = ConcreteBlock::new(mem::transmute(block_get_int), 13i); + let block: ConcreteBlock<(), int, int> = + ConcreteBlock::new(mem::transmute(block_get_int), 13i); invoke_int_block(mem::transmute(&block)) }; assert!(result == 13); From 732b197195f907cebba16ffb4ab06a2d1b2a22ad Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 21 Dec 2014 13:35:25 -0600 Subject: [PATCH 012/125] Made creating ConcreteBlocks safer. Instead of supplying an extern fn, a simpler native rust fn is supplied and the BlockArguments trait is used to get an extern fn that wraps it. --- src/lib.rs | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 331c97558..4a809cbb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,12 +13,20 @@ extern { static _NSConcreteStackBlock: Class; } +pub type BlockInvoke = + unsafe extern fn(*mut Block, ...) -> R; + +pub type ConcreteBlockInvoke = + unsafe extern fn(*mut ConcreteBlock, ...) -> R; + pub trait BlockArguments { - fn invoke_block(self, block: &Block) -> R; + fn call_block(self, block: &Block) -> R; + + fn invoke_for_concrete_block() -> ConcreteBlockInvoke; } impl BlockArguments for () { - fn invoke_block(self, block: &Block<(), R>) -> R { + fn call_block(self, block: &Block<(), R>) -> R { let invoke: unsafe extern fn(*mut Block<(), R>) -> R = unsafe { mem::transmute(block.invoke) }; @@ -27,6 +35,18 @@ impl BlockArguments for () { invoke(block_ptr) } } + + fn invoke_for_concrete_block() -> ConcreteBlockInvoke<(), R, C> { + unsafe extern fn concrete_block_invoke_args0( + block_ptr: *mut ConcreteBlock<(), R, C>) -> R { + let block = &*block_ptr; + (block.rust_invoke)(&block.context, ()) + } + + unsafe { + mem::transmute(concrete_block_invoke_args0::) + } + } } #[repr(C)] @@ -34,7 +54,7 @@ pub struct Block { isa: *const Class, flags: c_int, _reserved: c_int, - invoke: unsafe extern fn(*mut Block, ...) -> R, + invoke: BlockInvoke, } impl Block { @@ -46,7 +66,7 @@ impl Block { } pub fn call(&self, args: A) -> R { - args.invoke_block(self) + args.call_block(self) } } @@ -56,23 +76,27 @@ impl Message for Block { } struct ConcreteBlock { base: Block, descriptor: *const BlockDescriptor>, - pub context: C, + rust_invoke: fn (&C, A) -> R, + context: C, } impl ConcreteBlock { - pub fn new(invoke: unsafe extern fn(&ConcreteBlock, ...) -> R, context: C) -> ConcreteBlock { + pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock { + let extern_invoke: ConcreteBlockInvoke = + BlockArguments::invoke_for_concrete_block(); ConcreteBlock { base: Block { isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE flags: 1 << 25, _reserved: 0, - invoke: unsafe { mem::transmute(invoke) }, + invoke: unsafe { mem::transmute(extern_invoke) }, }, // TODO: don't leak memory here descriptor: unsafe { mem::transmute(box BlockDescriptor::::new()) }, + rust_invoke: invoke, context: context, } } @@ -80,8 +104,7 @@ impl ConcreteBlock { impl Clone for ConcreteBlock { fn clone(&self) -> ConcreteBlock { - let invoke = unsafe { mem::transmute(self.base.invoke) }; - ConcreteBlock::new(invoke, self.context.clone()) + ConcreteBlock::new(self.rust_invoke, self.context.clone()) } } @@ -124,13 +147,12 @@ mod tests { #[test] fn test_create_block() { - extern fn block_get_int(block: &ConcreteBlock<(), int, int>) -> int { - block.context + fn block_get_int(context: &int, _args: ()) -> int { + *context } let result = unsafe { - let block: ConcreteBlock<(), int, int> = - ConcreteBlock::new(mem::transmute(block_get_int), 13i); + let block = ConcreteBlock::new(block_get_int, 13i); invoke_int_block(mem::transmute(&block)) }; assert!(result == 13); From 27c5aef7312b7318aa10a45770a6959e7e877e00 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Mon, 22 Dec 2014 22:16:17 -0600 Subject: [PATCH 013/125] Implemented BlockArguments up to 12-tuple with a macro. --- src/lib.rs | 66 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4a809cbb8..a75c24aa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,29 +25,51 @@ pub trait BlockArguments { fn invoke_for_concrete_block() -> ConcreteBlockInvoke; } -impl BlockArguments for () { - fn call_block(self, block: &Block<(), R>) -> R { - let invoke: unsafe extern fn(*mut Block<(), R>) -> R = unsafe { - mem::transmute(block.invoke) - }; - let block_ptr = block as *const _ as *mut _; - unsafe { - invoke(block_ptr) - } - } - - fn invoke_for_concrete_block() -> ConcreteBlockInvoke<(), R, C> { - unsafe extern fn concrete_block_invoke_args0( - block_ptr: *mut ConcreteBlock<(), R, C>) -> R { - let block = &*block_ptr; - (block.rust_invoke)(&block.context, ()) +macro_rules! block_args_impl( + ($f:ident $(, $a:ident : $t:ident)*) => ( + impl<$($t),*> BlockArguments for ($($t,)*) { + fn call_block(self, block: &Block<($($t,)*), R>) -> R { + let invoke: unsafe extern fn(*mut Block<($($t,)*), R> $(, $t)*) -> R = unsafe { + mem::transmute(block.invoke) + }; + let ($($a,)*) = self; + let block_ptr = block as *const _ as *mut _; + unsafe { + invoke(block_ptr $(, $a)*) + } + } + + fn invoke_for_concrete_block() -> + ConcreteBlockInvoke<($($t,)*), R, X> { + unsafe extern fn $f( + block_ptr: *mut ConcreteBlock<($($t,)*), R, X> + $(, $a: $t)*) -> R { + let args = ($($a,)*); + let block = &*block_ptr; + (block.rust_invoke)(&block.context, args) + } + + unsafe { + mem::transmute($f::) + } + } } - - unsafe { - mem::transmute(concrete_block_invoke_args0::) - } - } -} + ); +); + +block_args_impl!(concrete_block_invoke_args0); +block_args_impl!(concrete_block_invoke_args1, a: A); +block_args_impl!(concrete_block_invoke_args2, a: A, b: B); +block_args_impl!(concrete_block_invoke_args3, a: A, b: B, c: C); +block_args_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D); +block_args_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E); +block_args_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F); +block_args_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G); +block_args_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); +block_args_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); +block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); +block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); +block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); #[repr(C)] pub struct Block { From 9b0c3b48c71c0e6b00c1ff7212c4bcfd420590e8 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Mon, 22 Dec 2014 22:55:34 -0600 Subject: [PATCH 014/125] Implemented Deref to Block for ConcreteBlock. --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a75c24aa2..b7ddde644 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,6 +130,12 @@ impl Clone for ConcreteBlock { } } +impl Deref> for ConcreteBlock { + fn deref(&self) -> &Block { + &self.base + } +} + unsafe extern fn block_context_dispose( block: &mut ConcreteBlock) { let mut context = mem::uninitialized(); From 45cadbdf318da2aee920e5efc81f2200cb044e5e Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Mon, 22 Dec 2014 22:57:44 -0600 Subject: [PATCH 015/125] Added more block tests. --- src/lib.rs | 81 +++++++++++++++++++++++++++++++++++++++++++---- test_utils/lib.rs | 12 +++---- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b7ddde644..f19f1c560 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -169,9 +169,67 @@ impl BlockDescriptor> { #[cfg(test)] mod tests { - use std::mem; - use objc_test_utils::invoke_int_block; - use super::ConcreteBlock; + use Id; + use objc_test_utils; + use super::{Block, ConcreteBlock}; + + fn get_int_block() -> &'static Block<(), int> { + unsafe { + &*(objc_test_utils::get_int_block() as *const _) + } + } + + fn get_int_block_with(i: int) -> Id> { + unsafe { + let ptr = objc_test_utils::get_int_block_with(i); + Id::from_retained_ptr(ptr as *mut _) + } + } + + fn get_add_block() -> &'static Block<(int,), int> { + unsafe { + &*(objc_test_utils::get_add_block() as *const _) + } + } + + fn get_add_block_with(i: int) -> Id> { + unsafe { + let ptr = objc_test_utils::get_add_block_with(i); + Id::from_retained_ptr(ptr as *mut _) + } + } + + fn invoke_int_block(block: &Block<(), int>) -> int { + let ptr = block as *const _ as *const _; + unsafe { + objc_test_utils::invoke_int_block(ptr) + } + } + + fn invoke_add_block(block: &Block<(int,), int>, a: int) -> int { + let ptr = block as *const _ as *const _; + unsafe { + objc_test_utils::invoke_add_block(ptr, a) + } + } + + #[test] + fn test_call_block() { + let block = get_int_block(); + assert!(block.call(()) == 7); + + let block = get_int_block_with(13); + assert!(block.call(()) == 13); + } + + #[test] + fn test_call_block_args() { + let block = get_add_block(); + assert!(block.call((2,)) == 9); + + let block = get_add_block_with(13); + assert!(block.call((2,)) == 15); + } #[test] fn test_create_block() { @@ -179,10 +237,19 @@ mod tests { *context } - let result = unsafe { - let block = ConcreteBlock::new(block_get_int, 13i); - invoke_int_block(mem::transmute(&block)) - }; + let block = ConcreteBlock::new(block_get_int, 13); + let result = invoke_int_block(&*block); assert!(result == 13); } + + #[test] + fn test_create_block_args() { + fn block_add_int(context: &int, (a,): (int,)) -> int { + a + *context + } + + let block = ConcreteBlock::new(block_add_int, 5); + let result = invoke_add_block(&*block, 6); + assert!(result == 11); + } } diff --git a/test_utils/lib.rs b/test_utils/lib.rs index c8d94ab43..aed1e3208 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -8,10 +8,10 @@ use libc::c_void; #[allow(improper_ctypes)] #[link(name="block_utils", kind="static")] extern { - pub fn get_int_block() -> *mut c_void; - pub fn get_int_block_with() -> *mut c_void; - pub fn get_add_block() -> *mut c_void; - pub fn get_add_block_with() -> *mut c_void; - pub fn invoke_int_block(block: *mut c_void) -> int; - pub fn invoke_add_block(block: *mut c_void, a: int) -> int; + pub fn get_int_block() -> *const c_void; + pub fn get_int_block_with(i: int) -> *const c_void; + pub fn get_add_block() -> *const c_void; + pub fn get_add_block_with(i: int) -> *const c_void; + pub fn invoke_int_block(block: *const c_void) -> int; + pub fn invoke_add_block(block: *const c_void, a: int) -> int; } From 78a4852170cedd7f68b5f805a41f29e44f9eaf06 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 01:26:03 -0600 Subject: [PATCH 016/125] Made block module public and added documentation. --- src/lib.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f19f1c560..c61be1787 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,7 @@ -#![allow(dead_code)] +//! A Rust interface for Objective-C blocks. +//! +//! For more information on the specifics of the block implementation, see +//! Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html use std::mem; use std::ptr; @@ -13,15 +16,22 @@ extern { static _NSConcreteStackBlock: Class; } -pub type BlockInvoke = - unsafe extern fn(*mut Block, ...) -> R; +/// An invoke function for a `Block`; this is the raw C function called by the +/// Objective-C runtime. +type BlockInvoke = unsafe extern fn(*mut Block, ...) -> R; +/// An invoke function for a `ConcreteBlock`; this is the raw C function called +/// by the Objective-C runtime. pub type ConcreteBlockInvoke = unsafe extern fn(*mut ConcreteBlock, ...) -> R; +/// Types that may be used as the arguments to an Objective-C block. pub trait BlockArguments { + /// Calls the given `Block` with self as the arguments. fn call_block(self, block: &Block) -> R; + /// Returns an invoke function for a `ConcreteBlock` that takes this type + /// of arguments. fn invoke_for_concrete_block() -> ConcreteBlockInvoke; } @@ -71,6 +81,8 @@ block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); +/// An Objective-C block that takes arguments of `A` when called and +/// returns a value of `R`. #[repr(C)] pub struct Block { isa: *const Class, @@ -80,6 +92,7 @@ pub struct Block { } impl Block { + /// Copy self onto the heap. pub fn copy(&self) -> Id> { unsafe { let block = msg_send![self copy] as *mut Block; @@ -87,6 +100,7 @@ impl Block { } } + /// Call self with the given arguments. pub fn call(&self, args: A) -> R { args.call_block(self) } @@ -94,8 +108,10 @@ impl Block { impl Message for Block { } +/// An Objective-C block whose size is known at compile time and may be +/// constructed on the stack. #[repr(C)] -struct ConcreteBlock { +pub struct ConcreteBlock { base: Block, descriptor: *const BlockDescriptor>, rust_invoke: fn (&C, A) -> R, @@ -103,6 +119,9 @@ struct ConcreteBlock { } impl ConcreteBlock { + /// Constructs a `ConcreteBlock` with the given invoke function and context. + /// When the block is called, it will return the value that results from + /// calling the invoke function with a reference to its context. pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock { let extern_invoke: ConcreteBlockInvoke = BlockArguments::invoke_for_concrete_block(); @@ -157,7 +176,7 @@ struct BlockDescriptor { } impl BlockDescriptor> { - pub fn new() -> BlockDescriptor> { + fn new() -> BlockDescriptor> { BlockDescriptor { _reserved: 0, block_size: mem::size_of::>() as c_ulong, From 34b5bb40d6f61658f8ce91e5b07f8e34fe207059 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 04:15:39 -0600 Subject: [PATCH 017/125] Added crashing test. --- src/lib.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index c61be1787..316db2937 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -164,6 +164,9 @@ unsafe extern fn block_context_dispose( unsafe extern fn block_context_copy( dst: &mut ConcreteBlock, src: &ConcreteBlock) { + // The src block actually gets memmoved to the destination beforehand, + // but we'll set the function pointer, too, to be safe. + dst.rust_invoke = src.rust_invoke; dst.context = src.context.clone(); } @@ -271,4 +274,22 @@ mod tests { let result = invoke_add_block(&*block, 6); assert!(result == 11); } + + #[test] + fn test_concrete_block_copy() { + fn block_get_string_len(context: &String, _args: ()) -> uint { + context.len() + } + + let s = "Hello!".into_string(); + let expected_len = s.len(); + let block = ConcreteBlock::new(block_get_string_len, s); + assert!(block.call(()) == expected_len); + + let copied = block.copy(); + assert!(copied.call(()) == expected_len); + + drop(block); + assert!(copied.call(()) == expected_len); + } } From 0e03246daceb43df3bae7ef76cd8d951c8e9ecad Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 11:17:15 -0600 Subject: [PATCH 018/125] Fixed a nasty bug in block_context_copy. Previous code was just assigning to an uninitialzed field, so the compiler was dropping it; by changing this to a ptr::write the existing value is no longer dropped. --- src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 316db2937..6a080b957 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,17 +157,16 @@ impl Deref> for ConcreteBlock( block: &mut ConcreteBlock) { - let mut context = mem::uninitialized(); - ptr::copy_nonoverlapping_memory(&mut context, &block.context, 1); - drop(context); + // Read the context from the block and let it drop + ptr::read(&block.context); } unsafe extern fn block_context_copy( dst: &mut ConcreteBlock, src: &ConcreteBlock) { // The src block actually gets memmoved to the destination beforehand, // but we'll set the function pointer, too, to be safe. - dst.rust_invoke = src.rust_invoke; - dst.context = src.context.clone(); + ptr::write(&mut dst.rust_invoke, src.rust_invoke); + ptr::write(&mut dst.context, src.context.clone()); } #[repr(C)] From 0c2c447eae42f1f734879a0dcfa09aed3a29302a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 11:20:46 -0600 Subject: [PATCH 019/125] Added ConcreteBlock clone test. --- src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6a080b957..aa3b4cc51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,6 +274,24 @@ mod tests { assert!(result == 11); } + #[test] + fn test_concrete_block_clone() { + fn block_get_string_len(context: &String, _args: ()) -> uint { + context.len() + } + + let s = "Hello!".into_string(); + let expected_len = s.len(); + let block = ConcreteBlock::new(block_get_string_len, s); + assert!(block.call(()) == expected_len); + + let cloned = block.clone(); + assert!(cloned.call(()) == expected_len); + + drop(block); + assert!(cloned.call(()) == expected_len); + } + #[test] fn test_concrete_block_copy() { fn block_get_string_len(context: &String, _args: ()) -> uint { From 4e26f3385201f45f044e5487aa49328389d1faa8 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 11:22:13 -0600 Subject: [PATCH 020/125] Rearranged some test code. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index aa3b4cc51..ac97ed82f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,16 +221,16 @@ mod tests { } fn invoke_int_block(block: &Block<(), int>) -> int { - let ptr = block as *const _ as *const _; + let ptr = block as *const _; unsafe { - objc_test_utils::invoke_int_block(ptr) + objc_test_utils::invoke_int_block(ptr as *const _) } } fn invoke_add_block(block: &Block<(int,), int>, a: int) -> int { - let ptr = block as *const _ as *const _; + let ptr = block as *const _; unsafe { - objc_test_utils::invoke_add_block(ptr, a) + objc_test_utils::invoke_add_block(ptr as *const _, a) } } From 5d2a103f9bd5806b12a61c6210a3c91cf681dcf8 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 11:32:48 -0600 Subject: [PATCH 021/125] Replace a usage of transmute in ConcreteBlock. --- src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ac97ed82f..feb184a72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,6 +125,13 @@ impl ConcreteBlock { pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock { let extern_invoke: ConcreteBlockInvoke = BlockArguments::invoke_for_concrete_block(); + // TODO: don't leak memory here + let descriptor_ptr = { + let descriptor = box BlockDescriptor::::new(); + let ptr = &*descriptor as *const _; + unsafe { mem::forget(descriptor) }; + ptr + }; ConcreteBlock { base: Block { isa: &_NSConcreteStackBlock, @@ -133,10 +140,7 @@ impl ConcreteBlock { _reserved: 0, invoke: unsafe { mem::transmute(extern_invoke) }, }, - // TODO: don't leak memory here - descriptor: unsafe { - mem::transmute(box BlockDescriptor::::new()) - }, + descriptor: descriptor_ptr, rust_invoke: invoke, context: context, } From 3573f2e02152970899cf359e2cbde8ab965528c9 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 23 Dec 2014 23:05:10 -0600 Subject: [PATCH 022/125] Stop leaking descriptors by cloning and dropping them. --- src/lib.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index feb184a72..6e57d8622 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,7 +113,7 @@ impl Message for Block { } #[repr(C)] pub struct ConcreteBlock { base: Block, - descriptor: *const BlockDescriptor>, + descriptor: Box>>, rust_invoke: fn (&C, A) -> R, context: C, } @@ -125,13 +125,6 @@ impl ConcreteBlock { pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock { let extern_invoke: ConcreteBlockInvoke = BlockArguments::invoke_for_concrete_block(); - // TODO: don't leak memory here - let descriptor_ptr = { - let descriptor = box BlockDescriptor::::new(); - let ptr = &*descriptor as *const _; - unsafe { mem::forget(descriptor) }; - ptr - }; ConcreteBlock { base: Block { isa: &_NSConcreteStackBlock, @@ -140,7 +133,7 @@ impl ConcreteBlock { _reserved: 0, invoke: unsafe { mem::transmute(extern_invoke) }, }, - descriptor: descriptor_ptr, + descriptor: box BlockDescriptor::::new(), rust_invoke: invoke, context: context, } @@ -161,12 +154,15 @@ impl Deref> for ConcreteBlock( block: &mut ConcreteBlock) { - // Read the context from the block and let it drop - ptr::read(&block.context); + // Read the block onto the stack and let it drop + ptr::read(block); } unsafe extern fn block_context_copy( dst: &mut ConcreteBlock, src: &ConcreteBlock) { + // Doesn't seem like the descriptor is supposed to change in this function, + // but our descriptor isn't static (that's hard), so we just clone the box. + ptr::write(&mut dst.descriptor, src.descriptor.clone()); // The src block actually gets memmoved to the destination beforehand, // but we'll set the function pointer, too, to be safe. ptr::write(&mut dst.rust_invoke, src.rust_invoke); @@ -192,6 +188,14 @@ impl BlockDescriptor> { } } +impl Copy for BlockDescriptor { } + +impl Clone for BlockDescriptor { + fn clone(&self) -> BlockDescriptor { + *self + } +} + #[cfg(test)] mod tests { use Id; From 942de97ae07c7294128cf20953ac584878889bfa Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 25 Dec 2014 03:32:26 -0600 Subject: [PATCH 023/125] Relax some ConcreteBlock type bounds. --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6e57d8622..2df44f289 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,7 @@ impl Message for Block { } /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] -pub struct ConcreteBlock { +pub struct ConcreteBlock { base: Block, descriptor: Box>>, rust_invoke: fn (&C, A) -> R, @@ -146,13 +146,13 @@ impl Clone for ConcreteBlock { } } -impl Deref> for ConcreteBlock { +impl Deref> for ConcreteBlock { fn deref(&self) -> &Block { &self.base } } -unsafe extern fn block_context_dispose( +unsafe extern fn block_context_dispose( block: &mut ConcreteBlock) { // Read the block onto the stack and let it drop ptr::read(block); From f3119f38670794f014f547ae0e41007596b78bb4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 27 Dec 2014 18:55:06 -0600 Subject: [PATCH 024/125] Move self in copy method and only impl it for ConcreteBlocks. --- src/lib.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2df44f289..fe76c400d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,14 +92,6 @@ pub struct Block { } impl Block { - /// Copy self onto the heap. - pub fn copy(&self) -> Id> { - unsafe { - let block = msg_send![self copy] as *mut Block; - Id::from_retained_ptr(block) - } - } - /// Call self with the given arguments. pub fn call(&self, args: A) -> R { args.call_block(self) @@ -140,6 +132,16 @@ impl ConcreteBlock { } } +impl ConcreteBlock { + /// Copy self onto the heap. + pub fn copy(self) -> Id> { + unsafe { + let block = msg_send![&self.base copy] as *mut Block; + Id::from_retained_ptr(block) + } + } +} + impl Clone for ConcreteBlock { fn clone(&self) -> ConcreteBlock { ConcreteBlock::new(self.rust_invoke, self.context.clone()) @@ -313,8 +315,5 @@ mod tests { let copied = block.copy(); assert!(copied.call(()) == expected_len); - - drop(block); - assert!(copied.call(()) == expected_len); } } From 186a4cc22c2078b117af565ebe597b5b02b889af Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 27 Dec 2014 19:30:15 -0600 Subject: [PATCH 025/125] Remove Clone bound from ConcreteBlock. --- src/lib.rs | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fe76c400d..4c2405ffd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ pub trait BlockArguments { /// Returns an invoke function for a `ConcreteBlock` that takes this type /// of arguments. - fn invoke_for_concrete_block() -> ConcreteBlockInvoke; + fn invoke_for_concrete_block() -> ConcreteBlockInvoke; } macro_rules! block_args_impl( @@ -49,9 +49,9 @@ macro_rules! block_args_impl( } } - fn invoke_for_concrete_block() -> + fn invoke_for_concrete_block() -> ConcreteBlockInvoke<($($t,)*), R, X> { - unsafe extern fn $f( + unsafe extern fn $f( block_ptr: *mut ConcreteBlock<($($t,)*), R, X> $(, $a: $t)*) -> R { let args = ($($a,)*); @@ -110,7 +110,7 @@ pub struct ConcreteBlock { context: C, } -impl ConcreteBlock { +impl ConcreteBlock { /// Constructs a `ConcreteBlock` with the given invoke function and context. /// When the block is called, it will return the value that results from /// calling the invoke function with a reference to its context. @@ -130,13 +130,15 @@ impl ConcreteBlock { context: context, } } -} -impl ConcreteBlock { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { let block = msg_send![&self.base copy] as *mut Block; + // At this point, our copy helper has been run so the block will + // be moved to the heap and we can forget the original block + // because the heap block will drop in our dispose helper. + mem::forget(self); Id::from_retained_ptr(block) } } @@ -160,15 +162,9 @@ unsafe extern fn block_context_dispose( ptr::read(block); } -unsafe extern fn block_context_copy( - dst: &mut ConcreteBlock, src: &ConcreteBlock) { - // Doesn't seem like the descriptor is supposed to change in this function, - // but our descriptor isn't static (that's hard), so we just clone the box. - ptr::write(&mut dst.descriptor, src.descriptor.clone()); - // The src block actually gets memmoved to the destination beforehand, - // but we'll set the function pointer, too, to be safe. - ptr::write(&mut dst.rust_invoke, src.rust_invoke); - ptr::write(&mut dst.context, src.context.clone()); +unsafe extern fn block_context_copy( + _dst: &mut ConcreteBlock, _src: &ConcreteBlock) { + // The runtime memmoves the src block into the dst block, nothing to do } #[repr(C)] @@ -179,7 +175,7 @@ struct BlockDescriptor { dispose_helper: unsafe extern fn(&mut B), } -impl BlockDescriptor> { +impl BlockDescriptor> { fn new() -> BlockDescriptor> { BlockDescriptor { _reserved: 0, @@ -190,14 +186,6 @@ impl BlockDescriptor> { } } -impl Copy for BlockDescriptor { } - -impl Clone for BlockDescriptor { - fn clone(&self) -> BlockDescriptor { - *self - } -} - #[cfg(test)] mod tests { use Id; From d6670acb257491932748b25b4ddf8a87ab86ef3a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 27 Dec 2014 19:38:11 -0600 Subject: [PATCH 026/125] BlockDescriptor isn't specific to ConcreteBlock. --- src/lib.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4c2405ffd..b6b05edda 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,7 +125,7 @@ impl ConcreteBlock { _reserved: 0, invoke: unsafe { mem::transmute(extern_invoke) }, }, - descriptor: box BlockDescriptor::::new(), + descriptor: box BlockDescriptor::>::new(), rust_invoke: invoke, context: context, } @@ -156,14 +156,12 @@ impl Deref> for ConcreteBlock { } } -unsafe extern fn block_context_dispose( - block: &mut ConcreteBlock) { +unsafe extern fn block_context_dispose(block: &mut B) { // Read the block onto the stack and let it drop ptr::read(block); } -unsafe extern fn block_context_copy( - _dst: &mut ConcreteBlock, _src: &ConcreteBlock) { +unsafe extern fn block_context_copy(_dst: &mut B, _src: &B) { // The runtime memmoves the src block into the dst block, nothing to do } @@ -175,13 +173,13 @@ struct BlockDescriptor { dispose_helper: unsafe extern fn(&mut B), } -impl BlockDescriptor> { - fn new() -> BlockDescriptor> { +impl BlockDescriptor { + fn new() -> BlockDescriptor { BlockDescriptor { _reserved: 0, - block_size: mem::size_of::>() as c_ulong, - copy_helper: block_context_copy::, - dispose_helper: block_context_dispose::, + block_size: mem::size_of::() as c_ulong, + copy_helper: block_context_copy::, + dispose_helper: block_context_dispose::, } } } From e250b92721c3ead094dfe0127e5286ec4597d673 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 27 Dec 2014 20:04:34 -0600 Subject: [PATCH 027/125] Replace into_string for the latest rust. --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b6b05edda..61509d3e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -276,7 +276,7 @@ mod tests { context.len() } - let s = "Hello!".into_string(); + let s = String::from_str("Hello!"); let expected_len = s.len(); let block = ConcreteBlock::new(block_get_string_len, s); assert!(block.call(()) == expected_len); @@ -294,7 +294,7 @@ mod tests { context.len() } - let s = "Hello!".into_string(); + let s = String::from_str("Hello!"); let expected_len = s.len(); let block = ConcreteBlock::new(block_get_string_len, s); assert!(block.call(()) == expected_len); From 32001d676b636f75a6e387a4fc16af420c4c1c31 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 27 Dec 2014 20:13:07 -0600 Subject: [PATCH 028/125] Dried up some block code using Self. --- src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 61509d3e1..1e28582b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,8 +38,8 @@ pub trait BlockArguments { macro_rules! block_args_impl( ($f:ident $(, $a:ident : $t:ident)*) => ( impl<$($t),*> BlockArguments for ($($t,)*) { - fn call_block(self, block: &Block<($($t,)*), R>) -> R { - let invoke: unsafe extern fn(*mut Block<($($t,)*), R> $(, $t)*) -> R = unsafe { + fn call_block(self, block: &Block) -> R { + let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { mem::transmute(block.invoke) }; let ($($a,)*) = self; @@ -50,9 +50,9 @@ macro_rules! block_args_impl( } fn invoke_for_concrete_block() -> - ConcreteBlockInvoke<($($t,)*), R, X> { + ConcreteBlockInvoke { unsafe extern fn $f( - block_ptr: *mut ConcreteBlock<($($t,)*), R, X> + block_ptr: *mut ConcreteBlock $(, $a: $t)*) -> R { let args = ($($a,)*); let block = &*block_ptr; @@ -114,7 +114,7 @@ impl ConcreteBlock { /// Constructs a `ConcreteBlock` with the given invoke function and context. /// When the block is called, it will return the value that results from /// calling the invoke function with a reference to its context. - pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock { + pub fn new(invoke: fn (&C, A) -> R, context: C) -> Self { let extern_invoke: ConcreteBlockInvoke = BlockArguments::invoke_for_concrete_block(); ConcreteBlock { @@ -125,7 +125,7 @@ impl ConcreteBlock { _reserved: 0, invoke: unsafe { mem::transmute(extern_invoke) }, }, - descriptor: box BlockDescriptor::>::new(), + descriptor: box BlockDescriptor::::new(), rust_invoke: invoke, context: context, } @@ -145,7 +145,7 @@ impl ConcreteBlock { } impl Clone for ConcreteBlock { - fn clone(&self) -> ConcreteBlock { + fn clone(&self) -> Self { ConcreteBlock::new(self.rust_invoke, self.context.clone()) } } From 8bd035ae716770fc62d198b71e14478404305525 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 27 Dec 2014 21:24:04 -0600 Subject: [PATCH 029/125] Changed ConcreteBlock to use a generic closure. The old behavior can be replicated by creating a custom closure with a context and function. --- src/lib.rs | 74 ++++++++++++++---------------------------------------- 1 file changed, 19 insertions(+), 55 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1e28582b1..6c51dcc2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,8 +22,8 @@ type BlockInvoke = unsafe extern fn(*mut Block, ...) -> R; /// An invoke function for a `ConcreteBlock`; this is the raw C function called /// by the Objective-C runtime. -pub type ConcreteBlockInvoke = - unsafe extern fn(*mut ConcreteBlock, ...) -> R; +pub type ConcreteBlockInvoke = + unsafe extern fn(*mut ConcreteBlock, ...) -> R; /// Types that may be used as the arguments to an Objective-C block. pub trait BlockArguments { @@ -32,7 +32,7 @@ pub trait BlockArguments { /// Returns an invoke function for a `ConcreteBlock` that takes this type /// of arguments. - fn invoke_for_concrete_block() -> ConcreteBlockInvoke; + fn invoke_for_concrete_block>() -> ConcreteBlockInvoke; } macro_rules! block_args_impl( @@ -49,14 +49,13 @@ macro_rules! block_args_impl( } } - fn invoke_for_concrete_block() -> + fn invoke_for_concrete_block>() -> ConcreteBlockInvoke { - unsafe extern fn $f( + unsafe extern fn $f $(, $t)*>( block_ptr: *mut ConcreteBlock $(, $a: $t)*) -> R { - let args = ($($a,)*); let block = &*block_ptr; - (block.rust_invoke)(&block.context, args) + (block.closure)($($a),*) } unsafe { @@ -103,19 +102,15 @@ impl Message for Block { } /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] -pub struct ConcreteBlock { +pub struct ConcreteBlock { base: Block, - descriptor: Box>>, - rust_invoke: fn (&C, A) -> R, - context: C, + descriptor: Box>>, + closure: F, } -impl ConcreteBlock { - /// Constructs a `ConcreteBlock` with the given invoke function and context. - /// When the block is called, it will return the value that results from - /// calling the invoke function with a reference to its context. - pub fn new(invoke: fn (&C, A) -> R, context: C) -> Self { - let extern_invoke: ConcreteBlockInvoke = +impl> ConcreteBlock { + pub fn new(closure: F) -> Self { + let extern_invoke: ConcreteBlockInvoke = BlockArguments::invoke_for_concrete_block(); ConcreteBlock { base: Block { @@ -126,8 +121,7 @@ impl ConcreteBlock { invoke: unsafe { mem::transmute(extern_invoke) }, }, descriptor: box BlockDescriptor::::new(), - rust_invoke: invoke, - context: context, + closure: closure, } } @@ -144,13 +138,13 @@ impl ConcreteBlock { } } -impl Clone for ConcreteBlock { +impl + Clone> Clone for ConcreteBlock { fn clone(&self) -> Self { - ConcreteBlock::new(self.rust_invoke, self.context.clone()) + ConcreteBlock::new(self.closure.clone()) } } -impl Deref> for ConcreteBlock { +impl Deref> for ConcreteBlock { fn deref(&self) -> &Block { &self.base } @@ -250,53 +244,23 @@ mod tests { #[test] fn test_create_block() { - fn block_get_int(context: &int, _args: ()) -> int { - *context - } - - let block = ConcreteBlock::new(block_get_int, 13); + let block = ConcreteBlock::new(|&:| 13); let result = invoke_int_block(&*block); assert!(result == 13); } #[test] fn test_create_block_args() { - fn block_add_int(context: &int, (a,): (int,)) -> int { - a + *context - } - - let block = ConcreteBlock::new(block_add_int, 5); + let block = ConcreteBlock::new(|&: a: int| a + 5); let result = invoke_add_block(&*block, 6); assert!(result == 11); } - #[test] - fn test_concrete_block_clone() { - fn block_get_string_len(context: &String, _args: ()) -> uint { - context.len() - } - - let s = String::from_str("Hello!"); - let expected_len = s.len(); - let block = ConcreteBlock::new(block_get_string_len, s); - assert!(block.call(()) == expected_len); - - let cloned = block.clone(); - assert!(cloned.call(()) == expected_len); - - drop(block); - assert!(cloned.call(()) == expected_len); - } - #[test] fn test_concrete_block_copy() { - fn block_get_string_len(context: &String, _args: ()) -> uint { - context.len() - } - let s = String::from_str("Hello!"); let expected_len = s.len(); - let block = ConcreteBlock::new(block_get_string_len, s); + let block = ConcreteBlock::new(move |&:| s.len()); assert!(block.call(()) == expected_len); let copied = block.copy(); From 03a04fba9d28c215b537d6311c5e91bbd9a3b419 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 28 Dec 2014 02:44:40 -0600 Subject: [PATCH 030/125] Implement Fn trait for blocks. --- src/lib.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6c51dcc2f..19d35f176 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,9 +90,9 @@ pub struct Block { invoke: BlockInvoke, } -impl Block { +impl Fn for Block { /// Call self with the given arguments. - pub fn call(&self, args: A) -> R { + extern "rust-call" fn call(&self, args: A) -> R { args.call_block(self) } } @@ -150,6 +150,12 @@ impl Deref> for ConcreteBlock { } } +impl> Fn for ConcreteBlock { + extern "rust-call" fn call(&self, args: A) -> R { + self.closure.call(args) + } +} + unsafe extern fn block_context_dispose(block: &mut B) { // Read the block onto the stack and let it drop ptr::read(block); @@ -227,19 +233,19 @@ mod tests { #[test] fn test_call_block() { let block = get_int_block(); - assert!(block.call(()) == 7); + assert!((*block)() == 7); let block = get_int_block_with(13); - assert!(block.call(()) == 13); + assert!((*block)() == 13); } #[test] fn test_call_block_args() { let block = get_add_block(); - assert!(block.call((2,)) == 9); + assert!((*block)(2) == 9); let block = get_add_block_with(13); - assert!(block.call((2,)) == 15); + assert!((*block)(2) == 15); } #[test] @@ -261,9 +267,9 @@ mod tests { let s = String::from_str("Hello!"); let expected_len = s.len(); let block = ConcreteBlock::new(move |&:| s.len()); - assert!(block.call(()) == expected_len); + assert!((*block)() == expected_len); let copied = block.copy(); - assert!(copied.call(()) == expected_len); + assert!((*copied)() == expected_len); } } From d3579e8619a25c2ee51ff59bd3f338a32a81d5a0 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Mon, 29 Dec 2014 12:12:52 -0600 Subject: [PATCH 031/125] Simplified ConcreteBlock declaration. --- src/lib.rs | 56 ++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 19d35f176..3060ba705 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,15 +16,6 @@ extern { static _NSConcreteStackBlock: Class; } -/// An invoke function for a `Block`; this is the raw C function called by the -/// Objective-C runtime. -type BlockInvoke = unsafe extern fn(*mut Block, ...) -> R; - -/// An invoke function for a `ConcreteBlock`; this is the raw C function called -/// by the Objective-C runtime. -pub type ConcreteBlockInvoke = - unsafe extern fn(*mut ConcreteBlock, ...) -> R; - /// Types that may be used as the arguments to an Objective-C block. pub trait BlockArguments { /// Calls the given `Block` with self as the arguments. @@ -32,7 +23,8 @@ pub trait BlockArguments { /// Returns an invoke function for a `ConcreteBlock` that takes this type /// of arguments. - fn invoke_for_concrete_block>() -> ConcreteBlockInvoke; + fn invoke_for_concrete_block>() -> + unsafe extern fn(*mut ConcreteBlock, ...) -> R; } macro_rules! block_args_impl( @@ -50,9 +42,9 @@ macro_rules! block_args_impl( } fn invoke_for_concrete_block>() -> - ConcreteBlockInvoke { + unsafe extern fn(*mut ConcreteBlock, ...) -> R { unsafe extern fn $f $(, $t)*>( - block_ptr: *mut ConcreteBlock + block_ptr: *mut ConcreteBlock $(, $a: $t)*) -> R { let block = &*block_ptr; (block.closure)($($a),*) @@ -87,7 +79,7 @@ pub struct Block { isa: *const Class, flags: c_int, _reserved: c_int, - invoke: BlockInvoke, + invoke: unsafe extern fn(*mut Block, ...) -> R, } impl Fn for Block { @@ -102,24 +94,25 @@ impl Message for Block { } /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] -pub struct ConcreteBlock { - base: Block, - descriptor: Box>>, +pub struct ConcreteBlock { + isa: *const Class, + flags: c_int, + _reserved: c_int, + invoke: unsafe extern fn(*mut ConcreteBlock, ...), + descriptor: Box>>, closure: F, } -impl> ConcreteBlock { +impl> ConcreteBlock { pub fn new(closure: F) -> Self { - let extern_invoke: ConcreteBlockInvoke = - BlockArguments::invoke_for_concrete_block(); + let extern_invoke = + BlockArguments::invoke_for_concrete_block::(); ConcreteBlock { - base: Block { - isa: &_NSConcreteStackBlock, - // 1 << 25 = BLOCK_HAS_COPY_DISPOSE - flags: 1 << 25, - _reserved: 0, - invoke: unsafe { mem::transmute(extern_invoke) }, - }, + isa: &_NSConcreteStackBlock, + // 1 << 25 = BLOCK_HAS_COPY_DISPOSE + flags: 1 << 25, + _reserved: 0, + invoke: unsafe { mem::transmute(extern_invoke) }, descriptor: box BlockDescriptor::::new(), closure: closure, } @@ -128,7 +121,7 @@ impl> ConcreteBlock { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { - let block = msg_send![&self.base copy] as *mut Block; + let block = msg_send![&*self copy] as *mut Block; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. @@ -138,19 +131,20 @@ impl> ConcreteBlock { } } -impl + Clone> Clone for ConcreteBlock { +impl + Clone> Clone for ConcreteBlock { fn clone(&self) -> Self { ConcreteBlock::new(self.closure.clone()) } } -impl Deref> for ConcreteBlock { +impl> Deref> for ConcreteBlock { fn deref(&self) -> &Block { - &self.base + let ptr = self as *const _ as *const Block; + unsafe { &*ptr } } } -impl> Fn for ConcreteBlock { +impl> Fn for ConcreteBlock { extern "rust-call" fn call(&self, args: A) -> R { self.closure.call(args) } From 052e479b0aa5af29f7e9f7608a2ea5ef19347bdf Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 30 Dec 2014 01:46:28 -0600 Subject: [PATCH 032/125] Add back a comment for ConcreteBlock's new method. --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3060ba705..a59a5b4fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,6 +104,9 @@ pub struct ConcreteBlock { } impl> ConcreteBlock { + /// Constructs a `ConcreteBlock` with the given closure. + /// When the block is called, it will return the value that results from + /// calling the closure. pub fn new(closure: F) -> Self { let extern_invoke = BlockArguments::invoke_for_concrete_block::(); From be61ff1a12239fb1683aa48417b97742b07aaf32 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 30 Dec 2014 23:21:26 -0600 Subject: [PATCH 033/125] Calling a Block requires a mut reference. --- src/lib.rs | 75 ++++++++++++++++++++--------------------------- test_utils/lib.rs | 12 ++++---- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a59a5b4fd..5b117104d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ extern { /// Types that may be used as the arguments to an Objective-C block. pub trait BlockArguments { /// Calls the given `Block` with self as the arguments. - fn call_block(self, block: &Block) -> R; + fn call_block(self, block: &mut Block) -> R; /// Returns an invoke function for a `ConcreteBlock` that takes this type /// of arguments. @@ -30,14 +30,13 @@ pub trait BlockArguments { macro_rules! block_args_impl( ($f:ident $(, $a:ident : $t:ident)*) => ( impl<$($t),*> BlockArguments for ($($t,)*) { - fn call_block(self, block: &Block) -> R { + fn call_block(self, block: &mut Block) -> R { let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { mem::transmute(block.invoke) }; let ($($a,)*) = self; - let block_ptr = block as *const _ as *mut _; unsafe { - invoke(block_ptr $(, $a)*) + invoke(block $(, $a)*) } } @@ -82,9 +81,10 @@ pub struct Block { invoke: unsafe extern fn(*mut Block, ...) -> R, } -impl Fn for Block { +// TODO: impl FnMut when it's possible +impl Block { /// Call self with the given arguments. - extern "rust-call" fn call(&self, args: A) -> R { + pub fn call(&mut self, args: A) -> R { args.call_block(self) } } @@ -147,6 +147,13 @@ impl> Deref> for ConcreteBlock } } +impl> DerefMut> for ConcreteBlock { + fn deref_mut(&mut self) -> &mut Block { + let ptr = self as *mut _ as *mut Block; + unsafe { &mut *ptr } + } +} + impl> Fn for ConcreteBlock { extern "rust-call" fn call(&self, args: A) -> R { self.closure.call(args) @@ -187,12 +194,6 @@ mod tests { use objc_test_utils; use super::{Block, ConcreteBlock}; - fn get_int_block() -> &'static Block<(), int> { - unsafe { - &*(objc_test_utils::get_int_block() as *const _) - } - } - fn get_int_block_with(i: int) -> Id> { unsafe { let ptr = objc_test_utils::get_int_block_with(i); @@ -200,12 +201,6 @@ mod tests { } } - fn get_add_block() -> &'static Block<(int,), int> { - unsafe { - &*(objc_test_utils::get_add_block() as *const _) - } - } - fn get_add_block_with(i: int) -> Id> { unsafe { let ptr = objc_test_utils::get_add_block_with(i); @@ -213,60 +208,54 @@ mod tests { } } - fn invoke_int_block(block: &Block<(), int>) -> int { - let ptr = block as *const _; + fn invoke_int_block(block: &mut Block<(), int>) -> int { + let ptr = block as *mut _; unsafe { - objc_test_utils::invoke_int_block(ptr as *const _) + objc_test_utils::invoke_int_block(ptr as *mut _) } } - fn invoke_add_block(block: &Block<(int,), int>, a: int) -> int { - let ptr = block as *const _; + fn invoke_add_block(block: &mut Block<(int,), int>, a: int) -> int { + let ptr = block as *mut _; unsafe { - objc_test_utils::invoke_add_block(ptr as *const _, a) + objc_test_utils::invoke_add_block(ptr as *mut _, a) } } #[test] fn test_call_block() { - let block = get_int_block(); - assert!((*block)() == 7); - - let block = get_int_block_with(13); - assert!((*block)() == 13); + let mut block = get_int_block_with(13); + assert!(block.call(()) == 13); } #[test] fn test_call_block_args() { - let block = get_add_block(); - assert!((*block)(2) == 9); - - let block = get_add_block_with(13); - assert!((*block)(2) == 15); + let mut block = get_add_block_with(13); + assert!(block.call((2,)) == 15); } #[test] fn test_create_block() { - let block = ConcreteBlock::new(|&:| 13); - let result = invoke_int_block(&*block); + let mut block = ConcreteBlock::new(|&:| 13); + let result = invoke_int_block(&mut *block); assert!(result == 13); } #[test] fn test_create_block_args() { - let block = ConcreteBlock::new(|&: a: int| a + 5); - let result = invoke_add_block(&*block, 6); + let mut block = ConcreteBlock::new(|&: a: int| a + 5); + let result = invoke_add_block(&mut *block, 6); assert!(result == 11); } #[test] fn test_concrete_block_copy() { let s = String::from_str("Hello!"); - let expected_len = s.len(); - let block = ConcreteBlock::new(move |&:| s.len()); - assert!((*block)() == expected_len); + let expected_len = s.len() as int; + let mut block = ConcreteBlock::new(move |&:| s.len() as int); + assert!(invoke_int_block(&mut *block) == expected_len); - let copied = block.copy(); - assert!((*copied)() == expected_len); + let mut copied = block.copy(); + assert!(invoke_int_block(&mut *copied) == expected_len); } } diff --git a/test_utils/lib.rs b/test_utils/lib.rs index aed1e3208..3ea0c2783 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -8,10 +8,10 @@ use libc::c_void; #[allow(improper_ctypes)] #[link(name="block_utils", kind="static")] extern { - pub fn get_int_block() -> *const c_void; - pub fn get_int_block_with(i: int) -> *const c_void; - pub fn get_add_block() -> *const c_void; - pub fn get_add_block_with(i: int) -> *const c_void; - pub fn invoke_int_block(block: *const c_void) -> int; - pub fn invoke_add_block(block: *const c_void, a: int) -> int; + pub fn get_int_block() -> *mut c_void; + pub fn get_int_block_with(i: int) -> *mut c_void; + pub fn get_add_block() -> *mut c_void; + pub fn get_add_block_with(i: int) -> *mut c_void; + pub fn invoke_int_block(block: *mut c_void) -> int; + pub fn invoke_add_block(block: *mut c_void, a: int) -> int; } From eec21a1604df764e57d6073e5056341d68bd01f2 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 30 Dec 2014 23:24:03 -0600 Subject: [PATCH 034/125] Removed Fn implementation for ConcreteBlock. --- src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5b117104d..a2d566765 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,12 +154,6 @@ impl> DerefMut> for ConcreteBlock< } } -impl> Fn for ConcreteBlock { - extern "rust-call" fn call(&self, args: A) -> R { - self.closure.call(args) - } -} - unsafe extern fn block_context_dispose(block: &mut B) { // Read the block onto the stack and let it drop ptr::read(block); From 57daad91972a6f13dfd64f2f2835081b7a2910ad Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 6 Jan 2015 03:03:46 -0800 Subject: [PATCH 035/125] Updated for the latest rust. --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a2d566765..38ea6c854 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ //! Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html use std::mem; +use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong}; @@ -140,14 +141,16 @@ impl + Clone> Clone for ConcreteBlock { } } -impl> Deref> for ConcreteBlock { +impl> Deref for ConcreteBlock { + type Target = Block; + fn deref(&self) -> &Block { let ptr = self as *const _ as *const Block; unsafe { &*ptr } } } -impl> DerefMut> for ConcreteBlock { +impl> DerefMut for ConcreteBlock { fn deref_mut(&mut self) -> &mut Block { let ptr = self as *mut _ as *mut Block; unsafe { &mut *ptr } From 68d2a5df2ae5e2d7e2d5863072ab8d97de71a584 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 9 Jan 2015 22:27:55 -0800 Subject: [PATCH 036/125] Fixed most issues for the latest rust. Disabled the msg_send! and method! macros. --- src/lib.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 38ea6c854..46979d5d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong}; -use runtime::Class; +use runtime::{Class, Object, Sel, self}; use {Id, Message}; #[allow(improper_ctypes)] @@ -29,7 +29,10 @@ pub trait BlockArguments { } macro_rules! block_args_impl( - ($f:ident $(, $a:ident : $t:ident)*) => ( + ($f:ident) => ( + block_args_impl!($f,); + ); + ($f:ident, $($a:ident : $t:ident),*) => ( impl<$($t),*> BlockArguments for ($($t,)*) { fn call_block(self, block: &mut Block) -> R { let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { @@ -117,7 +120,7 @@ impl> ConcreteBlock { flags: 1 << 25, _reserved: 0, invoke: unsafe { mem::transmute(extern_invoke) }, - descriptor: box BlockDescriptor::::new(), + descriptor: Box::new(BlockDescriptor::::new()), closure: closure, } } @@ -125,12 +128,17 @@ impl> ConcreteBlock { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { - let block = msg_send![&*self copy] as *mut Block; + let mut block = self; + let copied = { + let sel = Sel::register("copy"); + let ptr = &mut *block as *mut Block as *mut Object; + runtime::objc_msgSend(ptr, sel) as *mut Block + }; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. - mem::forget(self); - Id::from_retained_ptr(block) + mem::forget(block); + Id::from_retained_ptr(copied) } } } From c798cd81e714beab05268c0c508bc510ab272554 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 9 Jan 2015 22:45:24 -0800 Subject: [PATCH 037/125] Add argument and return types back to ConcreteBlock. This reverts commit 3c6d05caf1b0e157892bebc69e6c3e3d72988c6e. --- src/lib.rs | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 46979d5d6..23ae4e474 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ pub trait BlockArguments { /// Returns an invoke function for a `ConcreteBlock` that takes this type /// of arguments. fn invoke_for_concrete_block>() -> - unsafe extern fn(*mut ConcreteBlock, ...) -> R; + unsafe extern fn(*mut ConcreteBlock, ...) -> R; } macro_rules! block_args_impl( @@ -45,9 +45,9 @@ macro_rules! block_args_impl( } fn invoke_for_concrete_block>() -> - unsafe extern fn(*mut ConcreteBlock, ...) -> R { + unsafe extern fn(*mut ConcreteBlock, ...) -> R { unsafe extern fn $f $(, $t)*>( - block_ptr: *mut ConcreteBlock + block_ptr: *mut ConcreteBlock $(, $a: $t)*) -> R { let block = &*block_ptr; (block.closure)($($a),*) @@ -98,16 +98,13 @@ impl Message for Block { } /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] -pub struct ConcreteBlock { - isa: *const Class, - flags: c_int, - _reserved: c_int, - invoke: unsafe extern fn(*mut ConcreteBlock, ...), - descriptor: Box>>, +pub struct ConcreteBlock { + base: Block, + descriptor: Box>>, closure: F, } -impl> ConcreteBlock { +impl> ConcreteBlock { /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. @@ -115,11 +112,13 @@ impl> ConcreteBlock { let extern_invoke = BlockArguments::invoke_for_concrete_block::(); ConcreteBlock { - isa: &_NSConcreteStackBlock, - // 1 << 25 = BLOCK_HAS_COPY_DISPOSE - flags: 1 << 25, - _reserved: 0, - invoke: unsafe { mem::transmute(extern_invoke) }, + base: Block { + isa: &_NSConcreteStackBlock, + // 1 << 25 = BLOCK_HAS_COPY_DISPOSE + flags: 1 << 25, + _reserved: 0, + invoke: unsafe { mem::transmute(extern_invoke) }, + }, descriptor: Box::new(BlockDescriptor::::new()), closure: closure, } @@ -131,7 +130,7 @@ impl> ConcreteBlock { let mut block = self; let copied = { let sel = Sel::register("copy"); - let ptr = &mut *block as *mut Block as *mut Object; + let ptr = &mut block.base as *mut _ as *mut Object; runtime::objc_msgSend(ptr, sel) as *mut Block }; // At this point, our copy helper has been run so the block will @@ -143,25 +142,23 @@ impl> ConcreteBlock { } } -impl + Clone> Clone for ConcreteBlock { +impl + Clone> Clone for ConcreteBlock { fn clone(&self) -> Self { ConcreteBlock::new(self.closure.clone()) } } -impl> Deref for ConcreteBlock { +impl> Deref for ConcreteBlock { type Target = Block; fn deref(&self) -> &Block { - let ptr = self as *const _ as *const Block; - unsafe { &*ptr } + &self.base } } -impl> DerefMut for ConcreteBlock { +impl> DerefMut for ConcreteBlock { fn deref_mut(&mut self) -> &mut Block { - let ptr = self as *mut _ as *mut Block; - unsafe { &mut *ptr } + &mut self.base } } From 481d37494cec78fca9352aa0015c9f78d4b7aa63 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 9 Jan 2015 23:35:44 -0800 Subject: [PATCH 038/125] Brought back the msg_send! macro with a comma. --- src/lib.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 23ae4e474..022991c01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong}; -use runtime::{Class, Object, Sel, self}; +use runtime::Class; use {Id, Message}; #[allow(improper_ctypes)] @@ -127,17 +127,12 @@ impl> ConcreteBlock { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { - let mut block = self; - let copied = { - let sel = Sel::register("copy"); - let ptr = &mut block.base as *mut _ as *mut Object; - runtime::objc_msgSend(ptr, sel) as *mut Block - }; + let block = msg_send![&self.base, copy] as *mut Block; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. - mem::forget(block); - Id::from_retained_ptr(copied) + mem::forget(self); + Id::from_retained_ptr(block) } } } From 9a552ffb401d745b6083d701ad00d7b19bcd47a3 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 00:06:05 -0800 Subject: [PATCH 039/125] Fixed core tests for the latest rust. --- test_utils/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index a7b62047f..e18aef127 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -10,4 +10,4 @@ name = "objc_test_utils" path = "lib.rs" [build-dependencies] -gcc = "0.1.1" +gcc = "0.1.4" From 06776644ea90aba5664aed09f4fecd0df8bf99df Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 12:18:12 -0800 Subject: [PATCH 040/125] Replaced int with i32 in test_utils. --- src/lib.rs | 14 +++++++------- test_utils/block_utils.m | 20 ++++++++++---------- test_utils/lib.rs | 9 ++++----- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 022991c01..0ded2a61a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -191,28 +191,28 @@ mod tests { use objc_test_utils; use super::{Block, ConcreteBlock}; - fn get_int_block_with(i: int) -> Id> { + fn get_int_block_with(i: i32) -> Id> { unsafe { let ptr = objc_test_utils::get_int_block_with(i); Id::from_retained_ptr(ptr as *mut _) } } - fn get_add_block_with(i: int) -> Id> { + fn get_add_block_with(i: i32) -> Id> { unsafe { let ptr = objc_test_utils::get_add_block_with(i); Id::from_retained_ptr(ptr as *mut _) } } - fn invoke_int_block(block: &mut Block<(), int>) -> int { + fn invoke_int_block(block: &mut Block<(), i32>) -> i32 { let ptr = block as *mut _; unsafe { objc_test_utils::invoke_int_block(ptr as *mut _) } } - fn invoke_add_block(block: &mut Block<(int,), int>, a: int) -> int { + fn invoke_add_block(block: &mut Block<(i32,), i32>, a: i32) -> i32 { let ptr = block as *mut _; unsafe { objc_test_utils::invoke_add_block(ptr as *mut _, a) @@ -240,7 +240,7 @@ mod tests { #[test] fn test_create_block_args() { - let mut block = ConcreteBlock::new(|&: a: int| a + 5); + let mut block = ConcreteBlock::new(|&: a: i32| a + 5); let result = invoke_add_block(&mut *block, 6); assert!(result == 11); } @@ -248,8 +248,8 @@ mod tests { #[test] fn test_concrete_block_copy() { let s = String::from_str("Hello!"); - let expected_len = s.len() as int; - let mut block = ConcreteBlock::new(move |&:| s.len() as int); + let expected_len = s.len() as i32; + let mut block = ConcreteBlock::new(move |&:| s.len() as i32); assert!(invoke_int_block(&mut *block) == expected_len); let mut copied = block.copy(); diff --git a/test_utils/block_utils.m b/test_utils/block_utils.m index 506a7dd5e..66fff8f43 100644 --- a/test_utils/block_utils.m +++ b/test_utils/block_utils.m @@ -1,28 +1,28 @@ -#import +#include -typedef NSInteger (^IntBlock)(); -typedef NSInteger (^AddBlock)(NSInteger); +typedef int32_t (^IntBlock)(); +typedef int32_t (^AddBlock)(int32_t); IntBlock get_int_block() { - return ^{ return (NSInteger)7; }; + return ^{ return (int32_t)7; }; } -IntBlock get_int_block_with(NSInteger i) { +IntBlock get_int_block_with(int32_t i) { return [^{ return i; } copy]; } AddBlock get_add_block() { - return ^(NSInteger a) { return a + 7; }; + return ^(int32_t a) { return a + 7; }; } -AddBlock get_add_block_with(NSInteger i) { - return [^(NSInteger a) { return a + i; } copy]; +AddBlock get_add_block_with(int32_t i) { + return [^(int32_t a) { return a + i; } copy]; } -NSInteger invoke_int_block(IntBlock block) { +int32_t invoke_int_block(IntBlock block) { return block(); } -NSInteger invoke_add_block(AddBlock block, NSInteger a) { +int32_t invoke_add_block(AddBlock block, int32_t a) { return block(a); } diff --git a/test_utils/lib.rs b/test_utils/lib.rs index 3ea0c2783..81416bc7b 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -5,13 +5,12 @@ extern crate libc; use libc::c_void; -#[allow(improper_ctypes)] #[link(name="block_utils", kind="static")] extern { pub fn get_int_block() -> *mut c_void; - pub fn get_int_block_with(i: int) -> *mut c_void; + pub fn get_int_block_with(i: i32) -> *mut c_void; pub fn get_add_block() -> *mut c_void; - pub fn get_add_block_with(i: int) -> *mut c_void; - pub fn invoke_int_block(block: *mut c_void) -> int; - pub fn invoke_add_block(block: *mut c_void, a: int) -> int; + pub fn get_add_block_with(i: i32) -> *mut c_void; + pub fn invoke_int_block(block: *mut c_void) -> i32; + pub fn invoke_add_block(block: *mut c_void, a: i32) -> i32; } From 679a8f65f22d26123ee9aefed5bb7f54a476b126 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 12:22:55 -0800 Subject: [PATCH 041/125] Silence the remaining unstable warnings. --- test_utils/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test_utils/lib.rs b/test_utils/lib.rs index 81416bc7b..a5413f8ff 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -1,6 +1,7 @@ #![crate_name = "objc_test_utils"] #![crate_type = "lib"] +#[allow(unstable)] extern crate libc; use libc::c_void; From 05c17eda9557d8795cb76c4768f1e83ab526d3b1 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 15:08:08 -0800 Subject: [PATCH 042/125] Made Message trait require an unsafe impl. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0ded2a61a..04b622e0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ impl Block { } } -impl Message for Block { } +unsafe impl Message for Block { } /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. From 5104479f50f4056dcd2a922bef60557dc5357dd4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 15:51:58 -0800 Subject: [PATCH 043/125] Added documentation and tests for test_utils. --- test_utils/lib.rs | 54 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/test_utils/lib.rs b/test_utils/lib.rs index a5413f8ff..7ef522cb4 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -1,17 +1,53 @@ #![crate_name = "objc_test_utils"] #![crate_type = "lib"] -#[allow(unstable)] -extern crate libc; +#![allow(unstable)] -use libc::c_void; +#[link(name = "Foundation", kind = "framework")] +extern { } + +/// A block that takes no arguments and returns an integer: `int32_t (^)()`. +#[allow(missing_copy_implementations)] +pub enum IntBlock { } + +/// A block that takes one integer argument, adds to it, and returns the sum: +/// `int32_t (^)(int32_t)`. +#[allow(missing_copy_implementations)] +pub enum AddBlock { } #[link(name="block_utils", kind="static")] extern { - pub fn get_int_block() -> *mut c_void; - pub fn get_int_block_with(i: i32) -> *mut c_void; - pub fn get_add_block() -> *mut c_void; - pub fn get_add_block_with(i: i32) -> *mut c_void; - pub fn invoke_int_block(block: *mut c_void) -> i32; - pub fn invoke_add_block(block: *mut c_void, a: i32) -> i32; + /// Returns a pointer to a global `IntBlock` that returns 7. + pub fn get_int_block() -> *mut IntBlock; + /// Returns a pointer to a copied `IntBlock` that returns `i`. + pub fn get_int_block_with(i: i32) -> *mut IntBlock; + /// Returns a pointer to a global `AddBlock` that returns its argument + 7. + pub fn get_add_block() -> *mut AddBlock; + /// Returns a pointer to a copied `AddBlock` that returns its argument + `i`. + pub fn get_add_block_with(i: i32) -> *mut AddBlock; + /// Invokes an `IntBlock` and returns its result. + pub fn invoke_int_block(block: *mut IntBlock) -> i32; + /// Invokes an `AddBlock` with `a` and returns the result. + pub fn invoke_add_block(block: *mut AddBlock, a: i32) -> i32; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_int_block() { + unsafe { + assert!(invoke_int_block(get_int_block()) == 7); + assert!(invoke_int_block(get_int_block_with(13)) == 13); + } + } + + #[test] + fn test_add_block() { + unsafe { + assert!(invoke_add_block(get_add_block(), 5) == 12); + assert!(invoke_add_block(get_add_block_with(3), 5) == 8); + } + } } From e609a1078535284b9ce5fc511a57b555db8c8310 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 17:05:31 -0800 Subject: [PATCH 044/125] Bump test_utils crate to 0.0.1 and add package metadata. --- test_utils/Cargo.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index e18aef127..ea5dd4988 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -1,8 +1,12 @@ [package] name = "objc_test_utils" -version = "0.0.0" +version = "0.0.1" authors = ["Steven Sheldon"] +description = "Utilities for testing Objective-C interop." +repository = "http://github.com/SSheldon/rust-objc" +documentation = "http://ssheldon.github.io/rust-objc/objc_test_utils/" + build = "build.rs" [lib] @@ -10,4 +14,4 @@ name = "objc_test_utils" path = "lib.rs" [build-dependencies] -gcc = "0.1.4" +gcc = "0.1" From b1efff8404f9ed03c844ee08590cc4cce6f0e9e1 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 10 Jan 2015 17:21:17 -0800 Subject: [PATCH 045/125] Added license which crates.io now requires. --- test_utils/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index ea5dd4988..bd4730a8d 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -6,6 +6,7 @@ authors = ["Steven Sheldon"] description = "Utilities for testing Objective-C interop." repository = "http://github.com/SSheldon/rust-objc" documentation = "http://ssheldon.github.io/rust-objc/objc_test_utils/" +license = "MIT" build = "build.rs" From bcb87e9657c892071c45df378b628f88ed35ca6b Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 13 Jan 2015 23:15:39 -0800 Subject: [PATCH 046/125] Converted trait bounds in core to use where clauses. --- src/lib.rs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 04b622e0b..31cae36e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,8 +24,9 @@ pub trait BlockArguments { /// Returns an invoke function for a `ConcreteBlock` that takes this type /// of arguments. - fn invoke_for_concrete_block>() -> - unsafe extern fn(*mut ConcreteBlock, ...) -> R; + fn invoke_for_concrete_block() -> + unsafe extern fn(*mut ConcreteBlock, ...) -> R + where F: Fn; } macro_rules! block_args_impl( @@ -44,11 +45,13 @@ macro_rules! block_args_impl( } } - fn invoke_for_concrete_block>() -> - unsafe extern fn(*mut ConcreteBlock, ...) -> R { - unsafe extern fn $f $(, $t)*>( + fn invoke_for_concrete_block() -> + unsafe extern fn(*mut ConcreteBlock, ...) -> R + where X: Fn { + unsafe extern fn $f( block_ptr: *mut ConcreteBlock - $(, $a: $t)*) -> R { + $(, $a: $t)*) -> R + where X: Fn { let block = &*block_ptr; (block.closure)($($a),*) } @@ -78,7 +81,7 @@ block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: /// An Objective-C block that takes arguments of `A` when called and /// returns a value of `R`. #[repr(C)] -pub struct Block { +pub struct Block where A: BlockArguments { isa: *const Class, flags: c_int, _reserved: c_int, @@ -86,25 +89,25 @@ pub struct Block { } // TODO: impl FnMut when it's possible -impl Block { +impl Block where A: BlockArguments { /// Call self with the given arguments. pub fn call(&mut self, args: A) -> R { args.call_block(self) } } -unsafe impl Message for Block { } +unsafe impl Message for Block where A: BlockArguments { } /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] -pub struct ConcreteBlock { +pub struct ConcreteBlock where A: BlockArguments { base: Block, descriptor: Box>>, closure: F, } -impl> ConcreteBlock { +impl ConcreteBlock where A: BlockArguments, F: Fn { /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. @@ -137,13 +140,15 @@ impl> ConcreteBlock { } } -impl + Clone> Clone for ConcreteBlock { +impl Clone for ConcreteBlock + where A: BlockArguments, F: Fn + Clone { fn clone(&self) -> Self { ConcreteBlock::new(self.closure.clone()) } } -impl> Deref for ConcreteBlock { +impl Deref for ConcreteBlock + where A: BlockArguments, F: Fn { type Target = Block; fn deref(&self) -> &Block { @@ -151,7 +156,8 @@ impl> Deref for ConcreteBlock { } } -impl> DerefMut for ConcreteBlock { +impl DerefMut for ConcreteBlock + where A: BlockArguments, F: Fn { fn deref_mut(&mut self) -> &mut Block { &mut self.base } From d61568bd591a7fb0e3288fbe747ff969e41f9b94 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 17 Jan 2015 11:50:01 -0800 Subject: [PATCH 047/125] Removed unnecessary allow(unstable) from test_utils. --- test_utils/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test_utils/lib.rs b/test_utils/lib.rs index 7ef522cb4..c38677e59 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -1,8 +1,6 @@ #![crate_name = "objc_test_utils"] #![crate_type = "lib"] -#![allow(unstable)] - #[link(name = "Foundation", kind = "framework")] extern { } From 2f7bf9fa3eb9b1f9cdc585faca323e48fa53636c Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 17 Jan 2015 21:29:21 -0800 Subject: [PATCH 048/125] Update core for msg_send using the MessageArguments trait. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 31cae36e9..ce1833e62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,7 +130,7 @@ impl ConcreteBlock where A: BlockArguments, F: Fn { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { - let block = msg_send![&self.base, copy] as *mut Block; + let block: *mut Block = msg_send![&self.base, copy]; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. From 093ea646ede697ff18f374672a4299a97bfc523f Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 18 Jan 2015 11:07:17 -0800 Subject: [PATCH 049/125] Made Message require EncodePtr. --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ce1833e62..eb1d216c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use std::ptr; use libc::{c_int, c_ulong}; use runtime::Class; -use {Id, Message}; +use {EncodePtr, Id, Message}; #[allow(improper_ctypes)] #[link(name = "Foundation", kind = "framework")] @@ -98,6 +98,10 @@ impl Block where A: BlockArguments { unsafe impl Message for Block where A: BlockArguments { } +impl EncodePtr for Block { + fn ptr_code() -> &'static str { "@?" } +} + /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] From e2be6b70c68c9bba40271d1db35f41a1a1f632de Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 18 Jan 2015 14:30:10 -0800 Subject: [PATCH 050/125] msg_send! macro verifies messages unless ndebug is set. --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index eb1d216c6..b34df65c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong}; -use runtime::Class; +use runtime::{Class, Object}; use {EncodePtr, Id, Message}; #[allow(improper_ctypes)] @@ -134,7 +134,9 @@ impl ConcreteBlock where A: BlockArguments, F: Fn { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { - let block: *mut Block = msg_send![&self.base, copy]; + // The copy method is declared as returning an object pointer. + let block: *mut Object = msg_send![&self.base, copy]; + let block = block as *mut Block; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. From efda93588067425037147912982f8be9d0534bac Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 30 Jan 2015 00:39:23 -0800 Subject: [PATCH 051/125] Updated Fn trait for latest rust. --- src/lib.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b34df65c7..c21167df1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ pub trait BlockArguments { /// of arguments. fn invoke_for_concrete_block() -> unsafe extern fn(*mut ConcreteBlock, ...) -> R - where F: Fn; + where F: Fn; } macro_rules! block_args_impl( @@ -47,11 +47,11 @@ macro_rules! block_args_impl( fn invoke_for_concrete_block() -> unsafe extern fn(*mut ConcreteBlock, ...) -> R - where X: Fn { + where X: Fn { unsafe extern fn $f( block_ptr: *mut ConcreteBlock $(, $a: $t)*) -> R - where X: Fn { + where X: Fn { let block = &*block_ptr; (block.closure)($($a),*) } @@ -111,7 +111,8 @@ pub struct ConcreteBlock where A: BlockArguments { closure: F, } -impl ConcreteBlock where A: BlockArguments, F: Fn { +impl ConcreteBlock + where A: BlockArguments, F: Fn { /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. @@ -147,14 +148,14 @@ impl ConcreteBlock where A: BlockArguments, F: Fn { } impl Clone for ConcreteBlock - where A: BlockArguments, F: Fn + Clone { + where A: BlockArguments, F: Fn + Clone { fn clone(&self) -> Self { ConcreteBlock::new(self.closure.clone()) } } impl Deref for ConcreteBlock - where A: BlockArguments, F: Fn { + where A: BlockArguments, F: Fn { type Target = Block; fn deref(&self) -> &Block { @@ -163,7 +164,7 @@ impl Deref for ConcreteBlock } impl DerefMut for ConcreteBlock - where A: BlockArguments, F: Fn { + where A: BlockArguments, F: Fn { fn deref_mut(&mut self) -> &mut Block { &mut self.base } From a159a1b7a1e856b518d2a0e43e8a42b4b582ef36 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 31 Jan 2015 23:30:50 -0800 Subject: [PATCH 052/125] Take advantage of autoderef where possible. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c21167df1..199c0048a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,14 +247,14 @@ mod tests { #[test] fn test_create_block() { let mut block = ConcreteBlock::new(|&:| 13); - let result = invoke_int_block(&mut *block); + let result = invoke_int_block(&mut block); assert!(result == 13); } #[test] fn test_create_block_args() { let mut block = ConcreteBlock::new(|&: a: i32| a + 5); - let result = invoke_add_block(&mut *block, 6); + let result = invoke_add_block(&mut block, 6); assert!(result == 11); } @@ -263,9 +263,9 @@ mod tests { let s = String::from_str("Hello!"); let expected_len = s.len() as i32; let mut block = ConcreteBlock::new(move |&:| s.len() as i32); - assert!(invoke_int_block(&mut *block) == expected_len); + assert!(invoke_int_block(&mut block) == expected_len); let mut copied = block.copy(); - assert!(invoke_int_block(&mut *copied) == expected_len); + assert!(invoke_int_block(&mut copied) == expected_len); } } From a17ef734da3f18ae7e20ad74a819ba58d9901baa Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 Feb 2015 02:21:59 -0800 Subject: [PATCH 053/125] Replaced use of unstable from_str. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 199c0048a..1d0c0d317 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -260,7 +260,7 @@ mod tests { #[test] fn test_concrete_block_copy() { - let s = String::from_str("Hello!"); + let s = "Hello!".to_string(); let expected_len = s.len() as i32; let mut block = ConcreteBlock::new(move |&:| s.len() as i32); assert!(invoke_int_block(&mut block) == expected_len); From 847aed1d8679d1ebf21cc45d9bc94f6a0a9b2078 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 Feb 2015 13:25:00 -0800 Subject: [PATCH 054/125] Added IntoConcreteBlock trait to remove unboxed_closures feature. --- src/lib.rs | 131 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 51 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1d0c0d317..3eda795ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,19 +21,10 @@ extern { pub trait BlockArguments { /// Calls the given `Block` with self as the arguments. fn call_block(self, block: &mut Block) -> R; - - /// Returns an invoke function for a `ConcreteBlock` that takes this type - /// of arguments. - fn invoke_for_concrete_block() -> - unsafe extern fn(*mut ConcreteBlock, ...) -> R - where F: Fn; } -macro_rules! block_args_impl( - ($f:ident) => ( - block_args_impl!($f,); - ); - ($f:ident, $($a:ident : $t:ident),*) => ( +macro_rules! block_args_impl { + ($($a:ident : $t:ident),*) => ( impl<$($t),*> BlockArguments for ($($t,)*) { fn call_block(self, block: &mut Block) -> R { let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { @@ -44,39 +35,23 @@ macro_rules! block_args_impl( invoke(block $(, $a)*) } } - - fn invoke_for_concrete_block() -> - unsafe extern fn(*mut ConcreteBlock, ...) -> R - where X: Fn { - unsafe extern fn $f( - block_ptr: *mut ConcreteBlock - $(, $a: $t)*) -> R - where X: Fn { - let block = &*block_ptr; - (block.closure)($($a),*) - } - - unsafe { - mem::transmute($f::) - } - } } ); -); - -block_args_impl!(concrete_block_invoke_args0); -block_args_impl!(concrete_block_invoke_args1, a: A); -block_args_impl!(concrete_block_invoke_args2, a: A, b: B); -block_args_impl!(concrete_block_invoke_args3, a: A, b: B, c: C); -block_args_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D); -block_args_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E); -block_args_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F); -block_args_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G); -block_args_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); -block_args_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); -block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); -block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); -block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); +} + +block_args_impl!(); +block_args_impl!(a: A); +block_args_impl!(a: A, b: B); +block_args_impl!(a: A, b: B, c: C); +block_args_impl!(a: A, b: B, c: C, d: D); +block_args_impl!(a: A, b: B, c: C, d: D, e: E); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); +block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); /// An Objective-C block that takes arguments of `A` when called and /// returns a value of `R`. @@ -102,6 +77,49 @@ impl EncodePtr for Block { fn ptr_code() -> &'static str { "@?" } } +pub trait IntoConcreteBlock where A: BlockArguments { + fn into_concrete_block(self) -> ConcreteBlock; +} + +macro_rules! concrete_block_impl { + ($f:ident) => ( + concrete_block_impl!($f,); + ); + ($f:ident, $($a:ident : $t:ident),*) => ( + impl<$($t,)* R, X> IntoConcreteBlock<($($t,)*), R> for X + where X: Fn($($t,)*) -> R { + fn into_concrete_block(self) -> ConcreteBlock<($($t,)*), R, X> { + unsafe extern fn $f<$($t,)* R, X>( + block_ptr: *mut ConcreteBlock<($($t,)*), R, X> + $(, $a: $t)*) -> R + where X: Fn($($t,)*) -> R { + let block = &*block_ptr; + (block.closure)($($a),*) + } + + unsafe { + ConcreteBlock::with_invoke( + mem::transmute($f::<$($t,)* R, X>), self) + } + } + } + ); +} + +concrete_block_impl!(concrete_block_invoke_args0); +concrete_block_impl!(concrete_block_invoke_args1, a: A); +concrete_block_impl!(concrete_block_invoke_args2, a: A, b: B); +concrete_block_impl!(concrete_block_invoke_args3, a: A, b: B, c: C); +concrete_block_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D); +concrete_block_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E); +concrete_block_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F); +concrete_block_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G); +concrete_block_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); +concrete_block_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); +concrete_block_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); +concrete_block_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); +concrete_block_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); + /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] @@ -112,22 +130,30 @@ pub struct ConcreteBlock where A: BlockArguments { } impl ConcreteBlock - where A: BlockArguments, F: Fn { + where A: BlockArguments, F: IntoConcreteBlock { /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. pub fn new(closure: F) -> Self { - let extern_invoke = - BlockArguments::invoke_for_concrete_block::(); + closure.into_concrete_block() + } +} + +impl ConcreteBlock where A: BlockArguments { + /// Constructs a `ConcreteBlock` with the given invoke function and closure. + /// Unsafe because the caller must ensure the invoke function takes the + /// correct arguments. + unsafe fn with_invoke(invoke: unsafe extern fn(*mut Self, ...) -> R, + closure: F) -> Self { ConcreteBlock { base: Block { isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE flags: 1 << 25, _reserved: 0, - invoke: unsafe { mem::transmute(extern_invoke) }, + invoke: mem::transmute(invoke), }, - descriptor: Box::new(BlockDescriptor::::new()), + descriptor: Box::new(BlockDescriptor::new()), closure: closure, } } @@ -148,14 +174,17 @@ impl ConcreteBlock } impl Clone for ConcreteBlock - where A: BlockArguments, F: Fn + Clone { + where A: BlockArguments, F: Clone { fn clone(&self) -> Self { - ConcreteBlock::new(self.closure.clone()) + unsafe { + ConcreteBlock::with_invoke(mem::transmute(self.invoke), + self.closure.clone()) + } } } impl Deref for ConcreteBlock - where A: BlockArguments, F: Fn { + where A: BlockArguments { type Target = Block; fn deref(&self) -> &Block { @@ -164,7 +193,7 @@ impl Deref for ConcreteBlock } impl DerefMut for ConcreteBlock - where A: BlockArguments, F: Fn { + where A: BlockArguments { fn deref_mut(&mut self) -> &mut Block { &mut self.base } From 25345a434de81fb1090729efd11df06d42acfeee Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 Feb 2015 14:17:38 -0800 Subject: [PATCH 055/125] Improve block module documentation. --- src/lib.rs | 47 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3eda795ae..b83956015 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,46 @@ -//! A Rust interface for Objective-C blocks. -//! -//! For more information on the specifics of the block implementation, see -//! Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html +/*! +A Rust interface for Objective-C blocks. + +For more information on the specifics of the block implementation, see +Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html + +# Invoking blocks + +The `Block` struct is used for invoking blocks from Objective-C. For example, +consider this Objective-C function: + +``` objc +int32_t sum(int32_t (^block)(int32_t, int32_t)) { + return block(5, 8); +} +``` + +We could write it in Rust as the following: + +``` +fn sum(block: &mut Block<(i32, i32), i32>) { + block.call((5, 8)) +} +``` + +Note the extra parentheses in the `call` method, since the arguments must be +passed as a tuple. + +# Creating blocks + +Creating a block to pass to Objective-C can be done with the `ConcreteBlock` +struct. For example, to create a block that adds two `i32`s, we could write: + +``` +let block = ConcreteBlock::new(|a: i32, b: i32| a + b); +let block = block.copy(); +``` + +It is important to copy your block to the heap (with the `copy` method) before +passing it to Objective-C; this is because our `ConcreteBlock` is only meant +to be copied once, and we can enforce this in Rust, but if Objective-C code +were to copy it twice we could have a double free. +*/ use std::mem; use std::ops::{Deref, DerefMut}; From 7fc4d69a548be0dc8e530169d9463127e6c96cbd Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 Feb 2015 14:25:45 -0800 Subject: [PATCH 056/125] Actually call the block in the doc example. --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index b83956015..635982ee8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,8 @@ struct. For example, to create a block that adds two `i32`s, we could write: ``` let block = ConcreteBlock::new(|a: i32, b: i32| a + b); -let block = block.copy(); +let mut block = block.copy(); +assert!(block.call((5, 8)) == 13); ``` It is important to copy your block to the heap (with the `copy` method) before From 0622f6d7b02debef5fcb9a32f571aec21d899111 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 Feb 2015 14:49:39 -0800 Subject: [PATCH 057/125] Removed unnecessary closure annotations. --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 635982ee8..cf7ccf4c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -315,14 +315,14 @@ mod tests { #[test] fn test_create_block() { - let mut block = ConcreteBlock::new(|&:| 13); + let mut block = ConcreteBlock::new(|| 13); let result = invoke_int_block(&mut block); assert!(result == 13); } #[test] fn test_create_block_args() { - let mut block = ConcreteBlock::new(|&: a: i32| a + 5); + let mut block = ConcreteBlock::new(|a: i32| a + 5); let result = invoke_add_block(&mut block, 6); assert!(result == 11); } @@ -331,7 +331,7 @@ mod tests { fn test_concrete_block_copy() { let s = "Hello!".to_string(); let expected_len = s.len() as i32; - let mut block = ConcreteBlock::new(move |&:| s.len() as i32); + let mut block = ConcreteBlock::new(move || s.len() as i32); assert!(invoke_int_block(&mut block) == expected_len); let mut copied = block.copy(); From f4842a2b61f0017d321845bac70ec0b8edac1306 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 Feb 2015 15:05:20 -0800 Subject: [PATCH 058/125] Enabled doctests for core. --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index cf7ccf4c8..fa38aec15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,9 @@ int32_t sum(int32_t (^block)(int32_t, int32_t)) { We could write it in Rust as the following: ``` -fn sum(block: &mut Block<(i32, i32), i32>) { +use objc::block::Block; + +fn sum(block: &mut Block<(i32, i32), i32>) -> i32 { block.call((5, 8)) } ``` @@ -32,6 +34,8 @@ Creating a block to pass to Objective-C can be done with the `ConcreteBlock` struct. For example, to create a block that adds two `i32`s, we could write: ``` +use objc::block::ConcreteBlock; + let block = ConcreteBlock::new(|a: i32, b: i32| a + b); let mut block = block.copy(); assert!(block.call((5, 8)) == 13); From d621f0f992c45bffcc5c6689edb7dc9263d03a9d Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 10 Feb 2015 08:35:01 -0800 Subject: [PATCH 059/125] Removed some trait bounds on blocks. --- src/lib.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fa38aec15..725b0d724 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: /// An Objective-C block that takes arguments of `A` when called and /// returns a value of `R`. #[repr(C)] -pub struct Block where A: BlockArguments { +pub struct Block { isa: *const Class, flags: c_int, _reserved: c_int, @@ -115,7 +115,7 @@ impl Block where A: BlockArguments { } } -unsafe impl Message for Block where A: BlockArguments { } +unsafe impl Message for Block { } impl EncodePtr for Block { fn ptr_code() -> &'static str { "@?" } @@ -167,7 +167,7 @@ concrete_block_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. #[repr(C)] -pub struct ConcreteBlock where A: BlockArguments { +pub struct ConcreteBlock { base: Block, descriptor: Box>>, closure: F, @@ -183,7 +183,7 @@ impl ConcreteBlock } } -impl ConcreteBlock where A: BlockArguments { +impl ConcreteBlock { /// Constructs a `ConcreteBlock` with the given invoke function and closure. /// Unsafe because the caller must ensure the invoke function takes the /// correct arguments. @@ -217,8 +217,7 @@ impl ConcreteBlock where A: BlockArguments { } } -impl Clone for ConcreteBlock - where A: BlockArguments, F: Clone { +impl Clone for ConcreteBlock where F: Clone { fn clone(&self) -> Self { unsafe { ConcreteBlock::with_invoke(mem::transmute(self.invoke), @@ -227,8 +226,7 @@ impl Clone for ConcreteBlock } } -impl Deref for ConcreteBlock - where A: BlockArguments { +impl Deref for ConcreteBlock { type Target = Block; fn deref(&self) -> &Block { @@ -236,8 +234,7 @@ impl Deref for ConcreteBlock } } -impl DerefMut for ConcreteBlock - where A: BlockArguments { +impl DerefMut for ConcreteBlock { fn deref_mut(&mut self) -> &mut Block { &mut self.base } From d17a48bec24674ff4a4bf6d5bc7bfceca1274b65 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 10 Feb 2015 11:24:59 -0800 Subject: [PATCH 060/125] Stop allowing improper_ctypes. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 725b0d724..086519739 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,6 @@ use libc::{c_int, c_ulong}; use runtime::{Class, Object}; use {EncodePtr, Id, Message}; -#[allow(improper_ctypes)] #[link(name = "Foundation", kind = "framework")] extern { static _NSConcreteStackBlock: Class; From a7a54f370d7525cc11e0b08b3627bf9d59e6c454 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 10 Feb 2015 11:26:54 -0800 Subject: [PATCH 061/125] Missing copy implementations doesn't warn anymore. --- test_utils/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test_utils/lib.rs b/test_utils/lib.rs index c38677e59..bd595edf1 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -5,12 +5,10 @@ extern { } /// A block that takes no arguments and returns an integer: `int32_t (^)()`. -#[allow(missing_copy_implementations)] pub enum IntBlock { } /// A block that takes one integer argument, adds to it, and returns the sum: /// `int32_t (^)(int32_t)`. -#[allow(missing_copy_implementations)] pub enum AddBlock { } #[link(name="block_utils", kind="static")] From 6a8656adea98a17312ef222f975326cab08094e3 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 11 Feb 2015 00:27:01 -0600 Subject: [PATCH 062/125] Added failing Block test. --- src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 086519739..87c27639b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -337,4 +337,16 @@ mod tests { let mut copied = block.copy(); assert!(invoke_int_block(&mut copied) == expected_len); } + + #[test] + fn test_concrete_block_stack_copy() { + fn make_block() -> Id> { + let x = 7; + let block = ConcreteBlock::new(|| x); + block.copy() + } + + let mut block = make_block(); + assert!(invoke_int_block(&mut block) == 7); + } } From 99d285bfc7c358f709add7e94bed684de4863ee4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 11 Feb 2015 00:32:38 -0600 Subject: [PATCH 063/125] Added a static bound for ConcreteBlock's copy. --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 87c27639b..31b2f526e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -200,7 +200,9 @@ impl ConcreteBlock { closure: closure, } } +} +impl ConcreteBlock where F: 'static { /// Copy self onto the heap. pub fn copy(self) -> Id> { unsafe { @@ -342,7 +344,7 @@ mod tests { fn test_concrete_block_stack_copy() { fn make_block() -> Id> { let x = 7; - let block = ConcreteBlock::new(|| x); + let block = ConcreteBlock::new(move || x); block.copy() } From 7c28aff6c731cfe3cbc9c20e88302c8282391c6a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 14 Feb 2015 15:20:19 -0600 Subject: [PATCH 064/125] Created a test_utils module. --- src/lib.rs | 44 ++++++++------------------------------------ 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 31b2f526e..838a03350 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -271,61 +271,33 @@ impl BlockDescriptor { #[cfg(test)] mod tests { + use test_utils; use Id; - use objc_test_utils; use super::{Block, ConcreteBlock}; - fn get_int_block_with(i: i32) -> Id> { - unsafe { - let ptr = objc_test_utils::get_int_block_with(i); - Id::from_retained_ptr(ptr as *mut _) - } - } - - fn get_add_block_with(i: i32) -> Id> { - unsafe { - let ptr = objc_test_utils::get_add_block_with(i); - Id::from_retained_ptr(ptr as *mut _) - } - } - - fn invoke_int_block(block: &mut Block<(), i32>) -> i32 { - let ptr = block as *mut _; - unsafe { - objc_test_utils::invoke_int_block(ptr as *mut _) - } - } - - fn invoke_add_block(block: &mut Block<(i32,), i32>, a: i32) -> i32 { - let ptr = block as *mut _; - unsafe { - objc_test_utils::invoke_add_block(ptr as *mut _, a) - } - } - #[test] fn test_call_block() { - let mut block = get_int_block_with(13); + let mut block = test_utils::get_int_block_with(13); assert!(block.call(()) == 13); } #[test] fn test_call_block_args() { - let mut block = get_add_block_with(13); + let mut block = test_utils::get_add_block_with(13); assert!(block.call((2,)) == 15); } #[test] fn test_create_block() { let mut block = ConcreteBlock::new(|| 13); - let result = invoke_int_block(&mut block); + let result = test_utils::invoke_int_block(&mut block); assert!(result == 13); } #[test] fn test_create_block_args() { let mut block = ConcreteBlock::new(|a: i32| a + 5); - let result = invoke_add_block(&mut block, 6); + let result = test_utils::invoke_add_block(&mut block, 6); assert!(result == 11); } @@ -334,10 +306,10 @@ mod tests { let s = "Hello!".to_string(); let expected_len = s.len() as i32; let mut block = ConcreteBlock::new(move || s.len() as i32); - assert!(invoke_int_block(&mut block) == expected_len); + assert!(test_utils::invoke_int_block(&mut block) == expected_len); let mut copied = block.copy(); - assert!(invoke_int_block(&mut copied) == expected_len); + assert!(test_utils::invoke_int_block(&mut copied) == expected_len); } #[test] @@ -349,6 +321,6 @@ mod tests { } let mut block = make_block(); - assert!(invoke_int_block(&mut block) == 7); + assert!(test_utils::invoke_int_block(&mut block) == 7); } } From 59d8e4617f5867d73ea44fe35d18b30df9823363 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 14 Feb 2015 16:00:36 -0600 Subject: [PATCH 065/125] Make the return type for IntoConcreteBlock an associated type. --- src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 838a03350..a1c58507d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,8 +120,10 @@ impl EncodePtr for Block { fn ptr_code() -> &'static str { "@?" } } -pub trait IntoConcreteBlock where A: BlockArguments { - fn into_concrete_block(self) -> ConcreteBlock; +pub trait IntoConcreteBlock where A: BlockArguments { + type Ret; + + fn into_concrete_block(self) -> ConcreteBlock; } macro_rules! concrete_block_impl { @@ -129,8 +131,10 @@ macro_rules! concrete_block_impl { concrete_block_impl!($f,); ); ($f:ident, $($a:ident : $t:ident),*) => ( - impl<$($t,)* R, X> IntoConcreteBlock<($($t,)*), R> for X + impl<$($t,)* R, X> IntoConcreteBlock<($($t,)*)> for X where X: Fn($($t,)*) -> R { + type Ret = R; + fn into_concrete_block(self) -> ConcreteBlock<($($t,)*), R, X> { unsafe extern fn $f<$($t,)* R, X>( block_ptr: *mut ConcreteBlock<($($t,)*), R, X> @@ -173,7 +177,7 @@ pub struct ConcreteBlock { } impl ConcreteBlock - where A: BlockArguments, F: IntoConcreteBlock { + where A: BlockArguments, F: IntoConcreteBlock { /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. From 2f8c87f64c53d30d47800fd175f999b0c63767e0 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 22 Feb 2015 11:50:36 -0800 Subject: [PATCH 066/125] Improved declare and block documentation. --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a1c58507d..890a837f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,9 +120,12 @@ impl EncodePtr for Block { fn ptr_code() -> &'static str { "@?" } } +/// Types that may be converted into a `ConcreteBlock`. pub trait IntoConcreteBlock where A: BlockArguments { + /// The return type of the resulting `ConcreteBlock`. type Ret; + /// Consumes self to create a `ConcreteBlock`. fn into_concrete_block(self) -> ConcreteBlock; } From 580ff1d6779fac163dda1a7ce532682fec30d980 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 22 Feb 2015 13:22:52 -0800 Subject: [PATCH 067/125] Don't ignore examples in doc tests. --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 890a837f8..9988a5fb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,7 @@ int32_t sum(int32_t (^block)(int32_t, int32_t)) { We could write it in Rust as the following: ``` -use objc::block::Block; - +# use objc::block::Block; fn sum(block: &mut Block<(i32, i32), i32>) -> i32 { block.call((5, 8)) } @@ -34,8 +33,7 @@ Creating a block to pass to Objective-C can be done with the `ConcreteBlock` struct. For example, to create a block that adds two `i32`s, we could write: ``` -use objc::block::ConcreteBlock; - +# use objc::block::ConcreteBlock; let block = ConcreteBlock::new(|a: i32, b: i32| a + b); let mut block = block.copy(); assert!(block.call((5, 8)) == 13); From 2ac205a00059092f8f00151e7172f9a86269eff3 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 24 Feb 2015 00:23:09 -0800 Subject: [PATCH 068/125] Updated test_utils to gcc 0.3. --- test_utils/Cargo.toml | 2 +- test_utils/build.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index bd4730a8d..de1d73777 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -15,4 +15,4 @@ name = "objc_test_utils" path = "lib.rs" [build-dependencies] -gcc = "0.1" +gcc = "0.3" diff --git a/test_utils/build.rs b/test_utils/build.rs index 57b060eb5..d9120d934 100644 --- a/test_utils/build.rs +++ b/test_utils/build.rs @@ -1,8 +1,5 @@ extern crate gcc; -use std::default::Default; - fn main() { - let config = Default::default(); - gcc::compile_library("libblock_utils.a", &config, &["block_utils.m"]); + gcc::compile_library("libblock_utils.a", &["block_utils.m"]); } From ee154d7a543f8b8c4beca0ffd38ff76c011180d9 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 24 Feb 2015 00:24:20 -0800 Subject: [PATCH 069/125] Bump test_utils crate to 0.0.2. --- test_utils/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index de1d73777..644e8cf66 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "objc_test_utils" -version = "0.0.1" +version = "0.0.2" authors = ["Steven Sheldon"] description = "Utilities for testing Objective-C interop." From 2d4266df9e2fd4dc0a4a58a504111a12a40dd227 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Tue, 3 Mar 2015 00:49:14 -0800 Subject: [PATCH 070/125] Added a BlockBase struct so Block is 0-sized. Fixes #8. --- src/lib.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9988a5fb2..0b81e4977 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ to be copied once, and we can enforce this in Rust, but if Objective-C code were to copy it twice we could have a double free. */ +use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr; @@ -69,7 +70,8 @@ macro_rules! block_args_impl { impl<$($t),*> BlockArguments for ($($t,)*) { fn call_block(self, block: &mut Block) -> R { let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { - mem::transmute(block.invoke) + let base = &*(block as *mut _ as *mut BlockBase); + mem::transmute(base.invoke) }; let ($($a,)*) = self; unsafe { @@ -94,16 +96,21 @@ block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); -/// An Objective-C block that takes arguments of `A` when called and -/// returns a value of `R`. #[repr(C)] -pub struct Block { +struct BlockBase { isa: *const Class, flags: c_int, _reserved: c_int, invoke: unsafe extern fn(*mut Block, ...) -> R, } +/// An Objective-C block that takes arguments of `A` when called and +/// returns a value of `R`. +#[repr(C)] +pub struct Block { + _base: PhantomData>, +} + // TODO: impl FnMut when it's possible impl Block where A: BlockArguments { /// Call self with the given arguments. @@ -172,7 +179,7 @@ concrete_block_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, /// constructed on the stack. #[repr(C)] pub struct ConcreteBlock { - base: Block, + base: BlockBase, descriptor: Box>>, closure: F, } @@ -194,7 +201,7 @@ impl ConcreteBlock { unsafe fn with_invoke(invoke: unsafe extern fn(*mut Self, ...) -> R, closure: F) -> Self { ConcreteBlock { - base: Block { + base: BlockBase { isa: &_NSConcreteStackBlock, // 1 << 25 = BLOCK_HAS_COPY_DISPOSE flags: 1 << 25, @@ -212,7 +219,7 @@ impl ConcreteBlock where F: 'static { pub fn copy(self) -> Id> { unsafe { // The copy method is declared as returning an object pointer. - let block: *mut Object = msg_send![&self.base, copy]; + let block: *mut Object = msg_send![&*self, copy]; let block = block as *mut Block; // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block @@ -226,7 +233,7 @@ impl ConcreteBlock where F: 'static { impl Clone for ConcreteBlock where F: Clone { fn clone(&self) -> Self { unsafe { - ConcreteBlock::with_invoke(mem::transmute(self.invoke), + ConcreteBlock::with_invoke(mem::transmute(self.base.invoke), self.closure.clone()) } } @@ -236,13 +243,13 @@ impl Deref for ConcreteBlock { type Target = Block; fn deref(&self) -> &Block { - &self.base + unsafe { &*(&self.base as *const _ as *const Block) } } } impl DerefMut for ConcreteBlock { fn deref_mut(&mut self) -> &mut Block { - &mut self.base + unsafe { &mut *(&mut self.base as *mut _ as *mut Block) } } } From 9ae50597af7c0ac1f9e6999450f182825fd56e34 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 18 Feb 2015 01:03:52 -0800 Subject: [PATCH 071/125] Replaced the EncodePtr trait with a macro. --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0b81e4977..d2d50e9f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ use std::ptr; use libc::{c_int, c_ulong}; use runtime::{Class, Object}; -use {EncodePtr, Id, Message}; +use {Id, Message}; #[link(name = "Foundation", kind = "framework")] extern { @@ -121,9 +121,7 @@ impl Block where A: BlockArguments { unsafe impl Message for Block { } -impl EncodePtr for Block { - fn ptr_code() -> &'static str { "@?" } -} +encode_message_impl!("@?", Block, A, R); /// Types that may be converted into a `ConcreteBlock`. pub trait IntoConcreteBlock where A: BlockArguments { From 313c0a51db04a7d6786214612b1d12f7d0605812 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 8 Mar 2015 01:42:38 -0800 Subject: [PATCH 072/125] Moved encode_message_impls! macro into the encode module. --- src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2d50e9f6..c29f3d30c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ use std::ptr; use libc::{c_int, c_ulong}; use runtime::{Class, Object}; -use {Id, Message}; +use Id; #[link(name = "Foundation", kind = "framework")] extern { @@ -119,10 +119,6 @@ impl Block where A: BlockArguments { } } -unsafe impl Message for Block { } - -encode_message_impl!("@?", Block, A, R); - /// Types that may be converted into a `ConcreteBlock`. pub trait IntoConcreteBlock where A: BlockArguments { /// The return type of the resulting `ConcreteBlock`. From 9949d592dead511dcccf37525f3ecebc6d2ffbee Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 22:30:41 -0700 Subject: [PATCH 073/125] Added config for Cargo and gitignore. --- .gitignore | 2 ++ Cargo.toml | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a9d37c560 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..e6d7c528f --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "block" +version = "0.0.0" +authors = ["Steven Sheldon"] From e20aba18d339ea67cfdb3e4cd0a6da581bf10045 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 22:31:57 -0700 Subject: [PATCH 074/125] Update block to compile as its own crate. --- Cargo.toml | 4 ++++ src/lib.rs | 10 ++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e6d7c528f..da40c3797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,7 @@ name = "block" version = "0.0.0" authors = ["Steven Sheldon"] + +[dependencies] +libc = "0.1" +objc = "0.1" diff --git a/src/lib.rs b/src/lib.rs index c29f3d30c..0d8def0f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,14 +45,18 @@ to be copied once, and we can enforce this in Rust, but if Objective-C code were to copy it twice we could have a double free. */ +extern crate libc; +#[macro_use] +extern crate objc; + use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong}; -use runtime::{Class, Object}; -use Id; +use objc::runtime::{Class, Object}; +use objc::{Message, Id}; #[link(name = "Foundation", kind = "framework")] extern { @@ -119,6 +123,8 @@ impl Block where A: BlockArguments { } } +unsafe impl Message for Block { } + /// Types that may be converted into a `ConcreteBlock`. pub trait IntoConcreteBlock where A: BlockArguments { /// The return type of the resulting `ConcreteBlock`. From 6a82e83c28922a06b55a972b61abf3ef6e634a4d Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 22:38:33 -0700 Subject: [PATCH 075/125] Update tests for new crate. --- Cargo.toml | 4 ++++ src/lib.rs | 53 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da40c3797..01bedbcb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,7 @@ authors = ["Steven Sheldon"] [dependencies] libc = "0.1" objc = "0.1" + +[dev-dependencies.objc_test_utils] +version = "0.0" +path = "test_utils" diff --git a/src/lib.rs b/src/lib.rs index 0d8def0f1..b630739e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ int32_t sum(int32_t (^block)(int32_t, int32_t)) { We could write it in Rust as the following: ``` -# use objc::block::Block; +# use block::Block; fn sum(block: &mut Block<(i32, i32), i32>) -> i32 { block.call((5, 8)) } @@ -33,7 +33,7 @@ Creating a block to pass to Objective-C can be done with the `ConcreteBlock` struct. For example, to create a block that adds two `i32`s, we could write: ``` -# use objc::block::ConcreteBlock; +# use block::ConcreteBlock; let block = ConcreteBlock::new(|a: i32, b: i32| a + b); let mut block = block.copy(); assert!(block.call((5, 8)) == 13); @@ -49,6 +49,9 @@ extern crate libc; #[macro_use] extern crate objc; +#[cfg(test)] +extern crate objc_test_utils; + use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; @@ -283,33 +286,61 @@ impl BlockDescriptor { #[cfg(test)] mod tests { - use test_utils; - use Id; + use objc::Id; + use objc_test_utils; use super::{Block, ConcreteBlock}; + fn get_int_block_with(i: i32) -> Id> { + unsafe { + let ptr = objc_test_utils::get_int_block_with(i); + Id::from_retained_ptr(ptr as *mut _) + } + } + + fn get_add_block_with(i: i32) -> Id> { + unsafe { + let ptr = objc_test_utils::get_add_block_with(i); + Id::from_retained_ptr(ptr as *mut _) + } + } + + fn invoke_int_block(block: &mut Block<(), i32>) -> i32 { + let ptr = block as *mut _; + unsafe { + objc_test_utils::invoke_int_block(ptr as *mut _) + } + } + + fn invoke_add_block(block: &mut Block<(i32,), i32>, a: i32) -> i32 { + let ptr = block as *mut _; + unsafe { + objc_test_utils::invoke_add_block(ptr as *mut _, a) + } + } + #[test] fn test_call_block() { - let mut block = test_utils::get_int_block_with(13); + let mut block = get_int_block_with(13); assert!(block.call(()) == 13); } #[test] fn test_call_block_args() { - let mut block = test_utils::get_add_block_with(13); + let mut block = get_add_block_with(13); assert!(block.call((2,)) == 15); } #[test] fn test_create_block() { let mut block = ConcreteBlock::new(|| 13); - let result = test_utils::invoke_int_block(&mut block); + let result = invoke_int_block(&mut block); assert!(result == 13); } #[test] fn test_create_block_args() { let mut block = ConcreteBlock::new(|a: i32| a + 5); - let result = test_utils::invoke_add_block(&mut block, 6); + let result = invoke_add_block(&mut block, 6); assert!(result == 11); } @@ -318,10 +349,10 @@ mod tests { let s = "Hello!".to_string(); let expected_len = s.len() as i32; let mut block = ConcreteBlock::new(move || s.len() as i32); - assert!(test_utils::invoke_int_block(&mut block) == expected_len); + assert!(invoke_int_block(&mut block) == expected_len); let mut copied = block.copy(); - assert!(test_utils::invoke_int_block(&mut copied) == expected_len); + assert!(invoke_int_block(&mut copied) == expected_len); } #[test] @@ -333,6 +364,6 @@ mod tests { } let mut block = make_block(); - assert!(test_utils::invoke_int_block(&mut block) == 7); + assert!(invoke_int_block(&mut block) == 7); } } From 7831e107edced863d5df0eceeb7ffe834430346a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 22:50:11 -0700 Subject: [PATCH 076/125] Added README. --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..3ec79ed39 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +Rust interface for Apple's C language extension of blocks. + +For more information on the specifics of the block implementation, see +Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html + +## Invoking blocks + +The `Block` struct is used for invoking blocks from Objective-C. For example, +consider this Objective-C function: + +``` objc +int32_t sum(int32_t (^block)(int32_t, int32_t)) { + return block(5, 8); +} +``` + +We could write it in Rust as the following: + +``` rust +fn sum(block: &mut Block<(i32, i32), i32>) -> i32 { + block.call((5, 8)) +} +``` + +Note the extra parentheses in the `call` method, since the arguments must be +passed as a tuple. + +## Creating blocks + +Creating a block to pass to Objective-C can be done with the `ConcreteBlock` +struct. For example, to create a block that adds two `i32`s, we could write: + +``` rust +let block = ConcreteBlock::new(|a: i32, b: i32| a + b); +let mut block = block.copy(); +assert!(block.call((5, 8)) == 13); +``` + +It is important to copy your block to the heap (with the `copy` method) before +passing it to Objective-C; this is because our `ConcreteBlock` is only meant +to be copied once, and we can enforce this in Rust, but if Objective-C code +were to copy it twice we could have a double free. From fe901fe98e0f94cc8f01251299816f08976cbd2d Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 22:55:19 -0700 Subject: [PATCH 077/125] Added more metadata and bumped to version 0.0.1. --- Cargo.toml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 01bedbcb9..f6683e61d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,16 @@ [package] name = "block" -version = "0.0.0" +version = "0.0.1" authors = ["Steven Sheldon"] +description = "Rust interface for Apple's C language extension of blocks." +keywords = ["blocks", "osx", "ios", "objective-c"] +readme = "README.md" +repository = "http://github.com/SSheldon/rust-block" +license = "MIT" + +exclude = [".gitignore"] + [dependencies] libc = "0.1" objc = "0.1" From b41dc67312b723fd6cb1b6238b66d988a069be47 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 23:14:32 -0700 Subject: [PATCH 078/125] Don't link Foundation for objc_test_utils. --- test_utils/block_utils.m | 5 +++-- test_utils/lib.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test_utils/block_utils.m b/test_utils/block_utils.m index 66fff8f43..440dbb948 100644 --- a/test_utils/block_utils.m +++ b/test_utils/block_utils.m @@ -1,4 +1,5 @@ #include +#include typedef int32_t (^IntBlock)(); typedef int32_t (^AddBlock)(int32_t); @@ -8,7 +9,7 @@ IntBlock get_int_block() { } IntBlock get_int_block_with(int32_t i) { - return [^{ return i; } copy]; + return Block_copy(^{ return i; }); } AddBlock get_add_block() { @@ -16,7 +17,7 @@ AddBlock get_add_block() { } AddBlock get_add_block_with(int32_t i) { - return [^(int32_t a) { return a + i; } copy]; + return Block_copy(^(int32_t a) { return a + i; }); } int32_t invoke_int_block(IntBlock block) { diff --git a/test_utils/lib.rs b/test_utils/lib.rs index bd595edf1..815ab482e 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -1,7 +1,7 @@ #![crate_name = "objc_test_utils"] #![crate_type = "lib"] -#[link(name = "Foundation", kind = "framework")] +#[link(name = "System", kind = "dylib")] extern { } /// A block that takes no arguments and returns an integer: `int32_t (^)()`. From 9c5dee58d2a6724fdca3432822fc33ba98d887d4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 16 Apr 2015 23:54:55 -0700 Subject: [PATCH 079/125] Change extension on block_utils from .m to .c. --- test_utils/{block_utils.m => block_utils.c} | 0 test_utils/build.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename test_utils/{block_utils.m => block_utils.c} (100%) diff --git a/test_utils/block_utils.m b/test_utils/block_utils.c similarity index 100% rename from test_utils/block_utils.m rename to test_utils/block_utils.c diff --git a/test_utils/build.rs b/test_utils/build.rs index d9120d934..7c1455a1e 100644 --- a/test_utils/build.rs +++ b/test_utils/build.rs @@ -1,5 +1,5 @@ extern crate gcc; fn main() { - gcc::compile_library("libblock_utils.a", &["block_utils.m"]); + gcc::compile_library("libblock_utils.a", &["block_utils.c"]); } From 05004aaeb9b20e97de61deb2d73a767e035da2c1 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 17 Apr 2015 22:51:01 -0700 Subject: [PATCH 080/125] Remove objc dependency. --- Cargo.toml | 1 - src/lib.rs | 78 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6683e61d..2bc4d2375 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ exclude = [".gitignore"] [dependencies] libc = "0.1" -objc = "0.1" [dev-dependencies.objc_test_utils] version = "0.0" diff --git a/src/lib.rs b/src/lib.rs index b630739e1..397001e12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,8 +46,6 @@ were to copy it twice we could have a double free. */ extern crate libc; -#[macro_use] -extern crate objc; #[cfg(test)] extern crate objc_test_utils; @@ -56,14 +54,14 @@ use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr; -use libc::{c_int, c_ulong}; +use libc::{c_int, c_ulong, c_void}; -use objc::runtime::{Class, Object}; -use objc::{Message, Id}; - -#[link(name = "Foundation", kind = "framework")] +#[link(name = "System", kind = "dylib")] extern { - static _NSConcreteStackBlock: Class; + static _NSConcreteStackBlock: (); + + fn _Block_copy(block: *const c_void) -> *mut c_void; + fn _Block_release(block: *const c_void); } /// Types that may be used as the arguments to an Objective-C block. @@ -105,7 +103,7 @@ block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: #[repr(C)] struct BlockBase { - isa: *const Class, + isa: *const (), flags: c_int, _reserved: c_int, invoke: unsafe extern fn(*mut Block, ...) -> R, @@ -126,7 +124,42 @@ impl Block where A: BlockArguments { } } -unsafe impl Message for Block { } +pub struct IdBlock { + ptr: *mut Block, +} + +impl IdBlock { + pub unsafe fn new(ptr: *mut Block) -> Self { + IdBlock { ptr: ptr } + } + + pub unsafe fn copy(ptr: *mut Block) -> Self { + let ptr = _Block_copy(ptr as *const c_void) as *mut Block; + IdBlock { ptr: ptr } + } +} + +impl Deref for IdBlock { + type Target = Block; + + fn deref(&self) -> &Block { + unsafe { &*self.ptr } + } +} + +impl DerefMut for IdBlock { + fn deref_mut(&mut self) -> &mut Block { + unsafe { &mut *self.ptr } + } +} + +impl Drop for IdBlock { + fn drop(&mut self) { + unsafe { + _Block_release(self.ptr as *const c_void); + } + } +} /// Types that may be converted into a `ConcreteBlock`. pub trait IntoConcreteBlock where A: BlockArguments { @@ -219,16 +252,16 @@ impl ConcreteBlock { impl ConcreteBlock where F: 'static { /// Copy self onto the heap. - pub fn copy(self) -> Id> { + pub fn copy(self) -> IdBlock { unsafe { - // The copy method is declared as returning an object pointer. - let block: *mut Object = msg_send![&*self, copy]; - let block = block as *mut Block; + let mut block = self; + let ptr: *mut Block = &mut *block; + let copied = IdBlock::copy(ptr); // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. - mem::forget(self); - Id::from_retained_ptr(block) + mem::forget(block); + copied } } } @@ -286,21 +319,20 @@ impl BlockDescriptor { #[cfg(test)] mod tests { - use objc::Id; use objc_test_utils; - use super::{Block, ConcreteBlock}; + use super::{Block, ConcreteBlock, IdBlock}; - fn get_int_block_with(i: i32) -> Id> { + fn get_int_block_with(i: i32) -> IdBlock<(), i32> { unsafe { let ptr = objc_test_utils::get_int_block_with(i); - Id::from_retained_ptr(ptr as *mut _) + IdBlock::new(ptr as *mut _) } } - fn get_add_block_with(i: i32) -> Id> { + fn get_add_block_with(i: i32) -> IdBlock<(i32,), i32> { unsafe { let ptr = objc_test_utils::get_add_block_with(i); - Id::from_retained_ptr(ptr as *mut _) + IdBlock::new(ptr as *mut _) } } @@ -357,7 +389,7 @@ mod tests { #[test] fn test_concrete_block_stack_copy() { - fn make_block() -> Id> { + fn make_block() -> IdBlock<(), i32> { let x = 7; let block = ConcreteBlock::new(move || x); block.copy() From c93b6a13c7aa060365f4bcdc52d1d0ecd95b3cab Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 19 Apr 2015 20:50:10 -0700 Subject: [PATCH 081/125] Added documentation link to Cargo metadata. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 2bc4d2375..3513ca1b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ description = "Rust interface for Apple's C language extension of blocks." keywords = ["blocks", "osx", "ios", "objective-c"] readme = "README.md" repository = "http://github.com/SSheldon/rust-block" +documentation = "http://ssheldon.github.io/rust-objc/block/" license = "MIT" exclude = [".gitignore"] From 895e712a9467388b680f8f2b48d178d4e0851217 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 26 Apr 2015 17:17:45 -0700 Subject: [PATCH 082/125] Removed unnecessary links in test utils. --- test_utils/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test_utils/lib.rs b/test_utils/lib.rs index 815ab482e..3a1e98aa9 100644 --- a/test_utils/lib.rs +++ b/test_utils/lib.rs @@ -1,9 +1,6 @@ #![crate_name = "objc_test_utils"] #![crate_type = "lib"] -#[link(name = "System", kind = "dylib")] -extern { } - /// A block that takes no arguments and returns an integer: `int32_t (^)()`. pub enum IntBlock { } @@ -11,7 +8,6 @@ pub enum IntBlock { } /// `int32_t (^)(int32_t)`. pub enum AddBlock { } -#[link(name="block_utils", kind="static")] extern { /// Returns a pointer to a global `IntBlock` that returns 7. pub fn get_int_block() -> *mut IntBlock; From 7b0fbcdeb998d71f86acd16aa490f1963486132d Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 29 Apr 2015 22:46:39 -0700 Subject: [PATCH 083/125] Removed unnecessary intermediate variable. --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 397001e12..5b591579c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,8 +255,7 @@ impl ConcreteBlock where F: 'static { pub fn copy(self) -> IdBlock { unsafe { let mut block = self; - let ptr: *mut Block = &mut *block; - let copied = IdBlock::copy(ptr); + let copied = IdBlock::copy(&mut *block); // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. From 4426ca151033fe90e1d8c58232fae1c7ddd92ab7 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 19 Apr 2015 20:50:10 -0700 Subject: [PATCH 084/125] Added documentation link to Cargo metadata. (cherry picked from commit c93b6a13c7aa060365f4bcdc52d1d0ecd95b3cab) --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index f6683e61d..8c827daae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ description = "Rust interface for Apple's C language extension of blocks." keywords = ["blocks", "osx", "ios", "objective-c"] readme = "README.md" repository = "http://github.com/SSheldon/rust-block" +documentation = "http://ssheldon.github.io/rust-objc/block/" license = "MIT" exclude = [".gitignore"] From a5111e03ebc39d17f610fb0a25316ab4f342224e Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 2 May 2015 14:28:17 -0700 Subject: [PATCH 085/125] Replace objc's Id with the standalone objc_id crate. --- Cargo.toml | 1 + src/lib.rs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8c827daae..159113caf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ exclude = [".gitignore"] [dependencies] libc = "0.1" objc = "0.1" +objc_id = "0.0" [dev-dependencies.objc_test_utils] version = "0.0" diff --git a/src/lib.rs b/src/lib.rs index b630739e1..191cfa74d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,7 @@ were to copy it twice we could have a double free. extern crate libc; #[macro_use] extern crate objc; +extern crate objc_id; #[cfg(test)] extern crate objc_test_utils; @@ -58,8 +59,9 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong}; +use objc::Message; use objc::runtime::{Class, Object}; -use objc::{Message, Id}; +use objc_id::Id; #[link(name = "Foundation", kind = "framework")] extern { @@ -286,7 +288,7 @@ impl BlockDescriptor { #[cfg(test)] mod tests { - use objc::Id; + use objc_id::Id; use objc_test_utils; use super::{Block, ConcreteBlock}; From 0c8b7a99f856050ad4b00d17b3e5bef60350c0d8 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 2 May 2015 14:29:08 -0700 Subject: [PATCH 086/125] Bumped to version 0.0.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 159113caf..f20170086 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.0.1" +version = "0.0.2" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From 9c28f61ac3df8a47d748eb75b14dbd119310a34b Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 11:44:49 -0700 Subject: [PATCH 087/125] Made BlockArguments::call_block unsafe. --- src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5b591579c..abfd4d6ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,21 +67,19 @@ extern { /// Types that may be used as the arguments to an Objective-C block. pub trait BlockArguments { /// Calls the given `Block` with self as the arguments. - fn call_block(self, block: &mut Block) -> R; + unsafe fn call_block(self, block: *mut Block) -> R; } macro_rules! block_args_impl { ($($a:ident : $t:ident),*) => ( impl<$($t),*> BlockArguments for ($($t,)*) { - fn call_block(self, block: &mut Block) -> R { - let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = unsafe { - let base = &*(block as *mut _ as *mut BlockBase); - mem::transmute(base.invoke) + unsafe fn call_block(self, block: *mut Block) -> R { + let invoke: unsafe extern fn(*mut Block $(, $t)*) -> R = { + let base = block as *mut BlockBase; + mem::transmute((*base).invoke) }; let ($($a,)*) = self; - unsafe { - invoke(block $(, $a)*) - } + invoke(block $(, $a)*) } } ); @@ -120,7 +118,9 @@ pub struct Block { impl Block where A: BlockArguments { /// Call self with the given arguments. pub fn call(&mut self, args: A) -> R { - args.call_block(self) + unsafe { + args.call_block(self) + } } } From 8d6da4108f293f93fbf75b8668343cb4305f0f41 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 14:13:41 -0700 Subject: [PATCH 088/125] Calling a block is unsafe and doesn't require &mut. --- src/lib.rs | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index abfd4d6ee..a3b9c4010 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ We could write it in Rust as the following: ``` # use block::Block; -fn sum(block: &mut Block<(i32, i32), i32>) -> i32 { +unsafe fn sum(block: &Block<(i32, i32), i32>) -> i32 { block.call((5, 8)) } ``` @@ -35,8 +35,8 @@ struct. For example, to create a block that adds two `i32`s, we could write: ``` # use block::ConcreteBlock; let block = ConcreteBlock::new(|a: i32, b: i32| a + b); -let mut block = block.copy(); -assert!(block.call((5, 8)) == 13); +let block = block.copy(); +assert!(unsafe { block.call((5, 8)) } == 13); ``` It is important to copy your block to the heap (with the `copy` method) before @@ -117,10 +117,8 @@ pub struct Block { // TODO: impl FnMut when it's possible impl Block where A: BlockArguments { /// Call self with the given arguments. - pub fn call(&mut self, args: A) -> R { - unsafe { - args.call_block(self) - } + pub unsafe fn call(&self, args: A) -> R { + args.call_block(self as *const _ as *mut _) } } @@ -335,15 +333,15 @@ mod tests { } } - fn invoke_int_block(block: &mut Block<(), i32>) -> i32 { - let ptr = block as *mut _; + fn invoke_int_block(block: &Block<(), i32>) -> i32 { + let ptr = block as *const _; unsafe { objc_test_utils::invoke_int_block(ptr as *mut _) } } - fn invoke_add_block(block: &mut Block<(i32,), i32>, a: i32) -> i32 { - let ptr = block as *mut _; + fn invoke_add_block(block: &Block<(i32,), i32>, a: i32) -> i32 { + let ptr = block as *const _; unsafe { objc_test_utils::invoke_add_block(ptr as *mut _, a) } @@ -351,27 +349,31 @@ mod tests { #[test] fn test_call_block() { - let mut block = get_int_block_with(13); - assert!(block.call(()) == 13); + let block = get_int_block_with(13); + unsafe { + assert!(block.call(()) == 13); + } } #[test] fn test_call_block_args() { - let mut block = get_add_block_with(13); - assert!(block.call((2,)) == 15); + let block = get_add_block_with(13); + unsafe { + assert!(block.call((2,)) == 15); + } } #[test] fn test_create_block() { - let mut block = ConcreteBlock::new(|| 13); - let result = invoke_int_block(&mut block); + let block = ConcreteBlock::new(|| 13); + let result = invoke_int_block(&block); assert!(result == 13); } #[test] fn test_create_block_args() { - let mut block = ConcreteBlock::new(|a: i32| a + 5); - let result = invoke_add_block(&mut block, 6); + let block = ConcreteBlock::new(|a: i32| a + 5); + let result = invoke_add_block(&block, 6); assert!(result == 11); } @@ -379,11 +381,11 @@ mod tests { fn test_concrete_block_copy() { let s = "Hello!".to_string(); let expected_len = s.len() as i32; - let mut block = ConcreteBlock::new(move || s.len() as i32); - assert!(invoke_int_block(&mut block) == expected_len); + let block = ConcreteBlock::new(move || s.len() as i32); + assert!(invoke_int_block(&block) == expected_len); - let mut copied = block.copy(); - assert!(invoke_int_block(&mut copied) == expected_len); + let copied = block.copy(); + assert!(invoke_int_block(&copied) == expected_len); } #[test] @@ -394,7 +396,7 @@ mod tests { block.copy() } - let mut block = make_block(); - assert!(invoke_int_block(&mut block) == 7); + let block = make_block(); + assert!(invoke_int_block(&block) == 7); } } From c485b4001e1d8e9398029587dd5e1366a0c58983 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 14:15:24 -0700 Subject: [PATCH 089/125] Replaced IdBlock with RcBlock. --- src/lib.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3b9c4010..80aeec1d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,22 +122,30 @@ impl Block where A: BlockArguments { } } -pub struct IdBlock { +pub struct RcBlock { ptr: *mut Block, } -impl IdBlock { +impl RcBlock { pub unsafe fn new(ptr: *mut Block) -> Self { - IdBlock { ptr: ptr } + RcBlock { ptr: ptr } } pub unsafe fn copy(ptr: *mut Block) -> Self { let ptr = _Block_copy(ptr as *const c_void) as *mut Block; - IdBlock { ptr: ptr } + RcBlock { ptr: ptr } } } -impl Deref for IdBlock { +impl Clone for RcBlock { + fn clone(&self) -> RcBlock { + unsafe { + RcBlock::copy(self.ptr) + } + } +} + +impl Deref for RcBlock { type Target = Block; fn deref(&self) -> &Block { @@ -145,13 +153,7 @@ impl Deref for IdBlock { } } -impl DerefMut for IdBlock { - fn deref_mut(&mut self) -> &mut Block { - unsafe { &mut *self.ptr } - } -} - -impl Drop for IdBlock { +impl Drop for RcBlock { fn drop(&mut self) { unsafe { _Block_release(self.ptr as *const c_void); @@ -250,10 +252,10 @@ impl ConcreteBlock { impl ConcreteBlock where F: 'static { /// Copy self onto the heap. - pub fn copy(self) -> IdBlock { + pub fn copy(self) -> RcBlock { unsafe { let mut block = self; - let copied = IdBlock::copy(&mut *block); + let copied = RcBlock::copy(&mut *block); // At this point, our copy helper has been run so the block will // be moved to the heap and we can forget the original block // because the heap block will drop in our dispose helper. @@ -317,19 +319,19 @@ impl BlockDescriptor { #[cfg(test)] mod tests { use objc_test_utils; - use super::{Block, ConcreteBlock, IdBlock}; + use super::{Block, ConcreteBlock, RcBlock}; - fn get_int_block_with(i: i32) -> IdBlock<(), i32> { + fn get_int_block_with(i: i32) -> RcBlock<(), i32> { unsafe { let ptr = objc_test_utils::get_int_block_with(i); - IdBlock::new(ptr as *mut _) + RcBlock::new(ptr as *mut _) } } - fn get_add_block_with(i: i32) -> IdBlock<(i32,), i32> { + fn get_add_block_with(i: i32) -> RcBlock<(i32,), i32> { unsafe { let ptr = objc_test_utils::get_add_block_with(i); - IdBlock::new(ptr as *mut _) + RcBlock::new(ptr as *mut _) } } @@ -390,7 +392,7 @@ mod tests { #[test] fn test_concrete_block_stack_copy() { - fn make_block() -> IdBlock<(), i32> { + fn make_block() -> RcBlock<(), i32> { let x = 7; let block = ConcreteBlock::new(move || x); block.copy() From 00631d538e3735f8fdf3c8280f056e045f1deb6b Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 14:26:05 -0700 Subject: [PATCH 090/125] Updated some documentation. --- src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 80aeec1d4..6b8fad1fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,9 @@ extern { /// Types that may be used as the arguments to an Objective-C block. pub trait BlockArguments { /// Calls the given `Block` with self as the arguments. + /// + /// Unsafe because `block` must point to a valid `Block` and this invokes + /// foreign code whose safety the compiler cannot verify. unsafe fn call_block(self, block: *mut Block) -> R; } @@ -114,9 +117,13 @@ pub struct Block { _base: PhantomData>, } -// TODO: impl FnMut when it's possible impl Block where A: BlockArguments { /// Call self with the given arguments. + /// + /// Unsafe because this invokes foreign code that the caller must verify + /// doesn't violate any of Rust's safety rules. For example, if this block + /// is shared with multiple references, the caller must ensure that calling + /// it will not cause a data race. pub unsafe fn call(&self, args: A) -> R { args.call_block(self as *const _ as *mut _) } @@ -251,7 +258,7 @@ impl ConcreteBlock { } impl ConcreteBlock where F: 'static { - /// Copy self onto the heap. + /// Copy self onto the heap as an `RcBlock`. pub fn copy(self) -> RcBlock { unsafe { let mut block = self; From fc918f43780231151bf933bdbc42689c088c30d3 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 15:20:16 -0700 Subject: [PATCH 091/125] Added RcBlock documentation. --- src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6b8fad1fa..504218a9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -129,15 +129,25 @@ impl Block where A: BlockArguments { } } +/// A reference-counted Objective-C block. pub struct RcBlock { ptr: *mut Block, } impl RcBlock { + /// Construct an `RcBlock` for the given block without copying it. + /// The caller must ensure the block has a +1 reference count. + /// + /// Unsafe because `ptr` must point to a valid `Block` and must have a +1 + /// reference count or it will be overreleased when the `RcBlock` is + /// dropped. pub unsafe fn new(ptr: *mut Block) -> Self { RcBlock { ptr: ptr } } + /// Constructs an `RcBlock` by copying the given block. + /// + /// Unsafe because `ptr` must point to a valid `Block`. pub unsafe fn copy(ptr: *mut Block) -> Self { let ptr = _Block_copy(ptr as *const c_void) as *mut Block; RcBlock { ptr: ptr } From 13cafce8feaacb006b7992eaa3349a6720be3172 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 15:42:01 -0700 Subject: [PATCH 092/125] Updated README. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3ec79ed39..78c65d087 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ int32_t sum(int32_t (^block)(int32_t, int32_t)) { We could write it in Rust as the following: ``` rust -fn sum(block: &mut Block<(i32, i32), i32>) -> i32 { +unsafe fn sum(block: &Block<(i32, i32), i32>) -> i32 { block.call((5, 8)) } ``` @@ -32,8 +32,8 @@ struct. For example, to create a block that adds two `i32`s, we could write: ``` rust let block = ConcreteBlock::new(|a: i32, b: i32| a + b); -let mut block = block.copy(); -assert!(block.call((5, 8)) == 13); +let block = block.copy(); +assert!(unsafe { block.call((5, 8)) } == 13); ``` It is important to copy your block to the heap (with the `copy` method) before From a4cba0bcb9610766f05136bc78982445e00202d7 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 17 May 2015 15:42:10 -0700 Subject: [PATCH 093/125] Bumped to version 0.1.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9a0a72902..0679045d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.0.2" +version = "0.1.0" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From 5fd52e876b010dd1a6bcf06bb9ae6c947ed84e4d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 2 Sep 2015 08:42:42 -0400 Subject: [PATCH 094/125] Fix nightly warnings related to lifetimes The following warnings appear: ``` src/lib.rs:73:5: 73:68 warning: the trait `core::marker::Sized` is not implemented for the type `Self` [E0277] src/lib.rs:73 unsafe fn call_block(self, block: *mut Block) -> R; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:73:5: 73:68 help: run `rustc --explain E0277` to see a detailed explanation src/lib.rs:73:5: 73:68 note: `Self` does not have a constant size known at compile-time src/lib.rs:73 unsafe fn call_block(self, block: *mut Block) -> R; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:73:5: 73:68 note: this warning results from recent bug fixes and clarifications; it will become a HARD ERROR in the next release. See RFC 1214 for details. src/lib.rs:73 unsafe fn call_block(self, block: *mut Block) -> R; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:73:5: 73:68 note: required by `Block` src/lib.rs:73 unsafe fn call_block(self, block: *mut Block) -> R; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:187:5: 187:71 warning: the trait `core::marker::Sized` is not implemented for the type `Self` [E0277] src/lib.rs:187 fn into_concrete_block(self) -> ConcreteBlock; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:187:5: 187:71 help: run `rustc --explain E0277` to see a detailed explanation src/lib.rs:187:5: 187:71 note: `Self` does not have a constant size known at compile-time src/lib.rs:187 fn into_concrete_block(self) -> ConcreteBlock; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:187:5: 187:71 note: this warning results from recent bug fixes and clarifications; it will become a HARD ERROR in the next release. See RFC 1214 for details. src/lib.rs:187 fn into_concrete_block(self) -> ConcreteBlock; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ src/lib.rs:187:5: 187:71 note: required by `ConcreteBlock` src/lib.rs:187 fn into_concrete_block(self) -> ConcreteBlock; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` ...because of: https://github.com/rust-lang/rfcs/pull/1214 --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 504218a9f..0b148809c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ extern { } /// Types that may be used as the arguments to an Objective-C block. -pub trait BlockArguments { +pub trait BlockArguments: Sized { /// Calls the given `Block` with self as the arguments. /// /// Unsafe because `block` must point to a valid `Block` and this invokes @@ -179,7 +179,7 @@ impl Drop for RcBlock { } /// Types that may be converted into a `ConcreteBlock`. -pub trait IntoConcreteBlock where A: BlockArguments { +pub trait IntoConcreteBlock: Sized where A: BlockArguments { /// The return type of the resulting `ConcreteBlock`. type Ret; From bd10ada3647ff1d0fe0d99379743d4f316a170ab Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 2 Sep 2015 20:39:11 -0700 Subject: [PATCH 095/125] Bumped to version 0.1.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0679045d1..d76a38911 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.1.0" +version = "0.1.1" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From a1c5ef60555ef46c4be7fc7df3d027296d1ecd7a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Mon, 5 Oct 2015 21:47:49 -0500 Subject: [PATCH 096/125] Add a Class type to fix the improper_ctypes warning. This warning starting appearing from rust-lang/rust#26583. --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0b148809c..3f2d444f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,9 +56,11 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use libc::{c_int, c_ulong, c_void}; +enum Class { } + #[link(name = "System", kind = "dylib")] extern { - static _NSConcreteStackBlock: (); + static _NSConcreteStackBlock: Class; fn _Block_copy(block: *const c_void) -> *mut c_void; fn _Block_release(block: *const c_void); @@ -104,7 +106,7 @@ block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: #[repr(C)] struct BlockBase { - isa: *const (), + isa: *const Class, flags: c_int, _reserved: c_int, invoke: unsafe extern fn(*mut Block, ...) -> R, From 0267d5ec387456e35205974139317e5ab15844b2 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Mon, 5 Oct 2015 21:51:06 -0500 Subject: [PATCH 097/125] Bumped to version 0.1.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d76a38911..9f671dffd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.1.1" +version = "0.1.2" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From 45b644f9d40fc8f96f9d1dfc893b3115b19de4f4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 6 Nov 2015 23:31:28 -0800 Subject: [PATCH 098/125] Updated libc dependency to allow 0.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9f671dffd..061430230 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" exclude = [".gitignore"] [dependencies] -libc = "0.1" +libc = ">= 0.1, < 0.3" [dev-dependencies.objc_test_utils] version = "0.0" From d79b428b1fbe1118cf3c78175bedccbd4e441539 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Fri, 6 Nov 2015 23:33:41 -0800 Subject: [PATCH 099/125] Bumped to version 0.1.3. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 061430230..fe9e439d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.1.2" +version = "0.1.3" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From d3ff93d03d0a3109dd01e358012eea8adb3ae5ee Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 11 Nov 2015 20:29:53 -0800 Subject: [PATCH 100/125] Removed libc dependency by using std::os::raw types. --- Cargo.toml | 3 --- src/lib.rs | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fe9e439d4..e35019092 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,9 +12,6 @@ license = "MIT" exclude = [".gitignore"] -[dependencies] -libc = ">= 0.1, < 0.3" - [dev-dependencies.objc_test_utils] version = "0.0" path = "test_utils" diff --git a/src/lib.rs b/src/lib.rs index 3f2d444f9..be809ef1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,16 +45,14 @@ to be copied once, and we can enforce this in Rust, but if Objective-C code were to copy it twice we could have a double free. */ -extern crate libc; - #[cfg(test)] extern crate objc_test_utils; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; +use std::os::raw::{c_int, c_ulong, c_void}; use std::ptr; -use libc::{c_int, c_ulong, c_void}; enum Class { } From b1207143cc12eb2b48dda73132b89e2fcf4b73c9 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Wed, 11 Nov 2015 23:43:25 -0800 Subject: [PATCH 101/125] Bumped to version 0.1.4. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e35019092..04310f54f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.1.3" +version = "0.1.4" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From 12109dc53ee20e1f4547b0bbba3fadc4c906c523 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Tue, 29 Mar 2016 10:31:46 -0400 Subject: [PATCH 102/125] Use explicit casts to silence warnings. Fixes #3. --- src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index be809ef1a..fda61f501 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,8 +206,11 @@ macro_rules! concrete_block_impl { } unsafe { - ConcreteBlock::with_invoke( - mem::transmute($f::<$($t,)* R, X>), self) + let f: unsafe extern "C" fn(*mut ConcreteBlock<($($t,)*), R, X> + $(, $a: $t)*) -> R = $f::<$($t,)* R, X>; + let f: unsafe extern "C" fn(*mut ConcreteBlock<($($t,)*), R, X>, ...) -> R = + mem::transmute(f); + ConcreteBlock::with_invoke(f, self) } } } From 88b38f6fa06286e7bd0b3a3284f27ecdd9e582d4 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 3 Apr 2016 22:19:20 -0700 Subject: [PATCH 103/125] Move safe code out of an unsafe block. --- src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fda61f501..523d8f82f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -205,12 +205,9 @@ macro_rules! concrete_block_impl { (block.closure)($($a),*) } + let f: unsafe extern fn(*mut ConcreteBlock<($($t,)*), R, X> $(, $a: $t)*) -> R = $f; unsafe { - let f: unsafe extern "C" fn(*mut ConcreteBlock<($($t,)*), R, X> - $(, $a: $t)*) -> R = $f::<$($t,)* R, X>; - let f: unsafe extern "C" fn(*mut ConcreteBlock<($($t,)*), R, X>, ...) -> R = - mem::transmute(f); - ConcreteBlock::with_invoke(f, self) + ConcreteBlock::with_invoke(mem::transmute(f), self) } } } From dd2da220cb9e4d7251fb58f76f26faff095f0977 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 3 Apr 2016 22:20:39 -0700 Subject: [PATCH 104/125] Bumped to version 0.1.5. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 04310f54f..9e6fd730f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.1.4" +version = "0.1.5" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From e1ebad95c831fbc6f3c993d816c12fcbbd781481 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 May 2016 20:24:49 -0700 Subject: [PATCH 105/125] Added travis config. --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..4cc2b689f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: rust +rust: + - stable + - nightly +os: osx +sudo: false From 8868a8bb89980a959ea3e315d1e261a3a92c522e Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 May 2016 19:55:01 -0700 Subject: [PATCH 106/125] Extracted test code to a test_utils module. --- src/lib.rs | 34 +++------------------------------- src/test_utils.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 31 deletions(-) create mode 100644 src/test_utils.rs diff --git a/src/lib.rs b/src/lib.rs index 523d8f82f..92e212eb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ were to copy it twice we could have a double free. */ #[cfg(test)] -extern crate objc_test_utils; +mod test_utils; use std::marker::PhantomData; use std::mem; @@ -335,36 +335,8 @@ impl BlockDescriptor { #[cfg(test)] mod tests { - use objc_test_utils; - use super::{Block, ConcreteBlock, RcBlock}; - - fn get_int_block_with(i: i32) -> RcBlock<(), i32> { - unsafe { - let ptr = objc_test_utils::get_int_block_with(i); - RcBlock::new(ptr as *mut _) - } - } - - fn get_add_block_with(i: i32) -> RcBlock<(i32,), i32> { - unsafe { - let ptr = objc_test_utils::get_add_block_with(i); - RcBlock::new(ptr as *mut _) - } - } - - fn invoke_int_block(block: &Block<(), i32>) -> i32 { - let ptr = block as *const _; - unsafe { - objc_test_utils::invoke_int_block(ptr as *mut _) - } - } - - fn invoke_add_block(block: &Block<(i32,), i32>, a: i32) -> i32 { - let ptr = block as *const _; - unsafe { - objc_test_utils::invoke_add_block(ptr as *mut _, a) - } - } + use test_utils::*; + use super::{ConcreteBlock, RcBlock}; #[test] fn test_call_block() { diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 000000000..940a3d227 --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,31 @@ +extern crate objc_test_utils; + +use {Block, RcBlock}; + +pub fn get_int_block_with(i: i32) -> RcBlock<(), i32> { + unsafe { + let ptr = objc_test_utils::get_int_block_with(i); + RcBlock::new(ptr as *mut _) + } +} + +pub fn get_add_block_with(i: i32) -> RcBlock<(i32,), i32> { + unsafe { + let ptr = objc_test_utils::get_add_block_with(i); + RcBlock::new(ptr as *mut _) + } +} + +pub fn invoke_int_block(block: &Block<(), i32>) -> i32 { + let ptr = block as *const _; + unsafe { + objc_test_utils::invoke_int_block(ptr as *mut _) + } +} + +pub fn invoke_add_block(block: &Block<(i32,), i32>, a: i32) -> i32 { + let ptr = block as *const _; + unsafe { + objc_test_utils::invoke_add_block(ptr as *mut _, a) + } +} From b4cb376b8229ce71e2d7da827aa886d1bdae1185 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 May 2016 20:21:39 -0700 Subject: [PATCH 107/125] Add rust-tests-ios support. --- .gitignore | 3 +++ tests-ios/prelude.rs | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 tests-ios/prelude.rs diff --git a/.gitignore b/.gitignore index a9d37c560..38188dacc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ target Cargo.lock + +tests-ios/* +!tests-ios/prelude.rs diff --git a/tests-ios/prelude.rs b/tests-ios/prelude.rs new file mode 100644 index 000000000..1c5eea202 --- /dev/null +++ b/tests-ios/prelude.rs @@ -0,0 +1,7 @@ +extern crate block; + +#[path = "../src/test_utils.rs"] +mod test_utils; + +pub use block::*; +use test_utils::*; From e7b6650cb2dcd27e25d2636a5c8ca9eba9d6c078 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 May 2016 20:36:48 -0700 Subject: [PATCH 108/125] Added scripts for running rust-test-ios on travis. --- Cargo.toml | 8 +++++++- travis_install.sh | 19 +++++++++++++++++++ travis_test.sh | 10 ++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100755 travis_install.sh create mode 100755 travis_test.sh diff --git a/Cargo.toml b/Cargo.toml index 9e6fd730f..d2c15b0cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,13 @@ repository = "http://github.com/SSheldon/rust-block" documentation = "http://ssheldon.github.io/rust-objc/block/" license = "MIT" -exclude = [".gitignore"] +exclude = [ + ".gitignore", + ".travis.yml", + "travis_install.sh", + "travis_test.sh", + "tests-ios/**", +] [dev-dependencies.objc_test_utils] version = "0.0" diff --git a/travis_install.sh b/travis_install.sh new file mode 100755 index 000000000..5d9623abe --- /dev/null +++ b/travis_install.sh @@ -0,0 +1,19 @@ +#! /usr/bin/env sh + +set -eu + +rust_ios_install() { + ios_stdlib="rust-std-nightly-${1}-apple-ios" + curl -O "http://static.rust-lang.org/dist/${ios_stdlib}.tar.gz" + tar xzf "${ios_stdlib}.tar.gz" + "./${ios_stdlib}/install.sh" --prefix=$(rustc --print sysroot) +} + +for arch in $IOS_ARCHS; do + rust_ios_install "$arch" +done + +if [ -n "$IOS_ARCHS" ]; then + curl -LO https://github.com/SSheldon/rust-test-ios/releases/download/0.1.1/rust-test-ios + chmod +x rust-test-ios +fi diff --git a/travis_test.sh b/travis_test.sh new file mode 100755 index 000000000..1964fe050 --- /dev/null +++ b/travis_test.sh @@ -0,0 +1,10 @@ +#! /usr/bin/env sh + +set -eu + +if [ -z "$IOS_ARCHS" ]; then + cargo build --verbose + cargo test --verbose +else + ./rust-test-ios +fi From a5767ce36d205a6781f6181699512301fa3e05de Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 May 2016 20:38:28 -0700 Subject: [PATCH 109/125] Change travis config to run the scripts. --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4cc2b689f..1d7f39a54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,14 @@ rust: - stable - nightly os: osx +env: + - IOS_ARCHS="" +matrix: + include: + - os: osx + osx_image: xcode7.2 + rust: nightly + env: IOS_ARCHS="i386 x86_64 armv7 armv7s aarch64" sudo: false +install: ./travis_install.sh +script: ./travis_test.sh From 1499799fd5d0718e70b163a9af4d3df1f670582c Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sat, 7 May 2016 22:15:35 -0700 Subject: [PATCH 110/125] Add support for Linux. Platforms beside OSX and iOS will link to libBlocksRuntime. --- .travis.yml | 9 ++++++++- src/lib.rs | 5 ++++- test_utils/build.rs | 6 +++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d7f39a54..2ec231d5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,9 @@ language: rust rust: - stable - nightly -os: osx +os: + - osx + - linux env: - IOS_ARCHS="" matrix: @@ -14,3 +16,8 @@ matrix: sudo: false install: ./travis_install.sh script: ./travis_test.sh +addons: + apt: + packages: + - libblocksruntime-dev + - libdispatch-dev diff --git a/src/lib.rs b/src/lib.rs index 92e212eb6..b9c5d1d77 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,10 @@ use std::ptr; enum Class { } -#[link(name = "System", kind = "dylib")] +#[cfg_attr(any(target_os = "macos", target_os = "ios"), + link(name = "System", kind = "dylib"))] +#[cfg_attr(not(any(target_os = "macos", target_os = "ios")), + link(name = "BlocksRuntime", kind = "dylib"))] extern { static _NSConcreteStackBlock: Class; diff --git a/test_utils/build.rs b/test_utils/build.rs index 7c1455a1e..301051915 100644 --- a/test_utils/build.rs +++ b/test_utils/build.rs @@ -1,5 +1,9 @@ extern crate gcc; fn main() { - gcc::compile_library("libblock_utils.a", &["block_utils.c"]); + gcc::Config::new() + .compiler("clang") + .file("block_utils.c") + .flag("-fblocks") + .compile("libblock_utils.a"); } From 47178790cfc9d4a8b092051d8b413b78bd31254a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 8 May 2016 11:32:49 -0700 Subject: [PATCH 111/125] Bumped to version 0.1.6. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d2c15b0cb..f414e7ef2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block" -version = "0.1.5" +version = "0.1.6" authors = ["Steven Sheldon"] description = "Rust interface for Apple's C language extension of blocks." From fb2fbf410b1ef456decedf495c47b3ec580d4a2a Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 8 May 2016 23:10:18 -0700 Subject: [PATCH 112/125] Remove libdispatch-dev package for travis. It isn't necessary now that travis-ci/apt-package-whitelist#2949 is fixed. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2ec231d5b..702eaee77 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,4 +20,3 @@ addons: apt: packages: - libblocksruntime-dev - - libdispatch-dev From d14ade0244c036df6817c430acf44f3183934881 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Sun, 19 Jun 2016 09:34:03 -0700 Subject: [PATCH 113/125] Update iOS stdlib to install over https. --- travis_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis_install.sh b/travis_install.sh index 5d9623abe..27c11fed7 100755 --- a/travis_install.sh +++ b/travis_install.sh @@ -4,7 +4,7 @@ set -eu rust_ios_install() { ios_stdlib="rust-std-nightly-${1}-apple-ios" - curl -O "http://static.rust-lang.org/dist/${ios_stdlib}.tar.gz" + curl -O "https://static.rust-lang.org/dist/${ios_stdlib}.tar.gz" tar xzf "${ios_stdlib}.tar.gz" "./${ios_stdlib}/install.sh" --prefix=$(rustc --print sysroot) } From 4fda0322ce22c08f03070a3e3103daa640232a89 Mon Sep 17 00:00:00 2001 From: Steven Sheldon Date: Thu, 8 Jun 2017 20:19:15 -0500 Subject: [PATCH 114/125] Use rustup rather than installing iOS stdlibs manually --- .travis.yml | 4 ++-- travis_install.sh | 9 +-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 702eaee77..88ceaf0a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ env: matrix: include: - os: osx - osx_image: xcode7.2 - rust: nightly + osx_image: xcode7.3 + rust: stable env: IOS_ARCHS="i386 x86_64 armv7 armv7s aarch64" sudo: false install: ./travis_install.sh diff --git a/travis_install.sh b/travis_install.sh index 27c11fed7..75e5dd8c1 100755 --- a/travis_install.sh +++ b/travis_install.sh @@ -2,15 +2,8 @@ set -eu -rust_ios_install() { - ios_stdlib="rust-std-nightly-${1}-apple-ios" - curl -O "https://static.rust-lang.org/dist/${ios_stdlib}.tar.gz" - tar xzf "${ios_stdlib}.tar.gz" - "./${ios_stdlib}/install.sh" --prefix=$(rustc --print sysroot) -} - for arch in $IOS_ARCHS; do - rust_ios_install "$arch" + rustup target add "${arch}-apple-ios" done if [ -n "$IOS_ARCHS" ]; then From 642ea4a4a5853a21b55b05c34832a5f1bb1af61c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 26 Jan 2018 16:52:55 +0700 Subject: [PATCH 115/125] Fix markdown warning. When updating to current Rust, there is a warning for a change in the output due to the change in Markdown implementations. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index b9c5d1d77..f05eee6f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ A Rust interface for Objective-C blocks. For more information on the specifics of the block implementation, see -Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html +Clang's documentation: # Invoking blocks From 8a4c403af29b68b17c943877f4b619ed525de7a2 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 15:45:29 +0200 Subject: [PATCH 116/125] Move `block` crate to subdirectory --- .github/workflows/ci.yml | 2 +- .travis.yml | 22 --------- Cargo.toml | 26 +--------- README.md | 43 ---------------- objc_block/Cargo.toml | 23 +++++++++ objc_block/README.md | 49 +++++++++++++++++++ {src => objc_block/src}/lib.rs | 0 {src => objc_block/src}/test_utils.rs | 0 .../tests-ios}/prelude.rs | 0 objc_foundation/Cargo.toml | 2 +- objc_test_utils/Cargo.toml | 23 +++++++++ {test_utils => objc_test_utils}/block_utils.c | 0 {test_utils => objc_test_utils}/build.rs | 0 {test_utils => objc_test_utils}/lib.rs | 0 test_utils/Cargo.toml | 18 ------- travis_install.sh | 12 ----- travis_test.sh | 10 ---- 17 files changed, 99 insertions(+), 131 deletions(-) delete mode 100644 .travis.yml create mode 100644 objc_block/Cargo.toml create mode 100644 objc_block/README.md rename {src => objc_block/src}/lib.rs (100%) rename {src => objc_block/src}/test_utils.rs (100%) rename {tests-ios => objc_block/tests-ios}/prelude.rs (100%) create mode 100644 objc_test_utils/Cargo.toml rename {test_utils => objc_test_utils}/block_utils.c (100%) rename {test_utils => objc_test_utils}/build.rs (100%) rename {test_utils => objc_test_utils}/lib.rs (100%) delete mode 100644 test_utils/Cargo.toml delete mode 100755 travis_install.sh delete mode 100755 travis_test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88c4900d7..cdc72be24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: - name: Install Packages if: contains(matrix.platform.os, 'ubuntu') - run: sudo apt-get install gobjc clang make + run: sudo apt-get install gobjc clang make libblocksruntime-dev - name: Install different Rust toolchain # A default toolchain is already installed diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 88ceaf0a3..000000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: rust -rust: - - stable - - nightly -os: - - osx - - linux -env: - - IOS_ARCHS="" -matrix: - include: - - os: osx - osx_image: xcode7.3 - rust: stable - env: IOS_ARCHS="i386 x86_64 armv7 armv7s aarch64" -sudo: false -install: ./travis_install.sh -script: ./travis_test.sh -addons: - apt: - packages: - - libblocksruntime-dev diff --git a/Cargo.toml b/Cargo.toml index a79c841a6..75b073626 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,34 +1,12 @@ [workspace] members = [ "objc", + "objc_block", "objc_encode", "objc_exception", "objc_foundation", "objc_foundation_derive", "objc_id", + "objc_test_utils", ] exclude = ["objc/tests-ios"] - -[package] -name = "block" -version = "0.1.6" -authors = ["Steven Sheldon"] - -description = "Rust interface for Apple's C language extension of blocks." -keywords = ["blocks", "osx", "ios", "objective-c"] -readme = "README.md" -repository = "http://github.com/SSheldon/rust-block" -documentation = "http://ssheldon.github.io/rust-objc/block/" -license = "MIT" - -exclude = [ - ".gitignore", - ".travis.yml", - "travis_install.sh", - "travis_test.sh", - "tests-ios/**", -] - -[dev-dependencies.objc_test_utils] -version = "0.0" -path = "test_utils" diff --git a/README.md b/README.md index df0ee8449..5e43873f7 100644 --- a/README.md +++ b/README.md @@ -2,46 +2,3 @@ [![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) [![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) - -Rust interface for Apple's C language extension of blocks. - -For more information on the specifics of the block implementation, see -Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html - -## Invoking blocks - -The `Block` struct is used for invoking blocks from Objective-C. For example, -consider this Objective-C function: - -``` objc -int32_t sum(int32_t (^block)(int32_t, int32_t)) { - return block(5, 8); -} -``` - -We could write it in Rust as the following: - -``` rust -unsafe fn sum(block: &Block<(i32, i32), i32>) -> i32 { - block.call((5, 8)) -} -``` - -Note the extra parentheses in the `call` method, since the arguments must be -passed as a tuple. - -## Creating blocks - -Creating a block to pass to Objective-C can be done with the `ConcreteBlock` -struct. For example, to create a block that adds two `i32`s, we could write: - -``` rust -let block = ConcreteBlock::new(|a: i32, b: i32| a + b); -let block = block.copy(); -assert!(unsafe { block.call((5, 8)) } == 13); -``` - -It is important to copy your block to the heap (with the `copy` method) before -passing it to Objective-C; this is because our `ConcreteBlock` is only meant -to be copied once, and we can enforce this in Rust, but if Objective-C code -were to copy it twice we could have a double free. diff --git a/objc_block/Cargo.toml b/objc_block/Cargo.toml new file mode 100644 index 000000000..791adb5d0 --- /dev/null +++ b/objc_block/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "block" +version = "0.1.6" +authors = ["Steven Sheldon", "Mads Marquart "] + +description = "Interface for Apple's C language extension of blocks." +keywords = ["objective-c", "macos", "ios", "blocks"] +categories = [ + "api-bindings", + "development-tools::ffi", + "os::macos-apis", +] +readme = "README.md" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/block/" +license = "MIT" + +exclude = [ + "tests-ios/**", +] + +[dev-dependencies] +objc_test_utils = { path = "../objc_test_utils", version = "0.0" } diff --git a/objc_block/README.md b/objc_block/README.md new file mode 100644 index 000000000..303855279 --- /dev/null +++ b/objc_block/README.md @@ -0,0 +1,49 @@ +# `block` + +[![Latest version](https://badgen.net/crates/v/block)](https://crates.io/crates/block) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/block/badge.svg)](https://docs.rs/block/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) + +Rust interface for Apple's C language extension of blocks. + +For more information on the specifics of the block implementation, see +Clang's documentation: http://clang.llvm.org/docs/Block-ABI-Apple.html + +## Invoking blocks + +The `Block` struct is used for invoking blocks from Objective-C. For example, +consider this Objective-C function: + +``` objc +int32_t sum(int32_t (^block)(int32_t, int32_t)) { + return block(5, 8); +} +``` + +We could write it in Rust as the following: + +``` rust +unsafe fn sum(block: &Block<(i32, i32), i32>) -> i32 { + block.call((5, 8)) +} +``` + +Note the extra parentheses in the `call` method, since the arguments must be +passed as a tuple. + +## Creating blocks + +Creating a block to pass to Objective-C can be done with the `ConcreteBlock` +struct. For example, to create a block that adds two `i32`s, we could write: + +``` rust +let block = ConcreteBlock::new(|a: i32, b: i32| a + b); +let block = block.copy(); +assert!(unsafe { block.call((5, 8)) } == 13); +``` + +It is important to copy your block to the heap (with the `copy` method) before +passing it to Objective-C; this is because our `ConcreteBlock` is only meant +to be copied once, and we can enforce this in Rust, but if Objective-C code +were to copy it twice we could have a double free. diff --git a/src/lib.rs b/objc_block/src/lib.rs similarity index 100% rename from src/lib.rs rename to objc_block/src/lib.rs diff --git a/src/test_utils.rs b/objc_block/src/test_utils.rs similarity index 100% rename from src/test_utils.rs rename to objc_block/src/test_utils.rs diff --git a/tests-ios/prelude.rs b/objc_block/tests-ios/prelude.rs similarity index 100% rename from tests-ios/prelude.rs rename to objc_block/tests-ios/prelude.rs diff --git a/objc_foundation/Cargo.toml b/objc_foundation/Cargo.toml index 9b56aadda..8d9009f49 100644 --- a/objc_foundation/Cargo.toml +++ b/objc_foundation/Cargo.toml @@ -20,6 +20,6 @@ license = "MIT" default = ["block"] [dependencies] -block = { optional = true, version = "0.1" } +block = { path = "../objc_block", optional = true, version = "0.1" } objc = { path = "../objc", version = "0.2.7" } objc_id = { path = "../objc_id", version = "0.1" } diff --git a/objc_test_utils/Cargo.toml b/objc_test_utils/Cargo.toml new file mode 100644 index 000000000..9187fd998 --- /dev/null +++ b/objc_test_utils/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "objc_test_utils" +version = "0.0.2" +authors = ["Steven Sheldon", "Mads Marquart "] + +description = "Utilities for testing Objective-C interop." +keywords = ["objective-c", "macos", "ios", "testing"] +categories = [ + "development-tools::ffi", + "development-tools::testing", + "os::macos-apis", +] +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc_test_utils/" +license = "MIT" + +build = "build.rs" + +[lib] +path = "lib.rs" + +[build-dependencies] +gcc = "0.3" diff --git a/test_utils/block_utils.c b/objc_test_utils/block_utils.c similarity index 100% rename from test_utils/block_utils.c rename to objc_test_utils/block_utils.c diff --git a/test_utils/build.rs b/objc_test_utils/build.rs similarity index 100% rename from test_utils/build.rs rename to objc_test_utils/build.rs diff --git a/test_utils/lib.rs b/objc_test_utils/lib.rs similarity index 100% rename from test_utils/lib.rs rename to objc_test_utils/lib.rs diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml deleted file mode 100644 index 644e8cf66..000000000 --- a/test_utils/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "objc_test_utils" -version = "0.0.2" -authors = ["Steven Sheldon"] - -description = "Utilities for testing Objective-C interop." -repository = "http://github.com/SSheldon/rust-objc" -documentation = "http://ssheldon.github.io/rust-objc/objc_test_utils/" -license = "MIT" - -build = "build.rs" - -[lib] -name = "objc_test_utils" -path = "lib.rs" - -[build-dependencies] -gcc = "0.3" diff --git a/travis_install.sh b/travis_install.sh deleted file mode 100755 index 75e5dd8c1..000000000 --- a/travis_install.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /usr/bin/env sh - -set -eu - -for arch in $IOS_ARCHS; do - rustup target add "${arch}-apple-ios" -done - -if [ -n "$IOS_ARCHS" ]; then - curl -LO https://github.com/SSheldon/rust-test-ios/releases/download/0.1.1/rust-test-ios - chmod +x rust-test-ios -fi diff --git a/travis_test.sh b/travis_test.sh deleted file mode 100755 index 1964fe050..000000000 --- a/travis_test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /usr/bin/env sh - -set -eu - -if [ -z "$IOS_ARCHS" ]; then - cargo build --verbose - cargo test --verbose -else - ./rust-test-ios -fi From ce5a9bf792bef2839adaa6813394eb58771c0542 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 15:47:53 +0200 Subject: [PATCH 117/125] Run `cargo fmt` --- objc/src/lib.rs | 6 +- objc/src/rc/autorelease.rs | 7 +- objc_block/src/lib.rs | 185 ++++++++++++++++++++++++++++------- objc_block/src/test_utils.rs | 8 +- objc_test_utils/lib.rs | 6 +- 5 files changed, 165 insertions(+), 47 deletions(-) diff --git a/objc/src/lib.rs b/objc/src/lib.rs index 1744d3c06..0f96c4a43 100644 --- a/objc/src/lib.rs +++ b/objc/src/lib.rs @@ -59,8 +59,10 @@ The bindings can be used on Linux or *BSD utilizing the */ #![no_std] -#![cfg_attr(feature = "unstable_autoreleasesafe", feature(negative_impls, auto_traits))] - +#![cfg_attr( + feature = "unstable_autoreleasesafe", + feature(negative_impls, auto_traits) +)] #![warn(missing_docs)] #![allow(clippy::missing_safety_doc)] // Update in Cargo.toml as well. diff --git a/objc/src/rc/autorelease.rs b/objc/src/rc/autorelease.rs index 661bb5b83..dd337161b 100644 --- a/objc/src/rc/autorelease.rs +++ b/objc/src/rc/autorelease.rs @@ -1,6 +1,6 @@ use core::ffi::c_void; #[cfg(all(debug_assertions, not(feature = "unstable_autoreleasesafe")))] -use std::{cell::RefCell, vec::Vec, thread_local}; +use std::{cell::RefCell, thread_local, vec::Vec}; use crate::runtime::{objc_autoreleasePoolPop, objc_autoreleasePoolPush}; @@ -265,7 +265,10 @@ impl !AutoreleaseSafe for AutoreleasePool {} /// inner pool: /// #[cfg_attr(feature = "unstable_autoreleasesafe", doc = "```rust,compile_fail")] -#[cfg_attr(not(feature = "unstable_autoreleasesafe"), doc = "```rust,should_panic")] +#[cfg_attr( + not(feature = "unstable_autoreleasesafe"), + doc = "```rust,should_panic" +)] /// # use objc::{class, msg_send}; /// # use objc::rc::{autoreleasepool, AutoreleasePool}; /// # use objc::runtime::Object; diff --git a/objc_block/src/lib.rs b/objc_block/src/lib.rs index f05eee6f0..bdb729921 100644 --- a/objc_block/src/lib.rs +++ b/objc_block/src/lib.rs @@ -54,13 +54,17 @@ use std::ops::{Deref, DerefMut}; use std::os::raw::{c_int, c_ulong, c_void}; use std::ptr; -enum Class { } - -#[cfg_attr(any(target_os = "macos", target_os = "ios"), - link(name = "System", kind = "dylib"))] -#[cfg_attr(not(any(target_os = "macos", target_os = "ios")), - link(name = "BlocksRuntime", kind = "dylib"))] -extern { +enum Class {} + +#[cfg_attr( + any(target_os = "macos", target_os = "ios"), + link(name = "System", kind = "dylib") +)] +#[cfg_attr( + not(any(target_os = "macos", target_os = "ios")), + link(name = "BlocksRuntime", kind = "dylib") +)] +extern "C" { static _NSConcreteStackBlock: Class; fn _Block_copy(block: *const c_void) -> *mut c_void; @@ -102,15 +106,40 @@ block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); -block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); -block_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); +block_args_impl!( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + k: K +); +block_args_impl!( + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + k: K, + l: L +); #[repr(C)] struct BlockBase { isa: *const Class, flags: c_int, _reserved: c_int, - invoke: unsafe extern fn(*mut Block, ...) -> R, + invoke: unsafe extern "C" fn(*mut Block, ...) -> R, } /// An Objective-C block that takes arguments of `A` when called and @@ -120,7 +149,10 @@ pub struct Block { _base: PhantomData>, } -impl Block where A: BlockArguments { +impl Block +where + A: BlockArguments, +{ /// Call self with the given arguments. /// /// Unsafe because this invokes foreign code that the caller must verify @@ -159,9 +191,7 @@ impl RcBlock { impl Clone for RcBlock { fn clone(&self) -> RcBlock { - unsafe { - RcBlock::copy(self.ptr) - } + unsafe { RcBlock::copy(self.ptr) } } } @@ -182,7 +212,10 @@ impl Drop for RcBlock { } /// Types that may be converted into a `ConcreteBlock`. -pub trait IntoConcreteBlock: Sized where A: BlockArguments { +pub trait IntoConcreteBlock: Sized +where + A: BlockArguments, +{ /// The return type of the resulting `ConcreteBlock`. type Ret; @@ -223,13 +256,90 @@ concrete_block_impl!(concrete_block_invoke_args2, a: A, b: B); concrete_block_impl!(concrete_block_invoke_args3, a: A, b: B, c: C); concrete_block_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D); concrete_block_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E); -concrete_block_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F); -concrete_block_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G); -concrete_block_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); -concrete_block_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); -concrete_block_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); -concrete_block_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); -concrete_block_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L); +concrete_block_impl!( + concrete_block_invoke_args6, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F +); +concrete_block_impl!( + concrete_block_invoke_args7, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G +); +concrete_block_impl!( + concrete_block_invoke_args8, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H +); +concrete_block_impl!( + concrete_block_invoke_args9, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I +); +concrete_block_impl!( + concrete_block_invoke_args10, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J +); +concrete_block_impl!( + concrete_block_invoke_args11, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + k: K +); +concrete_block_impl!( + concrete_block_invoke_args12, + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, + g: G, + h: H, + i: I, + j: J, + k: K, + l: L +); /// An Objective-C block whose size is known at compile time and may be /// constructed on the stack. @@ -241,7 +351,10 @@ pub struct ConcreteBlock { } impl ConcreteBlock - where A: BlockArguments, F: IntoConcreteBlock { +where + A: BlockArguments, + F: IntoConcreteBlock, +{ /// Constructs a `ConcreteBlock` with the given closure. /// When the block is called, it will return the value that results from /// calling the closure. @@ -254,8 +367,7 @@ impl ConcreteBlock { /// Constructs a `ConcreteBlock` with the given invoke function and closure. /// Unsafe because the caller must ensure the invoke function takes the /// correct arguments. - unsafe fn with_invoke(invoke: unsafe extern fn(*mut Self, ...) -> R, - closure: F) -> Self { + unsafe fn with_invoke(invoke: unsafe extern "C" fn(*mut Self, ...) -> R, closure: F) -> Self { ConcreteBlock { base: BlockBase { isa: &_NSConcreteStackBlock, @@ -270,7 +382,10 @@ impl ConcreteBlock { } } -impl ConcreteBlock where F: 'static { +impl ConcreteBlock +where + F: 'static, +{ /// Copy self onto the heap as an `RcBlock`. pub fn copy(self) -> RcBlock { unsafe { @@ -285,11 +400,13 @@ impl ConcreteBlock where F: 'static { } } -impl Clone for ConcreteBlock where F: Clone { +impl Clone for ConcreteBlock +where + F: Clone, +{ fn clone(&self) -> Self { unsafe { - ConcreteBlock::with_invoke(mem::transmute(self.base.invoke), - self.closure.clone()) + ConcreteBlock::with_invoke(mem::transmute(self.base.invoke), self.closure.clone()) } } } @@ -308,12 +425,12 @@ impl DerefMut for ConcreteBlock { } } -unsafe extern fn block_context_dispose(block: &mut B) { +unsafe extern "C" fn block_context_dispose(block: &mut B) { // Read the block onto the stack and let it drop ptr::read(block); } -unsafe extern fn block_context_copy(_dst: &mut B, _src: &B) { +unsafe extern "C" fn block_context_copy(_dst: &mut B, _src: &B) { // The runtime memmoves the src block into the dst block, nothing to do } @@ -321,8 +438,8 @@ unsafe extern fn block_context_copy(_dst: &mut B, _src: &B) { struct BlockDescriptor { _reserved: c_ulong, block_size: c_ulong, - copy_helper: unsafe extern fn(&mut B, &B), - dispose_helper: unsafe extern fn(&mut B), + copy_helper: unsafe extern "C" fn(&mut B, &B), + dispose_helper: unsafe extern "C" fn(&mut B), } impl BlockDescriptor { @@ -338,8 +455,8 @@ impl BlockDescriptor { #[cfg(test)] mod tests { - use test_utils::*; use super::{ConcreteBlock, RcBlock}; + use test_utils::*; #[test] fn test_call_block() { diff --git a/objc_block/src/test_utils.rs b/objc_block/src/test_utils.rs index 940a3d227..ca785ab53 100644 --- a/objc_block/src/test_utils.rs +++ b/objc_block/src/test_utils.rs @@ -18,14 +18,10 @@ pub fn get_add_block_with(i: i32) -> RcBlock<(i32,), i32> { pub fn invoke_int_block(block: &Block<(), i32>) -> i32 { let ptr = block as *const _; - unsafe { - objc_test_utils::invoke_int_block(ptr as *mut _) - } + unsafe { objc_test_utils::invoke_int_block(ptr as *mut _) } } pub fn invoke_add_block(block: &Block<(i32,), i32>, a: i32) -> i32 { let ptr = block as *const _; - unsafe { - objc_test_utils::invoke_add_block(ptr as *mut _, a) - } + unsafe { objc_test_utils::invoke_add_block(ptr as *mut _, a) } } diff --git a/objc_test_utils/lib.rs b/objc_test_utils/lib.rs index 3a1e98aa9..c3ec6b917 100644 --- a/objc_test_utils/lib.rs +++ b/objc_test_utils/lib.rs @@ -2,13 +2,13 @@ #![crate_type = "lib"] /// A block that takes no arguments and returns an integer: `int32_t (^)()`. -pub enum IntBlock { } +pub enum IntBlock {} /// A block that takes one integer argument, adds to it, and returns the sum: /// `int32_t (^)(int32_t)`. -pub enum AddBlock { } +pub enum AddBlock {} -extern { +extern "C" { /// Returns a pointer to a global `IntBlock` that returns 7. pub fn get_int_block() -> *mut IntBlock; /// Returns a pointer to a copied `IntBlock` that returns `i`. From 386895042fe2681cfdc33b6bd6fe2b77ae63c49c Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 15:50:27 +0200 Subject: [PATCH 118/125] Move objc_test_utils stuff to match normal crate structure --- objc_test_utils/Cargo.toml | 3 --- objc_test_utils/build.rs | 2 +- objc_test_utils/{ => extern}/block_utils.c | 0 objc_test_utils/{ => src}/lib.rs | 0 4 files changed, 1 insertion(+), 4 deletions(-) rename objc_test_utils/{ => extern}/block_utils.c (100%) rename objc_test_utils/{ => src}/lib.rs (100%) diff --git a/objc_test_utils/Cargo.toml b/objc_test_utils/Cargo.toml index 9187fd998..e0a5c0fdd 100644 --- a/objc_test_utils/Cargo.toml +++ b/objc_test_utils/Cargo.toml @@ -16,8 +16,5 @@ license = "MIT" build = "build.rs" -[lib] -path = "lib.rs" - [build-dependencies] gcc = "0.3" diff --git a/objc_test_utils/build.rs b/objc_test_utils/build.rs index 301051915..0af042056 100644 --- a/objc_test_utils/build.rs +++ b/objc_test_utils/build.rs @@ -3,7 +3,7 @@ extern crate gcc; fn main() { gcc::Config::new() .compiler("clang") - .file("block_utils.c") + .file("extern/block_utils.c") .flag("-fblocks") .compile("libblock_utils.a"); } diff --git a/objc_test_utils/block_utils.c b/objc_test_utils/extern/block_utils.c similarity index 100% rename from objc_test_utils/block_utils.c rename to objc_test_utils/extern/block_utils.c diff --git a/objc_test_utils/lib.rs b/objc_test_utils/src/lib.rs similarity index 100% rename from objc_test_utils/lib.rs rename to objc_test_utils/src/lib.rs From d8e1c602450b721dc8ca59164c6e693f8d971940 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 26 Jan 2018 16:58:31 +0700 Subject: [PATCH 119/125] Update test_utils to use `cc` rather than `gcc`. The `gcc` crate has been replaced with `cc`. Additionally, the `gcc:Config` was renamed to `gcc::Build`. This updates both of those. Commit taken from https://github.com/SSheldon/rust-block/pull/8 --- objc_test_utils/Cargo.toml | 2 +- objc_test_utils/build.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/objc_test_utils/Cargo.toml b/objc_test_utils/Cargo.toml index e0a5c0fdd..ae9971ddb 100644 --- a/objc_test_utils/Cargo.toml +++ b/objc_test_utils/Cargo.toml @@ -17,4 +17,4 @@ license = "MIT" build = "build.rs" [build-dependencies] -gcc = "0.3" +cc = "1.0" diff --git a/objc_test_utils/build.rs b/objc_test_utils/build.rs index 0af042056..7be34f363 100644 --- a/objc_test_utils/build.rs +++ b/objc_test_utils/build.rs @@ -1,7 +1,7 @@ -extern crate gcc; +extern crate cc; fn main() { - gcc::Config::new() + cc::Build::new() .compiler("clang") .file("extern/block_utils.c") .flag("-fblocks") From b6438c733a7a9bfe75e60b62126d1933137f42e4 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 16:09:15 +0200 Subject: [PATCH 120/125] Fix warnings --- objc/src/rc/autorelease.rs | 3 +++ objc_block/src/lib.rs | 42 +++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/objc/src/rc/autorelease.rs b/objc/src/rc/autorelease.rs index dd337161b..b3ed68ec4 100644 --- a/objc/src/rc/autorelease.rs +++ b/objc/src/rc/autorelease.rs @@ -81,6 +81,7 @@ impl AutoreleasePool { all(debug_assertions, not(feature = "unstable_autoreleasesafe")), inline )] + #[allow(clippy::needless_lifetimes)] pub unsafe fn ptr_as_ref<'p, T>(&'p self, ptr: *const T) -> &'p T { #[cfg(all(debug_assertions, not(feature = "unstable_autoreleasesafe")))] POOLS.with(|c| { @@ -110,6 +111,8 @@ impl AutoreleasePool { all(debug_assertions, not(feature = "unstable_autoreleasesafe")), inline )] + #[allow(clippy::needless_lifetimes)] + #[allow(clippy::mut_from_ref)] pub unsafe fn ptr_as_mut<'p, T>(&'p self, ptr: *mut T) -> &'p mut T { #[cfg(all(debug_assertions, not(feature = "unstable_autoreleasesafe")))] POOLS.with(|c| { diff --git a/objc_block/src/lib.rs b/objc_block/src/lib.rs index bdb729921..09a60edf3 100644 --- a/objc_block/src/lib.rs +++ b/objc_block/src/lib.rs @@ -54,7 +54,11 @@ use std::ops::{Deref, DerefMut}; use std::os::raw::{c_int, c_ulong, c_void}; use std::ptr; -enum Class {} +// TODO: Replace with `objc::Class` +#[repr(C)] +struct ClassInternal { + _priv: [u8; 0], +} #[cfg_attr( any(target_os = "macos", target_os = "ios"), @@ -65,7 +69,7 @@ enum Class {} link(name = "BlocksRuntime", kind = "dylib") )] extern "C" { - static _NSConcreteStackBlock: Class; + static _NSConcreteStackBlock: ClassInternal; fn _Block_copy(block: *const c_void) -> *mut c_void; fn _Block_release(block: *const c_void); @@ -75,8 +79,11 @@ extern "C" { pub trait BlockArguments: Sized { /// Calls the given `Block` with self as the arguments. /// - /// Unsafe because `block` must point to a valid `Block` and this invokes - /// foreign code whose safety the compiler cannot verify. + /// # Safety + /// + /// The given block must point to a valid `Block`. + /// + /// This invokes foreign code whose safety the user must guarantee. unsafe fn call_block(self, block: *mut Block) -> R; } @@ -136,7 +143,7 @@ block_args_impl!( #[repr(C)] struct BlockBase { - isa: *const Class, + isa: *const ClassInternal, flags: c_int, _reserved: c_int, invoke: unsafe extern "C" fn(*mut Block, ...) -> R, @@ -155,10 +162,13 @@ where { /// Call self with the given arguments. /// - /// Unsafe because this invokes foreign code that the caller must verify - /// doesn't violate any of Rust's safety rules. For example, if this block - /// is shared with multiple references, the caller must ensure that calling - /// it will not cause a data race. + /// # Safety + /// + /// This invokes foreign code that the caller must verify doesn't violate + /// any of Rust's safety rules. + /// + /// For example, if this block is shared with multiple references, the + /// caller must ensure that calling it will not cause a data race. pub unsafe fn call(&self, args: A) -> R { args.call_block(self as *const _ as *mut _) } @@ -173,19 +183,23 @@ impl RcBlock { /// Construct an `RcBlock` for the given block without copying it. /// The caller must ensure the block has a +1 reference count. /// - /// Unsafe because `ptr` must point to a valid `Block` and must have a +1 + /// # Safety + /// + /// The given pointer must point to a valid `Block` and must have a +1 /// reference count or it will be overreleased when the `RcBlock` is /// dropped. pub unsafe fn new(ptr: *mut Block) -> Self { - RcBlock { ptr: ptr } + RcBlock { ptr } } /// Constructs an `RcBlock` by copying the given block. /// - /// Unsafe because `ptr` must point to a valid `Block`. + /// # Safety + /// + /// The given pointer must point to a valid `Block`. pub unsafe fn copy(ptr: *mut Block) -> Self { let ptr = _Block_copy(ptr as *const c_void) as *mut Block; - RcBlock { ptr: ptr } + RcBlock { ptr } } } @@ -377,7 +391,7 @@ impl ConcreteBlock { invoke: mem::transmute(invoke), }, descriptor: Box::new(BlockDescriptor::new()), - closure: closure, + closure, } } } From 3f580b4658aa91d2154b9c4cfae55e403b1ec324 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 16:17:34 +0200 Subject: [PATCH 121/125] Update objc_block to 2018 edition --- objc_block/Cargo.toml | 1 + objc_block/src/lib.rs | 2 +- objc_block/src/test_utils.rs | 4 ++-- objc_foundation/Cargo.toml | 2 +- objc_foundation_derive/src/lib.rs | 4 ++-- objc_test_utils/Cargo.toml | 1 + objc_test_utils/build.rs | 2 +- objc_test_utils/src/lib.rs | 10 ++++++++-- 8 files changed, 17 insertions(+), 9 deletions(-) diff --git a/objc_block/Cargo.toml b/objc_block/Cargo.toml index 791adb5d0..6772e6694 100644 --- a/objc_block/Cargo.toml +++ b/objc_block/Cargo.toml @@ -2,6 +2,7 @@ name = "block" version = "0.1.6" authors = ["Steven Sheldon", "Mads Marquart "] +edition = "2018" description = "Interface for Apple's C language extension of blocks." keywords = ["objective-c", "macos", "ios", "blocks"] diff --git a/objc_block/src/lib.rs b/objc_block/src/lib.rs index 09a60edf3..5e2713432 100644 --- a/objc_block/src/lib.rs +++ b/objc_block/src/lib.rs @@ -470,7 +470,7 @@ impl BlockDescriptor { #[cfg(test)] mod tests { use super::{ConcreteBlock, RcBlock}; - use test_utils::*; + use crate::test_utils::*; #[test] fn test_call_block() { diff --git a/objc_block/src/test_utils.rs b/objc_block/src/test_utils.rs index ca785ab53..71632bda5 100644 --- a/objc_block/src/test_utils.rs +++ b/objc_block/src/test_utils.rs @@ -1,6 +1,6 @@ -extern crate objc_test_utils; +use objc_test_utils; -use {Block, RcBlock}; +use crate::{Block, RcBlock}; pub fn get_int_block_with(i: i32) -> RcBlock<(), i32> { unsafe { diff --git a/objc_foundation/Cargo.toml b/objc_foundation/Cargo.toml index 8d9009f49..c9c8bf31d 100644 --- a/objc_foundation/Cargo.toml +++ b/objc_foundation/Cargo.toml @@ -22,4 +22,4 @@ default = ["block"] [dependencies] block = { path = "../objc_block", optional = true, version = "0.1" } objc = { path = "../objc", version = "0.2.7" } -objc_id = { path = "../objc_id", version = "0.1" } +objc_id = { path = "../objc_id", version = "0.1.1" } diff --git a/objc_foundation_derive/src/lib.rs b/objc_foundation_derive/src/lib.rs index 2e4c72ae4..cda8a4d9a 100644 --- a/objc_foundation_derive/src/lib.rs +++ b/objc_foundation_derive/src/lib.rs @@ -5,10 +5,10 @@ #[doc = include_str!("../README.md")] extern "C" {} -extern crate proc_macro; + #[macro_use] extern crate quote; -extern crate syn; +use syn; use proc_macro::TokenStream; use quote::{ToTokens, Tokens}; diff --git a/objc_test_utils/Cargo.toml b/objc_test_utils/Cargo.toml index ae9971ddb..8a1154b12 100644 --- a/objc_test_utils/Cargo.toml +++ b/objc_test_utils/Cargo.toml @@ -2,6 +2,7 @@ name = "objc_test_utils" version = "0.0.2" authors = ["Steven Sheldon", "Mads Marquart "] +edition = "2018" description = "Utilities for testing Objective-C interop." keywords = ["objective-c", "macos", "ios", "testing"] diff --git a/objc_test_utils/build.rs b/objc_test_utils/build.rs index 7be34f363..1da9e08c1 100644 --- a/objc_test_utils/build.rs +++ b/objc_test_utils/build.rs @@ -1,4 +1,4 @@ -extern crate cc; +use cc; fn main() { cc::Build::new() diff --git a/objc_test_utils/src/lib.rs b/objc_test_utils/src/lib.rs index c3ec6b917..86c39d316 100644 --- a/objc_test_utils/src/lib.rs +++ b/objc_test_utils/src/lib.rs @@ -2,11 +2,17 @@ #![crate_type = "lib"] /// A block that takes no arguments and returns an integer: `int32_t (^)()`. -pub enum IntBlock {} +#[repr(C)] +pub struct IntBlock { + _priv: [u8; 0], +} /// A block that takes one integer argument, adds to it, and returns the sum: /// `int32_t (^)(int32_t)`. -pub enum AddBlock {} +#[repr(C)] +pub struct AddBlock { + _priv: [u8; 0], +} extern "C" { /// Returns a pointer to a global `IntBlock` that returns 7. From bbf3a4ea5a499f6c67bfb4245f74ff6b2436ecb0 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 16:29:26 +0200 Subject: [PATCH 122/125] Implement RefEncode for Block and ConcreteBlock This also adds A: EncodeArguments and R: Encode bounds on blocks, which is a good idea to require given that the types are being sent to and from Objective-C! --- objc_block/Cargo.toml | 3 +++ objc_block/src/lib.rs | 27 ++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/objc_block/Cargo.toml b/objc_block/Cargo.toml index 6772e6694..bf9056a55 100644 --- a/objc_block/Cargo.toml +++ b/objc_block/Cargo.toml @@ -20,5 +20,8 @@ exclude = [ "tests-ios/**", ] +[dependencies] +objc-encode = { path = "../objc_encode", version = "1.1.0" } + [dev-dependencies] objc_test_utils = { path = "../objc_test_utils", version = "0.0" } diff --git a/objc_block/src/lib.rs b/objc_block/src/lib.rs index 5e2713432..ae0338cf4 100644 --- a/objc_block/src/lib.rs +++ b/objc_block/src/lib.rs @@ -54,6 +54,8 @@ use std::ops::{Deref, DerefMut}; use std::os::raw::{c_int, c_ulong, c_void}; use std::ptr; +use objc_encode::{Encode, EncodeArguments, Encoding, RefEncode}; + // TODO: Replace with `objc::Class` #[repr(C)] struct ClassInternal { @@ -156,10 +158,11 @@ pub struct Block { _base: PhantomData>, } -impl Block -where - A: BlockArguments, -{ +unsafe impl RefEncode for Block { + const ENCODING_REF: Encoding<'static> = Encoding::Block; +} + +impl Block { /// Call self with the given arguments. /// /// # Safety @@ -226,12 +229,9 @@ impl Drop for RcBlock { } /// Types that may be converted into a `ConcreteBlock`. -pub trait IntoConcreteBlock: Sized -where - A: BlockArguments, -{ +pub trait IntoConcreteBlock: Sized { /// The return type of the resulting `ConcreteBlock`. - type Ret; + type Ret: Encode; /// Consumes self to create a `ConcreteBlock`. fn into_concrete_block(self) -> ConcreteBlock; @@ -242,7 +242,7 @@ macro_rules! concrete_block_impl { concrete_block_impl!($f,); ); ($f:ident, $($a:ident : $t:ident),*) => ( - impl<$($t,)* R, X> IntoConcreteBlock<($($t,)*)> for X + impl<$($t: Encode,)* R: Encode, X> IntoConcreteBlock<($($t,)*)> for X where X: Fn($($t,)*) -> R { type Ret = R; @@ -364,9 +364,14 @@ pub struct ConcreteBlock { closure: F, } +unsafe impl RefEncode for ConcreteBlock { + const ENCODING_REF: Encoding<'static> = Encoding::Block; +} + impl ConcreteBlock where - A: BlockArguments, + A: BlockArguments + EncodeArguments, + R: Encode, F: IntoConcreteBlock, { /// Constructs a `ConcreteBlock` with the given closure. From 2e71917fd199b3ee6a38eba9abe2ffd588934a5f Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 16:35:58 +0200 Subject: [PATCH 123/125] Make objc_block closer to no_std --- objc_block/src/lib.rs | 22 ++++++++++++++++------ objc_test_utils/Cargo.toml | 1 + objc_test_utils/src/lib.rs | 3 +-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/objc_block/src/lib.rs b/objc_block/src/lib.rs index ae0338cf4..3a81222f2 100644 --- a/objc_block/src/lib.rs +++ b/objc_block/src/lib.rs @@ -45,14 +45,21 @@ to be copied once, and we can enforce this in Rust, but if Objective-C code were to copy it twice we could have a double free. */ +#![no_std] + +extern crate alloc; +extern crate std; + #[cfg(test)] mod test_utils; -use std::marker::PhantomData; -use std::mem; -use std::ops::{Deref, DerefMut}; -use std::os::raw::{c_int, c_ulong, c_void}; -use std::ptr; +use alloc::boxed::Box; +use core::ffi::c_void; +use core::marker::PhantomData; +use core::mem; +use core::ops::{Deref, DerefMut}; +use core::ptr; +use std::os::raw::{c_int, c_ulong}; use objc_encode::{Encode, EncodeArguments, Encoding, RefEncode}; @@ -364,7 +371,9 @@ pub struct ConcreteBlock { closure: F, } -unsafe impl RefEncode for ConcreteBlock { +unsafe impl RefEncode + for ConcreteBlock +{ const ENCODING_REF: Encoding<'static> = Encoding::Block; } @@ -476,6 +485,7 @@ impl BlockDescriptor { mod tests { use super::{ConcreteBlock, RcBlock}; use crate::test_utils::*; + use alloc::string::ToString; #[test] fn test_call_block() { diff --git a/objc_test_utils/Cargo.toml b/objc_test_utils/Cargo.toml index 8a1154b12..7b906a7a4 100644 --- a/objc_test_utils/Cargo.toml +++ b/objc_test_utils/Cargo.toml @@ -8,6 +8,7 @@ description = "Utilities for testing Objective-C interop." keywords = ["objective-c", "macos", "ios", "testing"] categories = [ "development-tools::ffi", + "no-std", "development-tools::testing", "os::macos-apis", ] diff --git a/objc_test_utils/src/lib.rs b/objc_test_utils/src/lib.rs index 86c39d316..d1b9efa8a 100644 --- a/objc_test_utils/src/lib.rs +++ b/objc_test_utils/src/lib.rs @@ -1,5 +1,4 @@ -#![crate_name = "objc_test_utils"] -#![crate_type = "lib"] +#![no_std] /// A block that takes no arguments and returns an integer: `int32_t (^)()`. #[repr(C)] From 4c453dd51784ad83fb736867427cfaffa3df55e0 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 16:36:57 +0200 Subject: [PATCH 124/125] Don't depend on objc in objc_encode It's also actually nicer to have examples that use the current crate! --- objc_encode/Cargo.toml | 3 --- objc_encode/README.md | 4 ++-- objc_encode/examples/core_graphics.rs | 2 +- objc_encode/examples/ns_string.rs | 2 +- objc_encode/examples/ns_uinteger.rs | 2 +- objc_encode/examples/opaque_type.rs | 2 +- objc_foundation_derive/src/lib.rs | 1 - 7 files changed, 6 insertions(+), 10 deletions(-) diff --git a/objc_encode/Cargo.toml b/objc_encode/Cargo.toml index d4673c045..40de8a601 100644 --- a/objc_encode/Cargo.toml +++ b/objc_encode/Cargo.toml @@ -17,6 +17,3 @@ readme = "README.md" repository = "https://github.com/madsmtm/objc" documentation = "https://docs.rs/objc-encode/" license = "MIT" - -[dev-dependencies] -objc = { path = "../objc", version = "0.2.7" } diff --git a/objc_encode/README.md b/objc_encode/README.md index 72287d5d8..3f08c9900 100644 --- a/objc_encode/README.md +++ b/objc_encode/README.md @@ -51,7 +51,7 @@ An `Encoding` can be compared with an encoding string from the Objective-C runtime: ```rust -use objc::Encode; +use objc_encode::Encode; assert!(&i32::ENCODING == "i"); ``` @@ -59,7 +59,7 @@ assert!(&i32::ENCODING == "i"); generated conveniently through the `to_string` method: ```rust -use objc::Encode; +use objc_encode::Encode; assert_eq!(i32::ENCODING.to_string(), "i"); ``` diff --git a/objc_encode/examples/core_graphics.rs b/objc_encode/examples/core_graphics.rs index 611579e73..ed2f7c85a 100644 --- a/objc_encode/examples/core_graphics.rs +++ b/objc_encode/examples/core_graphics.rs @@ -1,4 +1,4 @@ -use objc::{Encode, Encoding}; +use objc_encode::{Encode, Encoding}; #[cfg(target_pointer_width = "32")] type CGFloat = f32; diff --git a/objc_encode/examples/ns_string.rs b/objc_encode/examples/ns_string.rs index afc890424..a1c250f0f 100644 --- a/objc_encode/examples/ns_string.rs +++ b/objc_encode/examples/ns_string.rs @@ -1,4 +1,4 @@ -use objc::{Encode, Encoding, RefEncode}; +use objc_encode::{Encode, Encoding, RefEncode}; /// We don't know the size of NSString, so we can only hold pointers to it. /// diff --git a/objc_encode/examples/ns_uinteger.rs b/objc_encode/examples/ns_uinteger.rs index 0473deecf..929d18517 100644 --- a/objc_encode/examples/ns_uinteger.rs +++ b/objc_encode/examples/ns_uinteger.rs @@ -2,7 +2,7 @@ //! //! Note that in this case `NSUInteger` could actually just be a type alias //! for `usize`. -use objc::{Encode, Encoding, RefEncode}; +use objc_encode::{Encode, Encoding, RefEncode}; #[repr(transparent)] struct NSUInteger { diff --git a/objc_encode/examples/opaque_type.rs b/objc_encode/examples/opaque_type.rs index 72df41460..48d9ad44b 100644 --- a/objc_encode/examples/opaque_type.rs +++ b/objc_encode/examples/opaque_type.rs @@ -1,5 +1,5 @@ //! Implementing `RefEncode` for `NSDecimal`. -use objc::{Encoding, RefEncode}; +use objc_encode::{Encoding, RefEncode}; /// We choose in this case to represent `NSDecimal` as an opaque struct /// (and in the future as an `extern type`) because we don't know much diff --git a/objc_foundation_derive/src/lib.rs b/objc_foundation_derive/src/lib.rs index cda8a4d9a..dc1a356ec 100644 --- a/objc_foundation_derive/src/lib.rs +++ b/objc_foundation_derive/src/lib.rs @@ -5,7 +5,6 @@ #[doc = include_str!("../README.md")] extern "C" {} - #[macro_use] extern crate quote; use syn; From 50704af24111807db2802ff62570e4d68b374b82 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 2 Sep 2021 16:44:57 +0200 Subject: [PATCH 125/125] Run CI on objc_foundation/block feature --- .github/workflows/ci.yml | 7 +++---- objc_foundation/Cargo.toml | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cdc72be24..399a51477 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,12 +120,11 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - # TODO: `objc_foundation/block` feature doesn't work args: --verbose --no-fail-fast --no-default-features - - name: Test w. exception and verify_message features + - name: Test with features uses: actions-rs/cargo@v1 with: command: test - # TODO: `objc_foundation/block` feature doesn't work - args: --verbose --no-fail-fast --no-default-features --features exception,verify_message + # Not using --all-features because some features are nightly-only + args: --verbose --no-fail-fast --features block,exception,verify_message diff --git a/objc_foundation/Cargo.toml b/objc_foundation/Cargo.toml index c9c8bf31d..8fcf11094 100644 --- a/objc_foundation/Cargo.toml +++ b/objc_foundation/Cargo.toml @@ -20,6 +20,7 @@ license = "MIT" default = ["block"] [dependencies] +# Feature provided as a way to cut down on dependencies block = { path = "../objc_block", optional = true, version = "0.1" } objc = { path = "../objc", version = "0.2.7" } objc_id = { path = "../objc_id", version = "0.1.1" }