Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pigeon] Swift implementation for ProxyApis #6602

Merged
merged 130 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
af9b509
temp file for instance manager
bparrishMines Mar 28, 2024
a71727b
tests and some improvements
bparrishMines Apr 1, 2024
82211af
finish tests and some improvements
bparrishMines Apr 1, 2024
303b50f
add documentation and type arguments for getters
bparrishMines Apr 2, 2024
d87cb78
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 2, 2024
ed3da4b
change precondition to assert
bparrishMines Apr 2, 2024
52f81cc
add instancemanagerapi
bparrishMines Apr 2, 2024
65c1dfa
fix class names and implement codec
bparrishMines Apr 2, 2024
59dfe0e
finish test implementation
bparrishMines Apr 3, 2024
ee74764
fix name
bparrishMines Apr 3, 2024
05afe22
add convenience init and break some stuff
bparrishMines Apr 3, 2024
23f1338
remove retain cycle work
bparrishMines Apr 3, 2024
ae9f0fa
add teardown to codec
bparrishMines Apr 3, 2024
684fa86
fix api references
bparrishMines Apr 9, 2024
204815a
use safe names
bparrishMines Apr 9, 2024
cd1c31e
current code no retain cycle
bparrishMines Apr 10, 2024
8ca6118
improve tests and make some classes private
bparrishMines Apr 10, 2024
c0753ce
pass the calling api to the delegate
bparrishMines Apr 10, 2024
cbcdfeb
formatting
bparrishMines Apr 10, 2024
45d7425
use inner classes
bparrishMines Apr 10, 2024
7d18949
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 10, 2024
4b9be7f
change some class names
bparrishMines Apr 10, 2024
17b9463
change names again
bparrishMines Apr 10, 2024
3547d2f
start of implementation
bparrishMines Apr 11, 2024
a0db47f
add template
bparrishMines Apr 11, 2024
2c46e5e
get api math working
bparrishMines Apr 15, 2024
072e469
add imports and handle proxy api types
bparrishMines Apr 17, 2024
4a3adbd
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 17, 2024
452fe21
add generation of registrar and codec
bparrishMines Apr 18, 2024
952a09b
generate api delegatge
bparrishMines Apr 18, 2024
86bd465
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 18, 2024
b22028a
add setUPMessagehandler for constructors
bparrishMines Apr 23, 2024
8ea16d5
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 23, 2024
6308dc6
add proxy api generated file and fix channel suffix for host messages
bparrishMines Apr 23, 2024
399ff98
fix
bparrishMines Apr 23, 2024
84c6c7a
implementation of pigeonNewInstance
bparrishMines Apr 23, 2024
d44a62c
add other host method channel handlers
bparrishMines Apr 23, 2024
ee4ffdf
finish flutter methods
bparrishMines Apr 23, 2024
a974f7b
implement the apis
bparrishMines Apr 24, 2024
f52c9a7
compile and fix tests
bparrishMines Apr 24, 2024
d08fd27
add integration tests
bparrishMines Apr 24, 2024
b47f10a
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 24, 2024
f95e682
try publishing the plugin
bparrishMines Apr 24, 2024
b8e1ff0
only test on swift
bparrishMines Apr 24, 2024
e237475
move class declarations
bparrishMines Apr 24, 2024
b258d04
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Apr 24, 2024
eed62f9
update macos
bparrishMines Apr 24, 2024
6039d27
try with nullable test type args
bparrishMines Apr 24, 2024
702ecea
fix implementations
bparrishMines Apr 24, 2024
cdf155e
undo change i guess
bparrishMines Apr 24, 2024
410cac9
fix integration tests
bparrishMines Apr 24, 2024
5d2f968
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines May 29, 2024
6eba0ca
fix merge
bparrishMines May 29, 2024
f1b3f0a
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jun 12, 2024
226b506
fix the channel suffix code
bparrishMines Jun 12, 2024
c505697
fix analyze errors
bparrishMines Jun 13, 2024
b178edb
remove raw values from enums
bparrishMines Jun 13, 2024
559d709
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jun 13, 2024
0a54d3a
fix error names
bparrishMines Jun 13, 2024
7cd55bb
generate the api
bparrishMines Jun 14, 2024
2ea6db8
fix error macos error class
bparrishMines Jun 14, 2024
66fa54a
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jun 14, 2024
3975ed2
add some tools stuff
bparrishMines Jun 14, 2024
e6b4288
fix tests
bparrishMines Jun 14, 2024
6799a19
change variable name
bparrishMines Jun 14, 2024
1756e79
use format
bparrishMines Jun 15, 2024
280dd03
use convenience function for creating availablity
bparrishMines Jun 17, 2024
679f5ca
fix codec version check
bparrishMines Jun 17, 2024
2174fa1
verify api requirements
bparrishMines Jun 17, 2024
88d9a45
update macos
bparrishMines Jun 17, 2024
875e9b7
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jun 17, 2024
1c65d0b
analyze error
bparrishMines Jun 18, 2024
650061b
fix compilation
bparrishMines Jun 18, 2024
0893cef
can use a default implementation for apis without host method calls
bparrishMines Jun 18, 2024
c690050
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jun 18, 2024
f8c8635
add support for supporting specific oss
bparrishMines Jun 18, 2024
1158d6d
also check unattached methods
bparrishMines Jun 21, 2024
acbeae1
add a protocol for flutter methods
bparrishMines Jun 28, 2024
0eb1ace
update format
bparrishMines Jul 17, 2024
76b49c0
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jul 17, 2024
ebf77c8
some working tests
bparrishMines Jul 19, 2024
893c563
fix unit tests
bparrishMines Jul 19, 2024
73936e5
exit early in codec
bparrishMines Jul 19, 2024
28c057c
consistent prefix
bparrishMines Jul 19, 2024
d9803b2
write codec in generator
bparrishMines Jul 19, 2024
af7d3b2
fix tests and use file specfic prefix
bparrishMines Jul 19, 2024
0149834
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jul 19, 2024
44f78ec
fix swift tests
bparrishMines Jul 19, 2024
3a0647d
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jul 28, 2024
d85849e
update to check if type is builtin first
bparrishMines Jul 28, 2024
247ad5d
fix i think
bparrishMines Jul 29, 2024
a69d023
fix type check
bparrishMines Jul 29, 2024
71de011
also do enums
bparrishMines Jul 29, 2024
5f9f5d9
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jul 29, 2024
f202851
fix version test and add nil check
bparrishMines Jul 29, 2024
50cbfae
dont check for nil i guess
bparrishMines Jul 29, 2024
e19a34a
ignore calls to dart for swift
bparrishMines Jul 31, 2024
78a7726
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Jul 31, 2024
a256c11
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 15, 2024
d381d3a
fix tests and prefixes
bparrishMines Aug 15, 2024
b6be7e7
use onlye pigeon for instance manager
bparrishMines Aug 15, 2024
de8fddb
fix instancemanager name
bparrishMines Aug 16, 2024
d64e682
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 16, 2024
469024f
fix name actually this time
bparrishMines Aug 16, 2024
6b93a53
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 17, 2024
73aa72a
update api calls
bparrishMines Aug 17, 2024
5a35437
fix unit tests
bparrishMines Aug 17, 2024
28ab04a
fix instance manager tests
bparrishMines Aug 17, 2024
228bfb5
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 21, 2024
3f8dfa4
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 23, 2024
af4d3c6
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 26, 2024
168b868
use pigeon codec
bparrishMines Aug 29, 2024
9c4e668
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 29, 2024
ad38970
use var
bparrishMines Aug 29, 2024
97a102a
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 30, 2024
ad2c455
create set for test
bparrishMines Aug 30, 2024
d78d9c7
check not in
bparrishMines Aug 30, 2024
5094a31
remove trim flag
bparrishMines Aug 30, 2024
9e240a1
add spaces again
bparrishMines Aug 30, 2024
ac5ca82
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Aug 30, 2024
cf04c28
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Sep 11, 2024
205726e
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Sep 18, 2024
e379893
fix code gen probably
bparrishMines Sep 18, 2024
ed503d3
fix language name
bparrishMines Sep 18, 2024
7928362
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Sep 25, 2024
9cbe5c2
some imrovements
bparrishMines Sep 25, 2024
71e5949
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Sep 30, 2024
b1f1134
Merge branch 'main' of github.com:flutter/packages into pigeon_wrappe…
bparrishMines Oct 10, 2024
dbe4f16
add docs and add inherent indents
bparrishMines Oct 10, 2024
22e2312
change to xctunwrap
bparrishMines Oct 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 22.5.0

* [swift] Adds implementation for `@ProxyApi`.

## 22.4.2

* Updates `README.md` to replace the deprecated `flutter pub run pigeon` command with `dart run pigeon`.
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ This is what the temporary generated code that the _PigeonIsolate_ executes
looks like (see [State Diagram](#state-diagram)):

```dart
import 'path/to/supplied/pigeon/file.dart'
import 'path/to/supplied/pigeon/file.dart';
import 'dart:io';
import 'dart:isolate';
import 'package:pigeon/pigeon_lib.dart';
Expand Down
6 changes: 6 additions & 0 deletions packages/pigeon/lib/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
import 'generator_tools.dart';
import 'kotlin_generator.dart' show KotlinProxyApiOptions;
import 'pigeon_lib.dart';
import 'swift_generator.dart' show SwiftProxyApiOptions;

typedef _ListEquals = bool Function(List<Object?>, List<Object?>);

Expand Down Expand Up @@ -142,6 +143,7 @@ class AstProxyApi extends Api {
required this.fields,
this.superClass,
this.interfaces = const <TypeDeclaration>{},
this.swiftOptions,
this.kotlinOptions,
});

Expand All @@ -157,6 +159,10 @@ class AstProxyApi extends Api {
/// Name of the classes this class considers to be implemented.
Set<TypeDeclaration> interfaces;

/// Options that control how Swift code will be generated for a specific
/// ProxyApi.
final SwiftProxyApiOptions? swiftOptions;

/// Options that control how Kotlin code will be generated for a specific
/// ProxyApi.
final KotlinProxyApiOptions? kotlinOptions;
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'ast.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '22.4.2';
const String pigeonVersion = '22.5.0';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/pigeon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ export 'java_generator.dart' show JavaOptions;
export 'kotlin_generator.dart' show KotlinOptions, KotlinProxyApiOptions;
export 'objc_generator.dart' show ObjcOptions;
export 'pigeon_lib.dart';
export 'swift_generator.dart' show SwiftOptions;
export 'swift_generator.dart' show SwiftOptions, SwiftProxyApiOptions;
42 changes: 41 additions & 1 deletion packages/pigeon/lib/pigeon_lib.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'package:analyzer/error/error.dart' show AnalysisError;
import 'package:args/args.dart';
import 'package:collection/collection.dart' as collection;
import 'package:path/path.dart' as path;
import 'package:pub_semver/pub_semver.dart';

import 'ast.dart';
import 'ast_generator.dart';
Expand Down Expand Up @@ -139,7 +140,7 @@ class FlutterApi {
/// methods.
class ProxyApi {
/// Parametric constructor for [ProxyApi].
const ProxyApi({this.superClass, this.kotlinOptions});
const ProxyApi({this.superClass, this.kotlinOptions, this.swiftOptions});

/// The proxy api that is a super class to this one.
///
Expand All @@ -150,6 +151,10 @@ class ProxyApi {
/// with inherited method names.
final Type? superClass;

/// Options that control how Swift code will be generated for a specific
/// ProxyApi.
final SwiftProxyApiOptions? swiftOptions;

/// Options that control how Kotlin code will be generated for a specific
/// ProxyApi.
final KotlinProxyApiOptions? kotlinOptions;
Expand Down Expand Up @@ -1674,6 +1679,40 @@ class _RootBuilder extends dart_ast_visitor.RecursiveAstVisitor<Object?> {
}
}

SwiftProxyApiOptions? swiftOptions;
final Map<String, Object?>? swiftOptionsMap =
annotationMap['swiftOptions'] as Map<String, Object?>?;
if (swiftOptionsMap != null) {
swiftOptions = SwiftProxyApiOptions(
name: swiftOptionsMap['name'] as String?,
import: swiftOptionsMap['import'] as String?,
minIosApi: swiftOptionsMap['minIosApi'] as String?,
minMacosApi: swiftOptionsMap['minMacosApi'] as String?,
supportsIos: swiftOptionsMap['supportsIos'] as bool? ?? true,
supportsMacos: swiftOptionsMap['supportsMacos'] as bool? ?? true,
);
}

void tryParseApiRequirement(String? version) {
if (version == null) {
return;
}
try {
Version.parse(version);
} on FormatException catch (error) {
_errors.add(
Error(
message:
'Could not parse version: ${error.message}. Please use semantic versioning format: "1.2.3".',
lineNumber: _calculateLineNumber(source, node.offset),
),
);
}
}

tryParseApiRequirement(swiftOptions?.minIosApi);
tryParseApiRequirement(swiftOptions?.minMacosApi);

KotlinProxyApiOptions? kotlinOptions;
final Map<String, Object?>? kotlinOptionsMap =
annotationMap['kotlinOptions'] as Map<String, Object?>?;
Expand All @@ -1691,6 +1730,7 @@ class _RootBuilder extends dart_ast_visitor.RecursiveAstVisitor<Object?> {
fields: <ApiField>[],
superClass: superClass,
interfaces: interfaces,
swiftOptions: swiftOptions,
kotlinOptions: kotlinOptions,
documentationComments:
_documentationCommentsParser(node.documentationComment?.tokens),
Expand Down
256 changes: 256 additions & 0 deletions packages/pigeon/lib/swift/templates.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../generator_tools.dart';
import '../pigeon.dart';

/// Name of delegate that handles the callback when an object is deallocated
/// in an `InstanceManager`.
String instanceManagerFinalizerDelegateName(SwiftOptions options) =>
'${_instanceManagerFinalizerName(options)}Delegate';

/// The name of the registrar containing all the ProxyApi implementations.
String proxyApiRegistrarName(SwiftOptions options) =>
'${options.fileSpecificClassNameComponent ?? ''}${proxyApiClassNamePrefix}ProxyApiRegistrar';

/// The name of the `ReaderWriter` that handles ProxyApis.
String proxyApiReaderWriterName(SwiftOptions options) =>
'${options.fileSpecificClassNameComponent ?? ''}${classNamePrefix}ProxyApiCodecReaderWriter';

/// Name of the Swift `InstanceManager`.
String swiftInstanceManagerClassName(SwiftOptions options) =>
'${options.fileSpecificClassNameComponent ?? ''}${proxyApiClassNamePrefix}InstanceManager';

/// Template for delegate with callback when an object is deallocated.
String instanceManagerFinalizerDelegateTemplate(SwiftOptions options) => '''
/// Handles the callback when an object is deallocated.
protocol ${instanceManagerFinalizerDelegateName(options)}: AnyObject {
/// Invoked when the strong reference of an object is deallocated in an `InstanceManager`.
func onDeinit(identifier: Int64)
}

''';

/// Template for an object that tracks when an object is deallocated.
String instanceManagerFinalizerTemplate(SwiftOptions options) => '''
// Attaches to an object to receive a callback when the object is deallocated.
internal final class ${_instanceManagerFinalizerName(options)} {
private static let associatedObjectKey = malloc(1)!

private let identifier: Int64
// Reference to the delegate is weak because the callback should be ignored if the
// `InstanceManager` is deallocated.
private weak var delegate: ${instanceManagerFinalizerDelegateName(options)}?

private init(identifier: Int64, delegate: ${instanceManagerFinalizerDelegateName(options)}) {
self.identifier = identifier
self.delegate = delegate
}

internal static func attach(
to instance: AnyObject, identifier: Int64, delegate: ${instanceManagerFinalizerDelegateName(options)}
) {
let finalizer = ${_instanceManagerFinalizerName(options)}(identifier: identifier, delegate: delegate)
objc_setAssociatedObject(instance, associatedObjectKey, finalizer, .OBJC_ASSOCIATION_RETAIN)
}

static func detach(from instance: AnyObject) {
objc_setAssociatedObject(instance, associatedObjectKey, nil, .OBJC_ASSOCIATION_ASSIGN)
}

deinit {
delegate?.onDeinit(identifier: identifier)
}
}

''';

/// The Swift `InstanceManager`.
String instanceManagerTemplate(SwiftOptions options) {
return '''
/// Maintains instances used to communicate with the corresponding objects in Dart.
///
/// Objects stored in this container are represented by an object in Dart that is also stored in
/// an InstanceManager with the same identifier.
///
/// When an instance is added with an identifier, either can be used to retrieve the other.
///
/// Added instances are added as a weak reference and a strong reference. When the strong
/// reference is removed and the weak reference is deallocated,`${instanceManagerFinalizerDelegateName(options)}.onDeinit`
/// is called with the instance's identifier. However, if the strong reference is removed and then the identifier is
/// retrieved with the intention to pass the identifier to Dart (e.g. by calling `identifierWithStrongReference`),
/// the strong reference to the instance is re-added. The strong reference will then need to be removed manually
/// again.
///
/// Accessing and inserting to an InstanceManager is thread safe.
final class ${swiftInstanceManagerClassName(options)} {
// Identifiers are locked to a specific range to avoid collisions with objects
// created simultaneously from Dart.
// Host uses identifiers >= 2^16 and Dart is expected to use values n where,
// 0 <= n < 2^16.
private static let minHostCreatedIdentifier: Int64 = 65536

private let lockQueue = DispatchQueue(label: "${swiftInstanceManagerClassName(options)}")
private let identifiers: NSMapTable<AnyObject, NSNumber> = NSMapTable(
keyOptions: [.weakMemory, .objectPointerPersonality], valueOptions: .strongMemory)
private let weakInstances: NSMapTable<NSNumber, AnyObject> = NSMapTable(
keyOptions: .strongMemory, valueOptions: [.weakMemory, .objectPointerPersonality])
private let strongInstances: NSMapTable<NSNumber, AnyObject> = NSMapTable(
keyOptions: .strongMemory, valueOptions: [.strongMemory, .objectPointerPersonality])
private let finalizerDelegate: ${instanceManagerFinalizerDelegateName(options)}
private var nextIdentifier: Int64 = minHostCreatedIdentifier

public init(finalizerDelegate: ${instanceManagerFinalizerDelegateName(options)}) {
self.finalizerDelegate = finalizerDelegate
}

/// Adds a new instance that was instantiated from Dart.
///
/// The same instance can be added multiple times, but each identifier must be unique. This allows
/// two objects that are equivalent (e.g. conforms to `Equatable`) to both be added.
///
/// - Parameters:
/// - instance: the instance to be stored
/// - identifier: the identifier to be paired with instance. This value must be >= 0 and unique
func addDartCreatedInstance(_ instance: AnyObject, withIdentifier identifier: Int64) {
lockQueue.async {
self.addInstance(instance, withIdentifier: identifier)
}
}

/// Adds a new instance that was instantiated from the host platform.
///
/// - Parameters:
/// - instance: the instance to be stored. This must be unique to all other added instances.
/// - Returns: the unique identifier (>= 0) stored with instance
func addHostCreatedInstance(_ instance: AnyObject) -> Int64 {
assert(!containsInstance(instance), "Instance of \\(instance) has already been added.")
var identifier: Int64 = -1
lockQueue.sync {
identifier = nextIdentifier
nextIdentifier += 1
self.addInstance(instance, withIdentifier: identifier)
}
return identifier
}

/// Removes `instanceIdentifier` and its associated strongly referenced instance, if present, from the manager.
///
/// - Parameters:
/// - instanceIdentifier: the identifier paired to an instance.
/// - Returns: removed instance if the manager contains the given identifier, otherwise `nil` if
/// the manager doesn't contain the value
func removeInstance<T: AnyObject>(withIdentifier instanceIdentifier: Int64) throws -> T? {
var instance: AnyObject? = nil
lockQueue.sync {
instance = strongInstances.object(forKey: NSNumber(value: instanceIdentifier))
strongInstances.removeObject(forKey: NSNumber(value: instanceIdentifier))
}
return instance as? T
}

/// Retrieves the instance associated with identifier.
///
/// - Parameters:
/// - instanceIdentifier: the identifier associated with an instance
/// - Returns: the instance associated with `instanceIdentifier` if the manager contains the value, otherwise
/// `nil` if the manager doesn't contain the value
func instance<T: AnyObject>(forIdentifier instanceIdentifier: Int64) -> T? {
var instance: AnyObject? = nil
lockQueue.sync {
instance = weakInstances.object(forKey: NSNumber(value: instanceIdentifier))
}
return instance as? T
}

private func addInstance(_ instance: AnyObject, withIdentifier identifier: Int64) {
assert(identifier >= 0)
assert(
weakInstances.object(forKey: identifier as NSNumber) == nil,
"Identifier has already been added: \\(identifier)")
identifiers.setObject(NSNumber(value: identifier), forKey: instance)
weakInstances.setObject(instance, forKey: NSNumber(value: identifier))
strongInstances.setObject(instance, forKey: NSNumber(value: identifier))
${_instanceManagerFinalizerName(options)}.attach(to: instance, identifier: identifier, delegate: finalizerDelegate)
}

/// Retrieves the identifier paired with an instance.
///
/// If the manager contains a strong reference to `instance`, it will return the identifier
/// associated with `instance`. If the manager contains only a weak reference to `instance`, a new
/// strong reference to `instance` will be added and will need to be removed again with `removeInstance`.
///
/// If this method returns a nonnull identifier, this method also expects the Dart
/// `${swiftInstanceManagerClassName(options)}` to have, or recreate, a weak reference to the Dart instance the
/// identifier is associated with.
///
/// - Parameters:
/// - instance: an instance that may be stored in the manager
/// - Returns: the identifier associated with `instance` if the manager contains the value, otherwise
/// `nil` if the manager doesn't contain the value
func identifierWithStrongReference(forInstance instance: AnyObject) -> Int64? {
var identifier: Int64? = nil
lockQueue.sync {
if let existingIdentifier = identifiers.object(forKey: instance)?.int64Value {
strongInstances.setObject(instance, forKey: NSNumber(value: existingIdentifier))
identifier = existingIdentifier
}
}
return identifier
}

/// Whether this manager contains the given `instance`.
///
/// - Parameters:
/// - instance: the instance whose presence in this manager is to be tested
/// - Returns: whether this manager contains the given `instance`
func containsInstance(_ instance: AnyObject) -> Bool {
var containsInstance = false
lockQueue.sync {
containsInstance = identifiers.object(forKey: instance) != nil
}
return containsInstance
}

/// Removes all of the instances from this manager.
///
/// The manager will be empty after this call returns.
func removeAllObjects() throws {
lockQueue.sync {
identifiers.removeAllObjects()
weakInstances.removeAllObjects()
strongInstances.removeAllObjects()
nextIdentifier = ${swiftInstanceManagerClassName(options)}.minHostCreatedIdentifier
}
}

/// The number of instances stored as a strong reference.
///
/// For debugging and testing purposes.
internal var strongInstanceCount: Int {
var count: Int = 0
lockQueue.sync {
count = strongInstances.count
}
return count
}

/// The number of instances stored as a weak reference.
///
/// For debugging and testing purposes. NSMapTables that store keys or objects as weak
/// reference will be reclaimed non-deterministically.
internal var weakInstanceCount: Int {
var count: Int = 0
lockQueue.sync {
count = weakInstances.count
}
return count
}
}

''';
}

String _instanceManagerFinalizerName(SwiftOptions options) =>
'${options.fileSpecificClassNameComponent ?? ''}${classNamePrefix}Finalizer';
Loading