-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ffigen] Support ObjC objects in global variables (#1434)
- Loading branch information
1 parent
ca7e50c
commit 09a32e4
Showing
9 changed files
with
286 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
name: GlobalTestObjCLibrary | ||
description: 'Tests global variables' | ||
language: objc | ||
output: 'global_bindings.dart' | ||
exclude-all-by-default: true | ||
globals: | ||
include: | ||
- globalString | ||
- globalObject | ||
- globalBlock | ||
headers: | ||
entry-points: | ||
- 'global_test.h' | ||
preamble: | | ||
// ignore_for_file: camel_case_types, non_constant_identifier_names, unnecessary_non_null_assertion, unused_element, unused_field |
16 changes: 16 additions & 0 deletions
16
pkgs/ffigen/test/native_objc_test/global_native_config.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
name: GlobalTestObjCLibrary | ||
description: 'Tests global variables' | ||
language: objc | ||
output: 'global_native_bindings.dart' | ||
exclude-all-by-default: true | ||
ffi-native: | ||
globals: | ||
include: | ||
- globalString | ||
- globalObject | ||
- globalBlock | ||
headers: | ||
entry-points: | ||
- 'global_test.h' | ||
preamble: | | ||
// ignore_for_file: camel_case_types, non_constant_identifier_names, unnecessary_non_null_assertion, unused_element, unused_field |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
// Objective C support is only available on mac. | ||
@TestOn('mac-os') | ||
|
||
import 'dart:ffi'; | ||
import 'dart:io'; | ||
|
||
import 'package:objective_c/objective_c.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import '../test_utils.dart'; | ||
import 'global_native_bindings.dart'; | ||
import 'util.dart'; | ||
|
||
void main() { | ||
group('global using @Native', () { | ||
setUpAll(() { | ||
// TODO(https://github.com/dart-lang/native/issues/1068): Remove this. | ||
DynamicLibrary.open('../objective_c/test/objective_c.dylib'); | ||
final dylib = File('test/native_objc_test/global_native_test.dylib'); | ||
verifySetupFile(dylib); | ||
DynamicLibrary.open(dylib.absolute.path); | ||
generateBindingsForCoverage('global_native'); | ||
}); | ||
|
||
test('Global string', () { | ||
expect(globalString.toString(), 'Hello World'); | ||
globalString = 'Something else'.toNSString(); | ||
expect(globalString.toString(), 'Something else'); | ||
}); | ||
|
||
(Pointer<ObjCObject>, Pointer<ObjCObject>) globalObjectRefCountingInner() { | ||
final obj1 = NSObject.new1(); | ||
globalObject = obj1; | ||
final obj1raw = obj1.pointer; | ||
expect(objectRetainCount(obj1raw), 2); // obj1, and the global variable. | ||
|
||
final obj2 = NSObject.new1(); | ||
globalObject = obj2; | ||
final obj2raw = obj2.pointer; | ||
expect(objectRetainCount(obj2raw), 2); // obj2, and the global variable. | ||
expect(objectRetainCount(obj1raw), 1); // Just obj1. | ||
|
||
return (obj1raw, obj2raw); | ||
} | ||
|
||
test('Global object ref counting', () { | ||
final (obj1raw, obj2raw) = globalObjectRefCountingInner(); | ||
doGC(); | ||
|
||
expect(objectRetainCount(obj2raw), 1); // Just the global variable. | ||
expect(objectRetainCount(obj1raw), 0); | ||
|
||
globalObject = null; | ||
expect(objectRetainCount(obj2raw), 0); | ||
expect(objectRetainCount(obj1raw), 0); | ||
}); | ||
|
||
test('Global block', () { | ||
globalBlock = ObjCBlock_Int32_Int32.fromFunction((int x) => x * 10); | ||
expect(globalBlock!(123), 1230); | ||
globalBlock = ObjCBlock_Int32_Int32.fromFunction((int x) => x + 1000); | ||
expect(globalBlock!(456), 1456); | ||
}); | ||
|
||
(Pointer<ObjCBlock>, Pointer<ObjCBlock>) globalBlockRefCountingInner() { | ||
final blk1 = ObjCBlock_Int32_Int32.fromFunction((int x) => x * 10); | ||
globalBlock = blk1; | ||
final blk1raw = blk1.pointer; | ||
expect(blockRetainCount(blk1raw), 2); // blk1, and the global variable. | ||
|
||
final blk2 = ObjCBlock_Int32_Int32.fromFunction((int x) => x + 1000); | ||
globalBlock = blk2; | ||
final blk2raw = blk2.pointer; | ||
expect(blockRetainCount(blk2raw), 2); // blk2, and the global variable. | ||
expect(blockRetainCount(blk1raw), 1); // Just blk1. | ||
|
||
return (blk1raw, blk2raw); | ||
} | ||
|
||
test('Global block ref counting', () { | ||
final (blk1raw, blk2raw) = globalBlockRefCountingInner(); | ||
doGC(); | ||
|
||
expect(blockRetainCount(blk2raw), 1); // Just the global variable. | ||
expect(blockRetainCount(blk1raw), 0); | ||
|
||
globalBlock = null; | ||
expect(blockRetainCount(blk2raw), 0); | ||
expect(blockRetainCount(blk1raw), 0); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
#include "global_test.m" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
// Objective C support is only available on mac. | ||
@TestOn('mac-os') | ||
|
||
import 'dart:ffi'; | ||
import 'dart:io'; | ||
|
||
import 'package:objective_c/objective_c.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import '../test_utils.dart'; | ||
import 'global_bindings.dart'; | ||
import 'util.dart'; | ||
|
||
void main() { | ||
group('global', () { | ||
late GlobalTestObjCLibrary lib; | ||
|
||
setUpAll(() { | ||
// TODO(https://github.com/dart-lang/native/issues/1068): Remove this. | ||
DynamicLibrary.open('../objective_c/test/objective_c.dylib'); | ||
final dylib = File('test/native_objc_test/global_test.dylib'); | ||
verifySetupFile(dylib); | ||
lib = GlobalTestObjCLibrary(DynamicLibrary.open(dylib.absolute.path)); | ||
generateBindingsForCoverage('global'); | ||
}); | ||
|
||
test('Global string', () { | ||
expect(lib.globalString.toString(), 'Hello World'); | ||
lib.globalString = 'Something else'.toNSString(); | ||
expect(lib.globalString.toString(), 'Something else'); | ||
}); | ||
|
||
(Pointer<ObjCObject>, Pointer<ObjCObject>) globalObjectRefCountingInner() { | ||
final obj1 = NSObject.new1(); | ||
lib.globalObject = obj1; | ||
final obj1raw = obj1.pointer; | ||
expect(objectRetainCount(obj1raw), 2); // obj1, and the global variable. | ||
|
||
final obj2 = NSObject.new1(); | ||
lib.globalObject = obj2; | ||
final obj2raw = obj2.pointer; | ||
expect(objectRetainCount(obj2raw), 2); // obj2, and the global variable. | ||
expect(objectRetainCount(obj1raw), 1); // Just obj1. | ||
|
||
return (obj1raw, obj2raw); | ||
} | ||
|
||
test('Global object ref counting', () { | ||
final (obj1raw, obj2raw) = globalObjectRefCountingInner(); | ||
doGC(); | ||
|
||
expect(objectRetainCount(obj2raw), 1); // Just the global variable. | ||
expect(objectRetainCount(obj1raw), 0); | ||
|
||
lib.globalObject = null; | ||
expect(objectRetainCount(obj2raw), 0); | ||
expect(objectRetainCount(obj1raw), 0); | ||
}); | ||
|
||
test('Global block', () { | ||
lib.globalBlock = ObjCBlock_Int32_Int32.fromFunction((int x) => x * 10); | ||
expect(lib.globalBlock!(123), 1230); | ||
lib.globalBlock = ObjCBlock_Int32_Int32.fromFunction((int x) => x + 1000); | ||
expect(lib.globalBlock!(456), 1456); | ||
}); | ||
|
||
(Pointer<ObjCBlock>, Pointer<ObjCBlock>) globalBlockRefCountingInner() { | ||
final blk1 = ObjCBlock_Int32_Int32.fromFunction((int x) => x * 10); | ||
lib.globalBlock = blk1; | ||
final blk1raw = blk1.pointer; | ||
expect(blockRetainCount(blk1raw), 2); // blk1, and the global variable. | ||
|
||
final blk2 = ObjCBlock_Int32_Int32.fromFunction((int x) => x + 1000); | ||
lib.globalBlock = blk2; | ||
final blk2raw = blk2.pointer; | ||
expect(blockRetainCount(blk2raw), 2); // blk2, and the global variable. | ||
expect(blockRetainCount(blk1raw), 1); // Just blk1. | ||
|
||
return (blk1raw, blk2raw); | ||
} | ||
|
||
test('Global block ref counting', () { | ||
final (blk1raw, blk2raw) = globalBlockRefCountingInner(); | ||
doGC(); | ||
|
||
expect(blockRetainCount(blk2raw), 1); // Just the global variable. | ||
expect(blockRetainCount(blk1raw), 0); | ||
|
||
lib.globalBlock = null; | ||
expect(blockRetainCount(blk2raw), 0); | ||
expect(blockRetainCount(blk1raw), 0); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
#import <Foundation/NSObject.h> | ||
#import <Foundation/NSString.h> | ||
|
||
NSString* globalString; | ||
NSObject* _Nullable globalObject; | ||
int32_t (^_Nullable globalBlock)(int32_t); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
#import <Foundation/NSObject.h> | ||
|
||
#include "global_test.h" | ||
#include "util.h" | ||
|
||
NSString* globalString = @"Hello World"; | ||
NSObject* _Nullable globalObject = nil; | ||
int32_t (^_Nullable globalBlock)(int32_t) = nil; |