// 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, num() => dartObject.toNSNumber(), String() => dartObject.toNSString(), DateTime() => dartObject.toNSDate(), List() => dartObject.toNSArray(convertOther: convertOther), Set() => dartObject.toNSSet(convertOther: convertOther), Map() => dartObject.toNSDictionary( convertOther: convertOther, ), _ => convertOther(dartObject), }; extension DartListToNSArray on List { NSArray toNSArray({ ObjCObject Function(Object) convertOther = _defaultObjCConverter, }) => NSArray.of(map((o) => toObjCObject(o, convertOther: convertOther))); } extension DartSetToNSSet on Set { NSSet toNSSet({ ObjCObject Function(Object) convertOther = _defaultObjCConverter, }) => NSSet.of(map((o) => toObjCObject(o, convertOther: convertOther))); } extension DartMapToNSDictionary on Map { 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)) { return NSNumber.as(objCObject).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 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 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 toDartMap({ Object Function(ObjCObject) convertOther = _defaultDartConverter, }) => Map.fromEntries( asDart().entries.map( (kv) => MapEntry( toDartObject(kv.key, convertOther: convertOther), toDartObject(kv.value, convertOther: convertOther), ), ), ); }