Newer
Older
bremer-ios-app / Pods / RealmSwift / RealmSwift / Impl / ObjcBridgeable.swift
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2021 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

import Foundation
import Realm

/// A type which can be bridged to and from Objective-C.
///
/// Do not use this protocol or the functions it adds directly.
public protocol _ObjcBridgeable {
    static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Self?
    var _rlmObjcValue: Any { get }
}
/// A type where the default logic suffices for bridging and we don't need to do anything special.
internal protocol DefaultObjcBridgeable: _ObjcBridgeable {}
extension DefaultObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Self? { value as? Self }
    public var _rlmObjcValue: Any { self }
}
/// A type which needs custom logic, but doesn't care if it's being bridged inside an Optional
internal protocol BuiltInObjcBridgeable: _ObjcBridgeable {
    static func _rlmFromObjc(_ value: Any) -> Self?
}
extension BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Self? {
        return _rlmFromObjc(value)
    }
}

extension Bool: DefaultObjcBridgeable {}
extension Int: DefaultObjcBridgeable {}
extension Double: DefaultObjcBridgeable {}
extension Date: DefaultObjcBridgeable {}
extension String: DefaultObjcBridgeable {}
extension Data: DefaultObjcBridgeable {}
extension ObjectId: DefaultObjcBridgeable {}
extension UUID: DefaultObjcBridgeable {}
extension NSNumber: DefaultObjcBridgeable {}
extension NSDate: DefaultObjcBridgeable {}

extension ObjectBase: BuiltInObjcBridgeable {
    public class func _rlmFromObjc(_ value: Any) -> Self? {
        if let value = value as? Self {
            return value
        }
        if Self.self === DynamicObject.self, let object = value as? ObjectBase {
            // Without `as AnyObject` this will produce a warning which incorrectly
            // claims it could be replaced with `unsafeDowncast()`
            return unsafeBitCast(object as AnyObject, to: Self.self)
        }
        return nil
    }
    public var _rlmObjcValue: Any { self }
}

// `NSNumber as? T` coerces values which can't be exact represented for some
// types and fails for others. We want to always coerce, for backwards
// compatibility if nothing else.
extension Float: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        return (value as? NSNumber)?.floatValue
    }
    public var _rlmObjcValue: Any {
        return NSNumber(value: self)
    }
}
extension Int8: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        return (value as? NSNumber)?.int8Value
    }
    public var _rlmObjcValue: Any {
        // Promote to Int before boxing as otherwise 0 and 1 will get treated
        // as Bool instead.
        return NSNumber(value: Int16(self))
    }
}
extension Int16: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        return (value as? NSNumber)?.int16Value
    }
    public var _rlmObjcValue: Any {
        return NSNumber(value: self)
    }
}
extension Int32: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        return (value as? NSNumber)?.int32Value
    }
    public var _rlmObjcValue: Any {
        return NSNumber(value: self)
    }
}
extension Int64: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        return (value as? NSNumber)?.int64Value
    }
    public var _rlmObjcValue: Any {
        return NSNumber(value: self)
    }
}

extension Optional: BuiltInObjcBridgeable, _ObjcBridgeable where Wrapped: _ObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        // ?? here gives the nonsensical error "Left side of nil coalescing operator '??' has non-optional type 'Wrapped?', so the right side is never used"
        if let value = Wrapped._rlmFromObjc(value, insideOptional: true) {
            return .some(value)
        }
        // We have a double-optional here and need to explicitly specify that we
        // successfully converted to `nil`, as opposed to failing to bridge.
        return .some(Self.none)
    }
    public var _rlmObjcValue: Any {
        if let value = self {
            return value._rlmObjcValue
        }
        return NSNull()
    }
}
extension Decimal128: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Decimal128? {
        if let value = value as? Decimal128 {
            return .some(value)
        }
        if let number = value as? NSNumber {
            return Decimal128(number: number)
        }
        if let str = value as? String {
            return .some((try? Decimal128(string: str)) ?? Decimal128("nan"))
        }
        return .none
    }
    public var _rlmObjcValue: Any {
        return self
    }
}
extension AnyRealmValue: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        if let any = value as? Self {
            return any
        }
        if let any = value as? RLMValue {
            return ObjectiveCSupport.convert(value: any)
        }
        return Self?.none // We need to explicitly say which .none we want here
    }
    public var _rlmObjcValue: Any {
        return ObjectiveCSupport.convert(value: self) ?? NSNull()
    }
}

// MARK: - Collections

extension Map: BuiltInObjcBridgeable {
    public var _rlmObjcValue: Any { _rlmCollection }
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        (value as? RLMCollection).map(Self.init(collection:))
    }
}
extension RealmCollectionImpl {
    public var _rlmObjcValue: Any { self.collection }
    public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Self? {
        (value as? RLMCollection).map(Self.init(collection:))
    }
}

extension LinkingObjects: _ObjcBridgeable {}
extension Results: _ObjcBridgeable {}
extension AnyRealmCollection: _ObjcBridgeable {}
extension List: _ObjcBridgeable {}
extension MutableSet: _ObjcBridgeable {}

extension SectionedResults: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Self? {
        (value as? RLMSectionedResults<RLMValue, RLMValue>).map(Self.init(rlmSectionedResult:))
    }
    public var _rlmObjcValue: Any {
        self.collection
    }
}

extension ResultsSection: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any, insideOptional: Bool) -> Self? {
        (value as? RLMSection<RLMValue, RLMValue>).map(Self.init(rlmSectionedResult:))
    }
    public var _rlmObjcValue: Any {
        self.collection
    }
}

extension RLMSwiftCollectionBase: Equatable {
    public static func == (lhs: RLMSwiftCollectionBase, rhs: RLMSwiftCollectionBase) -> Bool {
        return lhs.isEqual(rhs)
    }
}

extension Projection: BuiltInObjcBridgeable {
    public static func _rlmFromObjc(_ value: Any) -> Self? {
        return (value as? Root).map(Self.init(projecting:))
    }

    public var _rlmObjcValue: Any {
        self.rootObject
    }
}

public protocol _PossiblyAggregateable: _ObjcBridgeable {
    associatedtype PersistedType
}
extension NSDate: _PossiblyAggregateable {}
extension NSNumber: _PossiblyAggregateable {}