| // Copyright (c) 2025, 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 'internal.dart'; | |
| import 'ns_array.dart'; | |
| import 'ns_date.dart'; | |
| import 'ns_dictionary.dart'; | |
| import 'ns_number.dart'; | |
| import 'ns_set.dart'; | |
| import 'ns_string.dart'; | |
| import 'objective_c_bindings_generated.dart'; | |
| ObjCObject _defaultObjCConverter(Object o) => | |
| throw UnimplementedError('No conversion for $o'); | |
| /// Converts a Dart object to the corresponding Objective C object. | |
| /// | |
| /// This supports basic types like `num` and `String`. It also works on | |
| /// collections, and recursively converts their elements. | |
| /// | |
| /// If [dartObject] is not one of the recognized types, [convertOther] is | |
| /// called. If [convertOther] is not provided, an error is thrown. | |
| ObjCObject toObjCObject( | |
| Object? dartObject, { | |
| ObjCObject Function(Object) convertOther = _defaultObjCConverter, | |
| }) => switch (dartObject) { | |
| null => NSNull.null$(), | |
| ObjCObject() => dartObject, | |
| bool() => dartObject.toNSNumber(), | |
| num() => dartObject.toNSNumber(), | |
| String() => dartObject.toNSString(), | |
| DateTime() => dartObject.toNSDate(), | |
| List<Object>() => dartObject.toNSArray(convertOther: convertOther), | |
| Set<Object>() => dartObject.toNSSet(convertOther: convertOther), | |
| Map<Object, Object>() => dartObject.toNSDictionary( | |
| convertOther: convertOther, | |
| ), | |
| _ => convertOther(dartObject), | |
| }; | |
| extension DartListToNSArray on List<Object> { | |
| NSArray toNSArray({ | |
| ObjCObject Function(Object) convertOther = _defaultObjCConverter, | |
| }) => NSArray.of(map((o) => toObjCObject(o, convertOther: convertOther))); | |
| } | |
| extension DartSetToNSSet on Set<Object> { | |
| NSSet toNSSet({ | |
| ObjCObject Function(Object) convertOther = _defaultObjCConverter, | |
| }) => NSSet.of(map((o) => toObjCObject(o, convertOther: convertOther))); | |
| } | |
| extension DartMapToNSDictionary on Map<Object, Object> { | |
| NSDictionary toNSDictionary({ | |
| ObjCObject Function(Object) convertOther = _defaultObjCConverter, | |
| }) => NSDictionary.fromEntries( | |
| entries.map( | |
| (kv) => MapEntry( | |
| toObjCObject(kv.key, convertOther: convertOther) as NSCopying, | |
| toObjCObject(kv.value, convertOther: convertOther), | |
| ), | |
| ), | |
| ); | |
| } | |
| Object _defaultDartConverter(ObjCObject o) => o; | |
| /// Converts a Objective C object to the corresponding Dart object. | |
| /// | |
| /// This supports basic types like `NSNumber` and `NSString`. It also works on | |
| /// collections, and recursively converts their elements. | |
| /// | |
| /// If [objCObject] is not one of the recognized types, [convertOther] is | |
| /// called. If [convertOther] is not provided, [objCObject] is returned | |
| /// directly. | |
| Object toDartObject( | |
| ObjCObject objCObject, { | |
| Object Function(ObjCObject) convertOther = _defaultDartConverter, | |
| }) { | |
| // A type-based switch, like in toObjCObject, won't work here because the | |
| // object could have a Dart runtime type of eg NSObject, even if the | |
| // underlying ObjC object that the Dart object is wrapping is a NSNumber. | |
| if (NSNumber.isA(objCObject)) { | |
| final nsNumber = NSNumber.as(objCObject); | |
| if (nsNumber.isBool) { | |
| return nsNumber.boolValue; | |
| } | |
| return nsNumber.numValue; | |
| } | |
| if (NSString.isA(objCObject)) { | |
| return NSString.as(objCObject).toDartString(); | |
| } | |
| if (NSDate.isA(objCObject)) { | |
| return NSDate.as(objCObject).toDateTime(); | |
| } | |
| if (NSArray.isA(objCObject)) { | |
| return NSArray.as(objCObject).toDartList(convertOther: convertOther); | |
| } | |
| if (NSSet.isA(objCObject)) { | |
| return NSSet.as(objCObject).toDartSet(convertOther: convertOther); | |
| } | |
| if (NSDictionary.isA(objCObject)) { | |
| return NSDictionary.as(objCObject).toDartMap(convertOther: convertOther); | |
| } | |
| return convertOther(objCObject); | |
| } | |
| /// Converts a Objective C object to the corresponding Dart object. | |
| /// | |
| /// See [toDartObject]. This method will additionally return `null` if passed an | |
| /// `NSNull`. | |
| Object? toNullableDartObject( | |
| ObjCObject objCObject, { | |
| Object Function(ObjCObject) convertOther = _defaultDartConverter, | |
| }) { | |
| if (NSNull.isA(objCObject)) { | |
| return null; | |
| } | |
| return toDartObject(objCObject, convertOther: convertOther); | |
| } | |
| extension NSArrayToDartList on NSArray { | |
| /// Deep converts this [NSArray] to a Dart [List]. | |
| /// | |
| /// This creates a new [List], converts all the [NSArray] elements, and adds | |
| /// them to the [List]. If you only need iteration and element access, | |
| /// [asDart] is much more efficient. | |
| List<Object> toDartList({ | |
| Object Function(ObjCObject) convertOther = _defaultDartConverter, | |
| }) => | |
| asDart().map((o) => toDartObject(o, convertOther: convertOther)).toList(); | |
| } | |
| extension NSSetToDartSet on NSSet { | |
| /// Deep converts this [NSSet] to a Dart [Set]. | |
| /// | |
| /// This creates a new [Set], converts all the [NSSet] elements, and adds | |
| /// them to the [Set]. If you only need iteration and element access, | |
| /// [asDart] is much more efficient. | |
| Set<Object> toDartSet({ | |
| Object Function(ObjCObject) convertOther = _defaultDartConverter, | |
| }) => | |
| asDart().map((o) => toDartObject(o, convertOther: convertOther)).toSet(); | |
| } | |
| extension NSDictionaryToDartMap on NSDictionary { | |
| /// Deep converts this [NSDictionary] to a Dart [Map]. | |
| /// | |
| /// This creates a new [Map], converts all the [NSDictionary] elements, and | |
| /// adds them to the [Map]. If you only need iteration and element access, | |
| /// [asDart] is much more efficient. | |
| Map<Object, Object> toDartMap({ | |
| Object Function(ObjCObject) convertOther = _defaultDartConverter, | |
| }) => Map.fromEntries( | |
| asDart().entries.map( | |
| (kv) => MapEntry( | |
| toDartObject(kv.key, convertOther: convertOther), | |
| toDartObject(kv.value, convertOther: convertOther), | |
| ), | |
| ), | |
| ); | |
| } |