@@ -11,14 +11,16 @@ import 'writer.dart';
11
11
12
12
class ObjCBlock extends BindingType {
13
13
final Type returnType;
14
- final List <Type > argTypes;
14
+ final List <Parameter > params;
15
+ final bool returnsRetained;
15
16
Func ? _wrapListenerBlock;
16
17
17
18
factory ObjCBlock ({
18
19
required Type returnType,
19
- required List <Type > argTypes,
20
+ required List <Parameter > params,
21
+ required bool returnsRetained,
20
22
}) {
21
- final usr = _getBlockUsr (returnType, argTypes );
23
+ final usr = _getBlockUsr (returnType, params, returnsRetained );
22
24
23
25
final oldBlock = bindingsIndex.getSeenObjCBlock (usr);
24
26
if (oldBlock != null ) {
@@ -27,9 +29,10 @@ class ObjCBlock extends BindingType {
27
29
28
30
final block = ObjCBlock ._(
29
31
usr: usr,
30
- name: _getBlockName (returnType, argTypes ),
32
+ name: _getBlockName (returnType, params. map ((a) => a.type) ),
31
33
returnType: returnType,
32
- argTypes: argTypes,
34
+ params: params,
35
+ returnsRetained: returnsRetained,
33
36
);
34
37
bindingsIndex.addObjCBlockToSeen (usr, block);
35
38
@@ -40,48 +43,54 @@ class ObjCBlock extends BindingType {
40
43
required String super .usr,
41
44
required super .name,
42
45
required this .returnType,
43
- required this .argTypes,
46
+ required this .params,
47
+ required this .returnsRetained,
44
48
}) : super (originalName: name);
45
49
46
50
// Generates a human readable name for the block based on the args and return
47
51
// type. These names will be pretty verbose and unweildy, but they're at least
48
52
// sensible and stable. Users can always add their own typedef with a simpler
49
53
// name if necessary.
50
- static String _getBlockName (Type returnType, List <Type > argTypes) =>
54
+ static String _getBlockName (Type returnType, Iterable <Type > argTypes) =>
51
55
'ObjCBlock_${[returnType , ...argTypes ].map (_typeName ).join ('_' )}' ;
52
56
static String _typeName (Type type) =>
53
57
type.toString ().replaceAll (_illegalNameChar, '' );
54
58
static final _illegalNameChar = RegExp (r'[^0-9a-zA-Z]' );
55
59
56
- static String _getBlockUsr (Type returnType, List <Type > argTypes) {
60
+ static String _getBlockUsr (
61
+ Type returnType, List <Parameter > params, bool returnsRetained) {
57
62
// Create a fake USR code for the block. This code is used to dedupe blocks
58
- // with the same signature.
63
+ // with the same signature. Not intended to be human readable.
59
64
final usr = StringBuffer ();
60
- usr.write ('objcBlock: ${returnType .cacheKey ()}' );
61
- for (final type in argTypes) {
62
- usr.write (' ${type .cacheKey ()}' );
65
+ usr.write (
66
+ 'objcBlock: ${returnType .cacheKey ()} ${returnsRetained ? 'R' : '' }' );
67
+ for (final param in params) {
68
+ usr.write (' ${param .type .cacheKey ()} ${param .objCConsumed ? 'C' : '' }' );
63
69
}
64
70
return usr.toString ();
65
71
}
66
72
67
73
bool get hasListener => returnType == voidType;
68
74
69
75
String _blockType (Writer w) {
70
- final args = argTypes.map ((t) => t.getObjCBlockSignatureType (w)).join (', ' );
71
- final func = '${returnType .getObjCBlockSignatureType (w )} Function($args )' ;
76
+ final argStr = params.map ((param) {
77
+ final type = param.type.getObjCBlockSignatureType (w);
78
+ return param.objCConsumed
79
+ ? '${ObjCBuiltInFunctions .consumedType .gen (w )}<$type >'
80
+ : type;
81
+ }).join (', ' );
82
+ final retType = returnType.getObjCBlockSignatureType (w);
83
+ final retStr = returnsRetained
84
+ ? '${ObjCBuiltInFunctions .retainedType .gen (w )}<$retType >'
85
+ : retType;
86
+ final func = '$retStr Function($argStr )' ;
72
87
return '${ObjCBuiltInFunctions .blockType .gen (w )}<$func >' ;
73
88
}
74
89
75
90
@override
76
91
BindingString toBindingString (Writer w) {
77
92
final s = StringBuffer ();
78
93
79
- final params = < Parameter > [];
80
- for (var i = 0 ; i < argTypes.length; ++ i) {
81
- params.add (
82
- Parameter (name: 'arg$i ' , type: argTypes[i], objCConsumed: false ));
83
- }
84
-
85
94
final voidPtr = PointerType (voidType).getCType (w);
86
95
final blockPtr = PointerType (objCBlockType);
87
96
final funcType = FunctionType (returnType: returnType, parameters: params);
@@ -135,12 +144,18 @@ $returnFfiDartType $closureTrampoline($blockCType block, $paramsFfiDartType) =>
135
144
// Snippet that converts a Dart typed closure to FfiDart type. This snippet
136
145
// is used below. Note that the closure being converted is called `fn`.
137
146
final convertedFnArgs = params
138
- .map ((p) =>
139
- p.type.convertFfiDartTypeToDartType (w, p.name, objCRetain: true ))
147
+ .map ((p) => p.type.convertFfiDartTypeToDartType (
148
+ w,
149
+ p.name,
150
+ objCRetain: ! p.objCConsumed,
151
+ ))
140
152
.join (', ' );
141
153
final convFnInvocation = returnType.convertDartTypeToFfiDartType (
142
- w, 'fn($convertedFnArgs )' ,
143
- objCRetain: true );
154
+ w,
155
+ 'fn($convertedFnArgs )' ,
156
+ objCRetain: true ,
157
+ objCAutorelease: ! returnsRetained,
158
+ );
144
159
final convFn = '($paramsFfiDartType ) => $convFnInvocation ' ;
145
160
146
161
// Write the wrapper class.
@@ -183,16 +198,19 @@ abstract final class $name {
183
198
184
199
// Listener block constructor is only available for void blocks.
185
200
if (hasListener) {
186
- // This snippet is the same as the convFn above, except that the args
201
+ // This snippet is the same as the convFn above, except that the params
187
202
// don't need to be retained because they've already been retained by
188
203
// _wrapListenerBlock.
189
204
final listenerConvertedFnArgs = params
190
205
.map ((p) =>
191
206
p.type.convertFfiDartTypeToDartType (w, p.name, objCRetain: false ))
192
207
.join (', ' );
193
208
final listenerConvFnInvocation = returnType.convertDartTypeToFfiDartType (
194
- w, 'fn($listenerConvertedFnArgs )' ,
195
- objCRetain: true );
209
+ w,
210
+ 'fn($listenerConvertedFnArgs )' ,
211
+ objCRetain: true ,
212
+ objCAutorelease: ! returnsRetained,
213
+ );
196
214
final listenerConvFn =
197
215
'($paramsFfiDartType ) => $listenerConvFnInvocation ' ;
198
216
final wrapFn = _wrapListenerBlock? .name;
@@ -236,14 +254,21 @@ abstract final class $name {
236
254
extension $callExtension on $blockType {
237
255
${returnType .getDartType (w )} call($paramsDartType ) =>''' );
238
256
final callMethodArgs = params
239
- .map ((p) =>
240
- p.type.convertDartTypeToFfiDartType (w, p.name, objCRetain: false ))
257
+ .map ((p) => p.type.convertDartTypeToFfiDartType (
258
+ w,
259
+ p.name,
260
+ objCRetain: p.objCConsumed,
261
+ objCAutorelease: false ,
262
+ ))
241
263
.join (', ' );
242
264
final callMethodInvocation = '''
243
265
ref.pointer.ref.invoke.cast<$natTrampFnType >().asFunction<$trampFuncFfiDartType >()(
244
266
ref.pointer, $callMethodArgs )''' ;
245
- s.write (returnType.convertFfiDartTypeToDartType (w, callMethodInvocation,
246
- objCRetain: false ));
267
+ s.write (returnType.convertFfiDartTypeToDartType (
268
+ w,
269
+ callMethodInvocation,
270
+ objCRetain: ! returnsRetained,
271
+ ));
247
272
s.write (';\n ' );
248
273
249
274
s.write ('}\n\n ' );
@@ -257,11 +282,11 @@ ref.pointer.ref.invoke.cast<$natTrampFnType>().asFunction<$trampFuncFfiDartType>
257
282
258
283
final argsReceived = < String > [];
259
284
final retains = < String > [];
260
- for (var i = 0 ; i < argTypes .length; ++ i) {
261
- final t = argTypes [i];
285
+ for (var i = 0 ; i < params .length; ++ i) {
286
+ final param = params [i];
262
287
final argName = 'arg$i ' ;
263
- argsReceived.add (t .getNativeType (varName: argName));
264
- retains.add (t .generateRetain (argName) ?? argName);
288
+ argsReceived.add (param .getNativeType (varName: argName));
289
+ retains.add (param.type .generateRetain (argName) ?? argName);
265
290
}
266
291
final fnName = _wrapListenerBlock! .name;
267
292
final blockTypedef = w.objCLevelUniqueNamer.makeUnique ('ListenerBlock' );
@@ -286,11 +311,11 @@ $blockTypedef $fnName($blockTypedef block) NS_RETURNS_RETAINED {
286
311
dependencies.add (this );
287
312
288
313
returnType.addDependencies (dependencies);
289
- for (final t in argTypes ) {
290
- t .addDependencies (dependencies);
314
+ for (final p in params ) {
315
+ p.type .addDependencies (dependencies);
291
316
}
292
317
293
- if (hasListener && argTypes .any ((t ) => t .generateRetain ('' ) != null )) {
318
+ if (hasListener && params .any ((p ) => p.type .generateRetain ('' ) != null )) {
294
319
_wrapListenerBlock = Func (
295
320
name: 'wrapListenerBlock_$name ' ,
296
321
returnType: this ,
@@ -318,8 +343,8 @@ $blockTypedef $fnName($blockTypedef block) NS_RETURNS_RETAINED {
318
343
319
344
@override
320
345
String getNativeType ({String varName = '' }) {
321
- final args = argTypes .map <String >((t ) => t .getNativeType ());
322
- return '${returnType .getNativeType ()} (^$varName )(${args .join (', ' )})' ;
346
+ final paramStrs = params .map <String >((p ) => p .getNativeType ());
347
+ return '${returnType .getNativeType ()} (^$varName )(${paramStrs .join (', ' )})' ;
323
348
}
324
349
325
350
@override
@@ -336,8 +361,9 @@ $blockTypedef $fnName($blockTypedef block) NS_RETURNS_RETAINED {
336
361
Writer w,
337
362
String value, {
338
363
required bool objCRetain,
364
+ required bool objCAutorelease,
339
365
}) =>
340
- ObjCInterface .generateGetId (value, objCRetain);
366
+ ObjCInterface .generateGetId (value, objCRetain, objCAutorelease );
341
367
342
368
@override
343
369
String convertFfiDartTypeToDartType (
@@ -352,5 +378,6 @@ $blockTypedef $fnName($blockTypedef block) NS_RETURNS_RETAINED {
352
378
String ? generateRetain (String value) => 'objc_retainBlock($value )' ;
353
379
354
380
@override
355
- String toString () => '($returnType (^)(${argTypes .join (', ' )}))' ;
381
+ String toString () =>
382
+ '($returnType (^)(${params .map ((p ) => p .type .toString ()).join (', ' )}))' ;
356
383
}
0 commit comments