Util.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2015 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. import Foundation
  19. import Realm
  20. import os.log
  21. #if BUILDING_REALM_SWIFT_TESTS
  22. import RealmSwift
  23. #endif
  24. // MARK: Internal Helpers
  25. // Swift 3.1 provides fixits for some of our uses of unsafeBitCast
  26. // to use unsafeDowncast instead, but the bitcast is required.
  27. internal func noWarnUnsafeBitCast<T, U>(_ x: T, to type: U.Type) -> U {
  28. return unsafeBitCast(x, to: type)
  29. }
  30. /// Given a list of `Any`-typed varargs, unwrap any optionals and
  31. /// replace them with the underlying value or NSNull.
  32. internal func unwrapOptionals(in varargs: [Any]) -> [Any] {
  33. return varargs.map { arg in
  34. if let someArg = arg as Any? {
  35. return someArg
  36. }
  37. return NSNull()
  38. }
  39. }
  40. internal func notFoundToNil(index: UInt) -> Int? {
  41. if index == UInt(NSNotFound) {
  42. return nil
  43. }
  44. return Int(index)
  45. }
  46. internal func throwRealmException(_ message: String, userInfo: [AnyHashable: Any]? = nil) -> Never {
  47. NSException(name: NSExceptionName(rawValue: RLMExceptionName), reason: message, userInfo: userInfo).raise()
  48. fatalError() // unreachable
  49. }
  50. internal func throwForNegativeIndex(_ int: Int, parameterName: String = "index") {
  51. if int < 0 {
  52. throwRealmException("Cannot pass a negative value for '\(parameterName)'.")
  53. }
  54. }
  55. internal func gsub(pattern: String, template: String, string: String, error: NSErrorPointer = nil) -> String? {
  56. let regex = try? NSRegularExpression(pattern: pattern, options: [])
  57. return regex?.stringByReplacingMatches(in: string, options: [],
  58. range: NSRange(location: 0, length: string.utf16.count),
  59. withTemplate: template)
  60. }
  61. extension ObjectBase {
  62. // Must *only* be used to call Realm Objective-C APIs that are exposed on `RLMObject`
  63. // but actually operate on `RLMObjectBase`. Do not expose cast value to user.
  64. internal func unsafeCastToRLMObject() -> RLMObject {
  65. return noWarnUnsafeBitCast(self, to: RLMObject.self)
  66. }
  67. }
  68. internal func coerceToNil(_ value: Any) -> Any? {
  69. if value is NSNull {
  70. return nil
  71. }
  72. // nil in Any is bridged to obj-c as NSNull. In the obj-c code we usually
  73. // convert NSNull back to nil, which ends up as Optional<Any>.none
  74. if case Optional<Any>.none = value {
  75. return nil
  76. }
  77. return value
  78. }
  79. // MARK: CustomObjectiveCBridgeable
  80. internal extension _ObjcBridgeable {
  81. static func _rlmFromObjc(_ value: Any) -> Self? { _rlmFromObjc(value, insideOptional: false) }
  82. }
  83. /// :nodoc:
  84. public func dynamicBridgeCast<T>(fromObjectiveC x: Any) -> T {
  85. if let bridged = failableDynamicBridgeCast(fromObjectiveC: x) as T? {
  86. return bridged
  87. }
  88. fatalError("Could not convert value '\(x)' to type '\(T.self)'")
  89. }
  90. /// :nodoc:
  91. @usableFromInline
  92. internal func failableDynamicBridgeCast<T>(fromObjectiveC x: Any) -> T? {
  93. if let bridgeableType = T.self as? _ObjcBridgeable.Type {
  94. return bridgeableType._rlmFromObjc(x).flatMap { $0 as? T }
  95. }
  96. if let value = x as? T {
  97. return value
  98. }
  99. return nil
  100. }
  101. /// :nodoc:
  102. public func dynamicBridgeCast<T>(fromSwift x: T) -> Any {
  103. if let x = x as? _ObjcBridgeable {
  104. return x._rlmObjcValue
  105. }
  106. return x
  107. }
  108. @usableFromInline
  109. internal func staticBridgeCast<T: _ObjcBridgeable>(fromSwift x: T) -> Any {
  110. return x._rlmObjcValue
  111. }
  112. @usableFromInline
  113. internal func staticBridgeCast<T: _ObjcBridgeable>(fromObjectiveC x: Any) -> T {
  114. if let value = T._rlmFromObjc(x) {
  115. return value
  116. }
  117. throwRealmException("Could not convert value '\(x)' to type '\(T.self)'.")
  118. }
  119. @usableFromInline
  120. internal func failableStaticBridgeCast<T: _ObjcBridgeable>(fromObjectiveC x: Any) -> T? {
  121. return T._rlmFromObjc(x)
  122. }
  123. internal func logRuntimeIssue(_ message: StaticString) {
  124. if #available(macOS 10.14, iOS 12.0, watchOS 5.0, tvOS 12.0, *) {
  125. // Reporting a runtime issue to Xcode requires pretending to be
  126. // one of the system libraries which are allowed to do so. We do
  127. // this by looking up a symbol defined by SwiftUI, getting the
  128. // dso information from that, and passing that to os_log() to
  129. // claim that we're SwiftUI. As this is obviously not a particularly legal thing to do, we only do it in debug and simulator builds.
  130. var dso = #dsohandle
  131. #if DEBUG || targetEnvironment(simulator)
  132. let sym = dlsym(dlopen(nil, RTLD_LAZY), "$s7SwiftUI3AppMp")
  133. var info = Dl_info()
  134. dladdr(sym, &info)
  135. if let base = info.dli_fbase {
  136. dso = UnsafeRawPointer(base)
  137. }
  138. #endif
  139. let log = OSLog(subsystem: "com.apple.runtime-issues", category: "Realm")
  140. os_log(.fault, dso: dso, log: log, message)
  141. } else {
  142. print(message)
  143. }
  144. }
  145. #if swift(<5.9)
  146. // These are added in SE-0392, but can be partially polyfilled for older versions.
  147. // We can't actually perform the proper checks to see if we're actually on the
  148. // expected executor, though.
  149. @_unavailableFromAsync
  150. internal func assumeOnMainActorExecutor<T>(_ operation: @MainActor () throws -> T,
  151. file: StaticString = #fileID, line: UInt = #line
  152. ) rethrows -> T {
  153. precondition(Thread.isMainThread, file: file, line: line)
  154. return try withoutActuallyEscaping(operation) { fn in
  155. try unsafeBitCast(fn, to: (() throws -> T).self)()
  156. }
  157. }
  158. @_unavailableFromAsync
  159. @available(macOS 10.15, tvOS 13.0, iOS 13.0, watchOS 6.0, *)
  160. internal func assumeOnActorExecutor<A: Actor, T>(_ actor: A,
  161. _ operation: (isolated A) throws -> T
  162. ) rethrows -> T {
  163. try withoutActuallyEscaping(operation) { fn in
  164. try unsafeBitCast(fn, to: ((A) throws -> T).self)(actor)
  165. }
  166. }
  167. #endif