Skip to content

Commit 04c7443

Browse files
committed
Add tests for blocks taking/returning large structs
1 parent fb0b37e commit 04c7443

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ build = "build.rs"
1212
[dependencies]
1313
block2 = { path = "../block2" }
1414
block-sys = { path = "../block-sys" }
15+
objc2-encode = { path = "../objc2-encode" }
1516

1617
[build-dependencies]
1718
cc = "1.0"

tests/extern/block_utils.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
#include <stdint.h>
22
#include <Block.h>
33

4+
typedef struct {
5+
float x;
6+
uint8_t y[100];
7+
} LargeStruct;
8+
49
typedef int32_t (^IntBlock)();
510
typedef int32_t (^AddBlock)(int32_t);
11+
typedef LargeStruct (^LargeStructBlock)(LargeStruct);
612

713
IntBlock get_int_block() {
814
return ^{ return (int32_t)7; };
@@ -27,3 +33,23 @@ int32_t invoke_int_block(IntBlock block) {
2733
int32_t invoke_add_block(AddBlock block, int32_t a) {
2834
return block(a);
2935
}
36+
37+
LargeStructBlock get_large_struct_block() {
38+
return ^(LargeStruct s) {
39+
s.x -= 1.0;
40+
s.y[12] += 1;
41+
s.y[99] = 123;
42+
return s;
43+
};
44+
}
45+
46+
LargeStructBlock get_large_struct_block_with(LargeStruct a) {
47+
return Block_copy(^(LargeStruct s) {
48+
(void)s; // Unused
49+
return a;
50+
});
51+
}
52+
53+
LargeStruct invoke_large_struct_block(LargeStructBlock block, LargeStruct s) {
54+
return block(s);
55+
}

tests/src/ffi.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use objc2_encode::{Encode, Encoding};
2+
13
/// A block that takes no arguments and returns an integer: `int32_t (^)()`.
24
#[repr(C)]
35
pub struct IntBlock {
@@ -11,6 +13,37 @@ pub struct AddBlock {
1113
_priv: [u8; 0],
1214
}
1315

16+
#[repr(C)]
17+
#[derive(Debug, Clone, Copy, PartialEq)]
18+
pub struct LargeStruct {
19+
pub x: f32,
20+
pub y: [u8; 100],
21+
}
22+
23+
impl LargeStruct {
24+
pub fn get() -> Self {
25+
let mut y = [10; 100];
26+
y[42] = 123;
27+
Self { x: 5.0, y }
28+
}
29+
30+
pub fn mutate(&mut self) {
31+
self.x -= 1.0;
32+
self.y[12] += 1;
33+
self.y[99] = 123;
34+
}
35+
}
36+
37+
unsafe impl Encode for LargeStruct {
38+
const ENCODING: Encoding<'static> =
39+
Encoding::Struct("LargeStruct", &[f32::ENCODING, <[u8; 100]>::ENCODING]);
40+
}
41+
42+
#[repr(C)]
43+
pub struct LargeStructBlock {
44+
_priv: [u8; 0],
45+
}
46+
1447
extern "C" {
1548
/// Returns a pointer to a global `IntBlock` that returns 7.
1649
pub fn get_int_block() -> *mut IntBlock;
@@ -24,6 +57,10 @@ extern "C" {
2457
pub fn invoke_int_block(block: *mut IntBlock) -> i32;
2558
/// Invokes an `AddBlock` with `a` and returns the result.
2659
pub fn invoke_add_block(block: *mut AddBlock, a: i32) -> i32;
60+
61+
pub fn get_large_struct_block() -> *mut LargeStructBlock;
62+
pub fn get_large_struct_block_with(i: LargeStruct) -> *mut LargeStructBlock;
63+
pub fn invoke_large_struct_block(block: *mut LargeStructBlock, s: LargeStruct) -> LargeStruct;
2764
}
2865

2966
#[cfg(test)]
@@ -45,4 +82,20 @@ mod tests {
4582
assert_eq!(invoke_add_block(get_add_block_with(3), 5), 8);
4683
}
4784
}
85+
86+
#[test]
87+
fn test_large_struct_block() {
88+
let data = LargeStruct::get();
89+
let mut expected = data.clone();
90+
expected.mutate();
91+
92+
assert_eq!(
93+
unsafe { invoke_large_struct_block(get_large_struct_block(), data) },
94+
expected
95+
);
96+
assert_eq!(
97+
unsafe { invoke_large_struct_block(get_large_struct_block_with(expected), data) },
98+
expected
99+
);
100+
}
48101
}

tests/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use block2::{Block, RcBlock};
88
extern crate alloc;
99

1010
pub mod ffi;
11+
use crate::ffi::LargeStruct;
1112

1213
pub fn get_int_block_with(i: i32) -> RcBlock<(), i32> {
1314
unsafe {
@@ -33,6 +34,14 @@ pub fn invoke_add_block(block: &Block<(i32,), i32>, a: i32) -> i32 {
3334
unsafe { ffi::invoke_add_block(ptr as *mut _, a) }
3435
}
3536

37+
pub fn invoke_large_struct_block(
38+
block: &Block<(LargeStruct,), LargeStruct>,
39+
x: LargeStruct,
40+
) -> LargeStruct {
41+
let ptr = block as *const _;
42+
unsafe { ffi::invoke_large_struct_block(ptr as *mut _, x) }
43+
}
44+
3645
#[cfg(test)]
3746
mod tests {
3847
use super::*;
@@ -103,4 +112,30 @@ mod tests {
103112
let block = make_block();
104113
assert_eq!(invoke_int_block(&block), 7);
105114
}
115+
116+
#[test]
117+
fn test_large_struct_block() {
118+
global_block! {
119+
static BLOCK = |data: LargeStruct| -> LargeStruct {
120+
let mut data = data;
121+
data.mutate();
122+
data
123+
}
124+
}
125+
126+
let data = LargeStruct::get();
127+
let mut new_data = data.clone();
128+
new_data.mutate();
129+
130+
assert_eq!(unsafe { BLOCK.call((data,)) }, new_data);
131+
assert_eq!(invoke_large_struct_block(&BLOCK, data), new_data);
132+
133+
let block = ConcreteBlock::new(|mut x: LargeStruct| {
134+
x.mutate();
135+
x
136+
});
137+
assert_eq!(invoke_large_struct_block(&block, data), new_data);
138+
let block = block.copy();
139+
assert_eq!(invoke_large_struct_block(&block, data), new_data);
140+
}
106141
}

0 commit comments

Comments
 (0)