X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/RealmSwift/RealmSwift/RealmCollection.swift diff --git a/iOS/Pods/RealmSwift/RealmSwift/RealmCollection.swift b/iOS/Pods/RealmSwift/RealmSwift/RealmCollection.swift new file mode 100644 index 0000000..7465c9c --- /dev/null +++ b/iOS/Pods/RealmSwift/RealmSwift/RealmCollection.swift @@ -0,0 +1,1123 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 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 + +/** + An iterator for a `RealmCollection` instance. + */ +public struct RLMIterator: IteratorProtocol { + private var generatorBase: NSFastEnumerationIterator + + init(collection: RLMCollection) { + generatorBase = NSFastEnumerationIterator(collection) + } + + /// Advance to the next element and return it, or `nil` if no next element exists. + public mutating func next() -> Element? { + let next = generatorBase.next() + if let next = next as? Object? { + if next == nil { + return nil as Element? + } + return unsafeBitCast(next, to: Optional.self) + } + return next as! Element? + } +} + +/** + A `RealmCollectionChange` value encapsulates information about changes to collections + that are reported by Realm notifications. + + The change information is available in two formats: a simple array of row + indices in the collection for each type of change, and an array of index paths + in a requested section suitable for passing directly to `UITableView`'s batch + update methods. + + The arrays of indices in the `.update` case follow `UITableView`'s batching + conventions, and can be passed as-is to a table view's batch update functions after being converted to index paths. + For example, for a simple one-section table view, you can do the following: + + ```swift + self.notificationToken = results.observe { changes in + switch changes { + case .initial: + // Results are now populated and can be accessed without blocking the UI + self.tableView.reloadData() + break + case .update(_, let deletions, let insertions, let modifications): + // Query results have changed, so apply them to the TableView + self.tableView.beginUpdates() + self.tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, + with: .automatic) + self.tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, + with: .automatic) + self.tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, + with: .automatic) + self.tableView.endUpdates() + break + case .error(let err): + // An error occurred while opening the Realm file on the background worker thread + fatalError("\(err)") + break + } + } + ``` + */ +public enum RealmCollectionChange { + /** + `.initial` indicates that the initial run of the query has completed (if + applicable), and the collection can now be used without performing any + blocking work. + */ + case initial(CollectionType) + + /** + `.update` indicates that a write transaction has been committed which + either changed which objects are in the collection, and/or modified one + or more of the objects in the collection. + + All three of the change arrays are always sorted in ascending order. + + - parameter deletions: The indices in the previous version of the collection which were removed from this one. + - parameter insertions: The indices in the new collection which were added in this version. + - parameter modifications: The indices of the objects in the new collection which were modified in this version. + */ + case update(CollectionType, deletions: [Int], insertions: [Int], modifications: [Int]) + + /** + If an error occurs, notification blocks are called one time with a `.error` + result and an `NSError` containing details about the error. This can only + currently happen if opening the Realm on a background thread to calcuate + the change set fails. The callback will never be called again after it is + invoked with a .error value. + */ + case error(Error) + + static func fromObjc(value: CollectionType, change: RLMCollectionChange?, error: Error?) -> RealmCollectionChange { + if let error = error { + return .error(error) + } + if let change = change { + return .update(value, + deletions: forceCast(change.deletions, to: [Int].self), + insertions: forceCast(change.insertions, to: [Int].self), + modifications: forceCast(change.modifications, to: [Int].self)) + } + return .initial(value) + } +} + +private func forceCast(_ from: A, to type: U.Type) -> U { + return from as! U +} + +/// A type which can be stored in a Realm List or Results +public protocol RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + static func _rlmArray() -> RLMArray +} + +extension RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .int, optional: false) + } +} + +extension Optional: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + switch Wrapped.self { + case is Int.Type, is Int8.Type, is Int16.Type, is Int32.Type, is Int64.Type: + return RLMArray(objectType: .int, optional: true) + case is Bool.Type: return RLMArray(objectType: .bool, optional: true) + case is Float.Type: return RLMArray(objectType: .float, optional: true) + case is Double.Type: return RLMArray(objectType: .double, optional: true) + case is String.Type: return RLMArray(objectType: .string, optional: true) + case is Data.Type: return RLMArray(objectType: .data, optional: true) + case is Date.Type: return RLMArray(objectType: .date, optional: true) + default: fatalError("Unsupported type for List: \(Wrapped.self)?") + } + } +} + +extension Int: RealmCollectionValue {} +extension Int8: RealmCollectionValue {} +extension Int16: RealmCollectionValue {} +extension Int32: RealmCollectionValue {} +extension Int64: RealmCollectionValue {} +extension Float: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .float, optional: false) + } +} +extension Double: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .double, optional: false) + } +} +extension Bool: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .bool, optional: false) + } +} + +extension String: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .string, optional: false) + } +} +extension Date: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .date, optional: false) + } +} +extension Data: RealmCollectionValue { + /// :nodoc: + // swiftlint:disable:next identifier_name + public static func _rlmArray() -> RLMArray { + return RLMArray(objectType: .data, optional: false) + } +} + +#if swift(>=3.2) +// FIXME: When we drop support for Swift 3.1, change ElementType to Element +// throughout the project (this is a non-breaking change). We use ElementType +// only because of limitations in Swift 3.1's compiler. +/// :nodoc: +public protocol RealmCollectionBase: RandomAccessCollection, LazyCollectionProtocol, CustomStringConvertible, ThreadConfined where Element: RealmCollectionValue { + typealias ElementType = Element +} +#else +/// :nodoc: +public protocol RealmCollectionBase: RandomAccessCollection, LazyCollectionProtocol, CustomStringConvertible, ThreadConfined { + /// The type of the objects contained in the collection. + associatedtype ElementType: RealmCollectionValue +} +#endif + +/** + A homogenous collection of `Object`s which can be retrieved, filtered, sorted, and operated upon. +*/ +public protocol RealmCollection: RealmCollectionBase { + // Must also conform to `AssistedObjectiveCBridgeable` + + // MARK: Properties + + /// The Realm which manages the collection, or `nil` for unmanaged collections. + var realm: Realm? { get } + + /** + Indicates if the collection can no longer be accessed. + + The collection can no longer be accessed if `invalidate()` is called on the `Realm` that manages the collection. + */ + var isInvalidated: Bool { get } + + /// The number of objects in the collection. + var count: Int { get } + + /// A human-readable description of the objects contained in the collection. + var description: String { get } + + + // MARK: Index Retrieval + + /** + Returns the index of an object in the collection, or `nil` if the object is not present. + + - parameter object: An object. + */ + func index(of object: ElementType) -> Int? + + /** + Returns the index of the first object matching the predicate, or `nil` if no objects match. + + - parameter predicate: The predicate to use to filter the objects. + */ + func index(matching predicate: NSPredicate) -> Int? + + /** + Returns the index of the first object matching the predicate, or `nil` if no objects match. + + - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments. + */ + func index(matching predicateFormat: String, _ args: Any...) -> Int? + + + // MARK: Filtering + + /** + Returns a `Results` containing all objects matching the given predicate in the collection. + + - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments. + */ + func filter(_ predicateFormat: String, _ args: Any...) -> Results + + /** + Returns a `Results` containing all objects matching the given predicate in the collection. + + - parameter predicate: The predicate to use to filter the objects. + */ + func filter(_ predicate: NSPredicate) -> Results + + + // MARK: Sorting + + /** + Returns a `Results` containing the objects in the collection, but sorted. + + Objects are sorted based on the values of the given key path. For example, to sort a collection of `Student`s from + youngest to oldest based on their `age` property, you might call + `students.sorted(byKeyPath: "age", ascending: true)`. + + - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision + floating point, integer, and string types. + + - parameter keyPath: The key path to sort by. + - parameter ascending: The direction to sort in. + */ + func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results + + /** + Returns a `Results` containing the objects in the collection, but sorted. + + - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision + floating point, integer, and string types. + + - see: `sorted(byKeyPath:ascending:)` + + - parameter sortDescriptors: A sequence of `SortDescriptor`s to sort by. + */ + func sorted(by sortDescriptors: S) -> Results where S.Iterator.Element == SortDescriptor + + // MARK: Aggregate Operations + + /** + Returns the minimum (lowest) value of the given property among all the objects in the collection, or `nil` if the + collection is empty. + + - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified. + + - parameter property: The name of a property whose minimum value is desired. + */ + func min(ofProperty property: String) -> T? + + /** + Returns the maximum (highest) value of the given property among all the objects in the collection, or `nil` if the + collection is empty. + + - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified. + + - parameter property: The name of a property whose minimum value is desired. + */ + func max(ofProperty property: String) -> T? + + /** + Returns the sum of the given property for objects in the collection, or `nil` if the collection is empty. + + - warning: Only names of properties of a type conforming to the `AddableType` protocol can be used. + + - parameter property: The name of a property conforming to `AddableType` to calculate sum on. + */ + func sum(ofProperty property: String) -> T + + /** + Returns the average value of a given property over all the objects in the collection, or `nil` if + the collection is empty. + + - warning: Only a property whose type conforms to the `AddableType` protocol can be specified. + + - parameter property: The name of a property whose values should be summed. + */ + func average(ofProperty property: String) -> Double? + + + // MARK: Key-Value Coding + + /** + Returns an `Array` containing the results of invoking `valueForKey(_:)` with `key` on each of the collection's + objects. + + - parameter key: The name of the property whose values are desired. + */ + func value(forKey key: String) -> Any? + + /** + Returns an `Array` containing the results of invoking `valueForKeyPath(_:)` with `keyPath` on each of the + collection's objects. + + - parameter keyPath: The key path to the property whose values are desired. + */ + func value(forKeyPath keyPath: String) -> Any? + + /** + Invokes `setValue(_:forKey:)` on each of the collection's objects using the specified `value` and `key`. + + - warning: This method may only be called during a write transaction. + + - parameter value: The object value. + - parameter key: The name of the property whose value should be set on each object. + */ + func setValue(_ value: Any?, forKey key: String) + + // MARK: Notifications + + /** + Registers a block to be called each time the collection changes. + + The block will be asynchronously called with the initial results, and then called again after each write + transaction which changes either any of the objects in the collection, or which objects are in the collection. + + The `change` parameter that is passed to the block reports, in the form of indices within the collection, which of + the objects were added, removed, or modified during each write transaction. See the `RealmCollectionChange` + documentation for more information on the change information supplied and an example of how to use it to update a + `UITableView`. + + At the time when the block is called, the collection will be fully evaluated and up-to-date, and as long as you do + not perform a write transaction on the same thread or explicitly call `realm.refresh()`, accessing it will never + perform blocking work. + + Notifications are delivered via the standard run loop, and so can't be delivered while the run loop is blocked by + other activity. When notifications can't be delivered instantly, multiple notifications may be coalesced into a + single notification. This can include the notification with the initial collection. + + For example, the following code performs a write transaction immediately after adding the notification block, so + there is no opportunity for the initial notification to be delivered first. As a result, the initial notification + will reflect the state of the Realm after the write transaction. + + ```swift + let results = realm.objects(Dog.self) + print("dogs.count: \(dogs?.count)") // => 0 + let token = dogs.observe { changes in + switch changes { + case .initial(let dogs): + // Will print "dogs.count: 1" + print("dogs.count: \(dogs.count)") + break + case .update: + // Will not be hit in this example + break + case .error: + break + } + } + try! realm.write { + let dog = Dog() + dog.name = "Rex" + person.dogs.append(dog) + } + // end of run loop execution context + ``` + + You must retain the returned token for as long as you want updates to be sent to the block. To stop receiving + updates, call `invalidate()` on the token. + + - warning: This method cannot be called during a write transaction, or when the containing Realm is read-only. + + - parameter block: The block to be called whenever a change occurs. + - returns: A token which must be held for as long as you want updates to be delivered. + */ + func observe(_ block: @escaping (RealmCollectionChange) -> Void) -> NotificationToken + + /// :nodoc: + func _observe(_ block: @escaping (RealmCollectionChange>) -> Void) -> NotificationToken +} + +/// :nodoc: +public protocol OptionalProtocol { + associatedtype Wrapped + /// :nodoc: + // swiftlint:disable:next identifier_name + func _rlmInferWrappedType() -> Wrapped +} + +extension Optional: OptionalProtocol { + /// :nodoc: + // swiftlint:disable:next identifier_name + public func _rlmInferWrappedType() -> Wrapped { return self! } +} + + +// FIXME: See the declaration of RealmCollectionBase for why this `#if` is required. +#if swift(>=3.2) +public extension RealmCollection where Element: MinMaxType { + /** + Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty. + */ + public func min() -> Element? { + return min(ofProperty: "self") + } + /** + Returns the maximum (highest) value of the collection, or `nil` if the collection is empty. + */ + public func max() -> Element? { + return max(ofProperty: "self") + } +} + +public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: MinMaxType { + /** + Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty. + */ + public func min() -> Element.Wrapped? { + return min(ofProperty: "self") + } + /** + Returns the maximum (highest) value of the collection, or `nil` if the collection is empty. + */ + public func max() -> Element.Wrapped? { + return max(ofProperty: "self") + } +} + +public extension RealmCollection where Element: AddableType { + /** + Returns the sum of the values in the collection, or `nil` if the collection is empty. + */ + public func sum() -> Element { + return sum(ofProperty: "self") + } + /** + Returns the average of all of the values in the collection. + */ + public func average() -> Double? { + return average(ofProperty: "self") + } +} + +public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: AddableType { + /** + Returns the sum of the values in the collection, or `nil` if the collection is empty. + */ + public func sum() -> Element.Wrapped { + return sum(ofProperty: "self") + } + /** + Returns the average of all of the values in the collection. + */ + public func average() -> Double? { + return average(ofProperty: "self") + } +} + +public extension RealmCollection where Element: Comparable { + /** + Returns a `Results` containing the objects in the collection, but sorted. + + Objects are sorted based on their values. For example, to sort a collection of `Date`s from + neweset to oldest based, you might call `dates.sorted(ascending: true)`. + + - parameter ascending: The direction to sort in. + */ + public func sorted(ascending: Bool = true) -> Results { + return sorted(byKeyPath: "self", ascending: ascending) + } +} + +public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: Comparable { + /** + Returns a `Results` containing the objects in the collection, but sorted. + + Objects are sorted based on their values. For example, to sort a collection of `Date`s from + neweset to oldest based, you might call `dates.sorted(ascending: true)`. + + - parameter ascending: The direction to sort in. + */ + public func sorted(ascending: Bool = true) -> Results { + return sorted(byKeyPath: "self", ascending: ascending) + } +} +#else +public extension RealmCollection where ElementType: MinMaxType { + /** + Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty. + */ + public func min() -> ElementType? { + return min(ofProperty: "self") + } + /** + Returns the maximum (highest) value of the collection, or `nil` if the collection is empty. + */ + public func max() -> ElementType? { + return max(ofProperty: "self") + } +} + +public extension RealmCollection where ElementType: OptionalProtocol, ElementType.Wrapped: MinMaxType { + /** + Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty. + */ + public func min() -> ElementType.Wrapped? { + return min(ofProperty: "self") + } + /** + Returns the maximum (highest) value of the collection, or `nil` if the collection is empty. + */ + public func max() -> ElementType.Wrapped? { + return max(ofProperty: "self") + } +} + +public extension RealmCollection where ElementType: AddableType { + /** + Returns the sum of the values in the collection, or `nil` if the collection is empty. + */ + public func sum() -> ElementType { + return sum(ofProperty: "self") + } + /** + Returns the average of all of the values in the collection. + */ + public func average() -> Double? { + return average(ofProperty: "self") + } +} + +public extension RealmCollection where ElementType: OptionalProtocol, ElementType.Wrapped: AddableType { + /** + Returns the sum of the values in the collection, or `nil` if the collection is empty. + */ + public func sum() -> ElementType.Wrapped { + return sum(ofProperty: "self") + } + /** + Returns the average of all of the values in the collection. + */ + public func average() -> Double? { + return average(ofProperty: "self") + } +} + +public extension RealmCollection where ElementType: Comparable { + /** + Returns a `Results` containing the objects in the collection, but sorted. + + Objects are sorted based on their values. For example, to sort a collection of `Date`s from + neweset to oldest based, you might call `dates.sorted(ascending: true)`. + + - parameter ascending: The direction to sort in. + */ + public func sorted(ascending: Bool = true) -> Results { + return sorted(byKeyPath: "self", ascending: ascending) + } +} + +public extension RealmCollection where ElementType: OptionalProtocol, ElementType.Wrapped: Comparable { + /** + Returns a `Results` containing the objects in the collection, but sorted. + + Objects are sorted based on their values. For example, to sort a collection of `Date`s from + neweset to oldest based, you might call `dates.sorted(ascending: true)`. + + - parameter ascending: The direction to sort in. + */ + public func sorted(ascending: Bool = true) -> Results { + return sorted(byKeyPath: "self", ascending: ascending) + } +} +#endif + +private class _AnyRealmCollectionBase: AssistedObjectiveCBridgeable { + typealias Wrapper = AnyRealmCollection + typealias Element = T + var realm: Realm? { fatalError() } + var isInvalidated: Bool { fatalError() } + var count: Int { fatalError() } + var description: String { fatalError() } + func index(of object: Element) -> Int? { fatalError() } + func index(matching predicate: NSPredicate) -> Int? { fatalError() } + func index(matching predicateFormat: String, _ args: Any...) -> Int? { fatalError() } + func filter(_ predicateFormat: String, _ args: Any...) -> Results { fatalError() } + func filter(_ predicate: NSPredicate) -> Results { fatalError() } + func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results { fatalError() } + func sorted(by sortDescriptors: S) -> Results where S.Iterator.Element == SortDescriptor { + fatalError() + } + func min(ofProperty property: String) -> T? { fatalError() } + func max(ofProperty property: String) -> T? { fatalError() } + func sum(ofProperty property: String) -> T { fatalError() } + func average(ofProperty property: String) -> Double? { fatalError() } + subscript(position: Int) -> Element { fatalError() } + func makeIterator() -> RLMIterator { fatalError() } + var startIndex: Int { fatalError() } + var endIndex: Int { fatalError() } + func value(forKey key: String) -> Any? { fatalError() } + func value(forKeyPath keyPath: String) -> Any? { fatalError() } + func setValue(_ value: Any?, forKey key: String) { fatalError() } + func _observe(_ block: @escaping (RealmCollectionChange) -> Void) + -> NotificationToken { fatalError() } + class func bridging(from objectiveCValue: Any, with metadata: Any?) -> Self { fatalError() } + var bridged: (objectiveCValue: Any, metadata: Any?) { fatalError() } +} + +private final class _AnyRealmCollection: _AnyRealmCollectionBase { + let base: C + init(base: C) { + self.base = base + } + + // MARK: Properties + + override var realm: Realm? { return base.realm } + override var isInvalidated: Bool { return base.isInvalidated } + override var count: Int { return base.count } + override var description: String { return base.description } + + + // MARK: Index Retrieval + + override func index(of object: C.ElementType) -> Int? { return base.index(of: object) } + + override func index(matching predicate: NSPredicate) -> Int? { return base.index(matching: predicate) } + + override func index(matching predicateFormat: String, _ args: Any...) -> Int? { + return base.index(matching: NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args))) + } + + // MARK: Filtering + + override func filter(_ predicateFormat: String, _ args: Any...) -> Results { + return base.filter(NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args))) + } + + override func filter(_ predicate: NSPredicate) -> Results { return base.filter(predicate) } + + // MARK: Sorting + + override func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results { + return base.sorted(byKeyPath: keyPath, ascending: ascending) + } + + override func sorted + (by sortDescriptors: S) -> Results where S.Iterator.Element == SortDescriptor { + return base.sorted(by: sortDescriptors) + } + + + // MARK: Aggregate Operations + + override func min(ofProperty property: String) -> T? { + return base.min(ofProperty: property) + } + + override func max(ofProperty property: String) -> T? { + return base.max(ofProperty: property) + } + + override func sum(ofProperty property: String) -> T { + return base.sum(ofProperty: property) + } + + override func average(ofProperty property: String) -> Double? { + return base.average(ofProperty: property) + } + + + // MARK: Sequence Support + + override subscript(position: Int) -> C.ElementType { + #if swift(>=3.2) + return base[position as! C.Index] + #else + return base[position as! C.Index] as! C.ElementType + #endif + } + + override func makeIterator() -> RLMIterator { + // FIXME: it should be possible to avoid this force-casting + return base.makeIterator() as! RLMIterator + } + + + // MARK: Collection Support + + override var startIndex: Int { + // FIXME: it should be possible to avoid this force-casting + return base.startIndex as! Int + } + + override var endIndex: Int { + // FIXME: it should be possible to avoid this force-casting + return base.endIndex as! Int + } + + + // MARK: Key-Value Coding + + override func value(forKey key: String) -> Any? { return base.value(forKey: key) } + + override func value(forKeyPath keyPath: String) -> Any? { return base.value(forKeyPath: keyPath) } + + override func setValue(_ value: Any?, forKey key: String) { base.setValue(value, forKey: key) } + + // MARK: Notifications + + /// :nodoc: + override func _observe(_ block: @escaping (RealmCollectionChange) -> Void) + -> NotificationToken { return base._observe(block) } + + // MARK: AssistedObjectiveCBridgeable + + override class func bridging(from objectiveCValue: Any, with metadata: Any?) -> _AnyRealmCollection { + return _AnyRealmCollection( + base: (C.self as! AssistedObjectiveCBridgeable.Type).bridging(from: objectiveCValue, with: metadata) as! C) + } + + override var bridged: (objectiveCValue: Any, metadata: Any?) { + return (base as! AssistedObjectiveCBridgeable).bridged + } +} + +/** + A type-erased `RealmCollection`. + + Instances of `RealmCollection` forward operations to an opaque underlying collection having the same `Element` type. + */ +public final class AnyRealmCollection: RealmCollection { + + /// The type of the objects contained within the collection. + public typealias ElementType = Element + + public func index(after i: Int) -> Int { return i + 1 } + public func index(before i: Int) -> Int { return i - 1 } + + /// The type of the objects contained in the collection. + fileprivate let base: _AnyRealmCollectionBase + + fileprivate init(base: _AnyRealmCollectionBase) { + self.base = base + } + + /// Creates an `AnyRealmCollection` wrapping `base`. + public init(_ base: C) where C.ElementType == Element { + self.base = _AnyRealmCollection(base: base) + } + + // MARK: Properties + + /// The Realm which manages the collection, or `nil` if the collection is unmanaged. + public var realm: Realm? { return base.realm } + + /** + Indicates if the collection can no longer be accessed. + + The collection can no longer be accessed if `invalidate()` is called on the containing `realm`. + */ + public var isInvalidated: Bool { return base.isInvalidated } + + /// The number of objects in the collection. + public var count: Int { return base.count } + + /// A human-readable description of the objects contained in the collection. + public var description: String { return base.description } + + + // MARK: Index Retrieval + + /** + Returns the index of the given object, or `nil` if the object is not in the collection. + + - parameter object: An object. + */ + public func index(of object: Element) -> Int? { return base.index(of: object) } + + /** + Returns the index of the first object matching the given predicate, or `nil` if no objects match. + + - parameter predicate: The predicate with which to filter the objects. + */ + public func index(matching predicate: NSPredicate) -> Int? { return base.index(matching: predicate) } + + /** + Returns the index of the first object matching the given predicate, or `nil` if no objects match. + + - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments. + */ + public func index(matching predicateFormat: String, _ args: Any...) -> Int? { + return base.index(matching: NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args))) + } + + // MARK: Filtering + + /** + Returns a `Results` containing all objects matching the given predicate in the collection. + + - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments. + */ + public func filter(_ predicateFormat: String, _ args: Any...) -> Results { + return base.filter(NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args))) + } + + /** + Returns a `Results` containing all objects matching the given predicate in the collection. + + - parameter predicate: The predicate with which to filter the objects. + + - returns: A `Results` containing objects that match the given predicate. + */ + public func filter(_ predicate: NSPredicate) -> Results { return base.filter(predicate) } + + + // MARK: Sorting + + /** + Returns a `Results` containing the objects in the collection, but sorted. + + Objects are sorted based on the values of the given key path. For example, to sort a collection of `Student`s from + youngest to oldest based on their `age` property, you might call + `students.sorted(byKeyPath: "age", ascending: true)`. + + - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision + floating point, integer, and string types. + + - parameter keyPath: The key path to sort by. + - parameter ascending: The direction to sort in. + */ + public func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results { + return base.sorted(byKeyPath: keyPath, ascending: ascending) + } + + /** + Returns a `Results` containing the objects in the collection, but sorted. + + - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision + floating point, integer, and string types. + + - see: `sorted(byKeyPath:ascending:)` + + - parameter sortDescriptors: A sequence of `SortDescriptor`s to sort by. + */ + public func sorted(by sortDescriptors: S) -> Results + where S.Iterator.Element == SortDescriptor { + return base.sorted(by: sortDescriptors) + } + + + // MARK: Aggregate Operations + + /** + Returns the minimum (lowest) value of the given property among all the objects in the collection, or `nil` if the + collection is empty. + + - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified. + + - parameter property: The name of a property whose minimum value is desired. + */ + public func min(ofProperty property: String) -> T? { + return base.min(ofProperty: property) + } + + /** + Returns the maximum (highest) value of the given property among all the objects in the collection, or `nil` if the + collection is empty. + + - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified. + + - parameter property: The name of a property whose minimum value is desired. + */ + public func max(ofProperty property: String) -> T? { + return base.max(ofProperty: property) + } + + /** + Returns the sum of the values of a given property over all the objects in the collection. + + - warning: Only a property whose type conforms to the `AddableType` protocol can be specified. + + - parameter property: The name of a property whose values should be summed. + */ + public func sum(ofProperty property: String) -> T { return base.sum(ofProperty: property) } + + /** + Returns the average value of a given property over all the objects in the collection, or `nil` if the collection is + empty. + + - warning: Only the name of a property whose type conforms to the `AddableType` protocol can be specified. + + - parameter property: The name of a property whose average value should be calculated. + */ + public func average(ofProperty property: String) -> Double? { return base.average(ofProperty: property) } + + + // MARK: Sequence Support + + /** + Returns the object at the given `index`. + + - parameter index: The index. + */ + public subscript(position: Int) -> Element { return base[position] } + + /// Returns a `RLMIterator` that yields successive elements in the collection. + public func makeIterator() -> RLMIterator { return base.makeIterator() } + + + // MARK: Collection Support + + /// The position of the first element in a non-empty collection. + /// Identical to endIndex in an empty collection. + public var startIndex: Int { return base.startIndex } + + /// The collection's "past the end" position. + /// endIndex is not a valid argument to subscript, and is always reachable from startIndex by + /// zero or more applications of successor(). + public var endIndex: Int { return base.endIndex } + + + // MARK: Key-Value Coding + + /** + Returns an `Array` containing the results of invoking `valueForKey(_:)` with `key` on each of the collection's + objects. + + - parameter key: The name of the property whose values are desired. + */ + public func value(forKey key: String) -> Any? { return base.value(forKey: key) } + + /** + Returns an `Array` containing the results of invoking `valueForKeyPath(_:)` with `keyPath` on each of the + collection's objects. + + - parameter keyPath: The key path to the property whose values are desired. + */ + public func value(forKeyPath keyPath: String) -> Any? { return base.value(forKeyPath: keyPath) } + + /** + Invokes `setValue(_:forKey:)` on each of the collection's objects using the specified `value` and `key`. + + - warning: This method may only be called during a write transaction. + + - parameter value: The value to set the property to. + - parameter key: The name of the property whose value should be set on each object. + */ + public func setValue(_ value: Any?, forKey key: String) { base.setValue(value, forKey: key) } + + // MARK: Notifications + + /** + Registers a block to be called each time the collection changes. + + The block will be asynchronously called with the initial results, and then called again after each write + transaction which changes either any of the objects in the collection, or which objects are in the collection. + + The `change` parameter that is passed to the block reports, in the form of indices within the collection, which of + the objects were added, removed, or modified during each write transaction. See the `RealmCollectionChange` + documentation for more information on the change information supplied and an example of how to use it to update a + `UITableView`. + + At the time when the block is called, the collection will be fully evaluated and up-to-date, and as long as you do + not perform a write transaction on the same thread or explicitly call `realm.refresh()`, accessing it will never + perform blocking work. + + Notifications are delivered via the standard run loop, and so can't be delivered while the run loop is blocked by + other activity. When notifications can't be delivered instantly, multiple notifications may be coalesced into a + single notification. This can include the notification with the initial collection. + + For example, the following code performs a write transaction immediately after adding the notification block, so + there is no opportunity for the initial notification to be delivered first. As a result, the initial notification + will reflect the state of the Realm after the write transaction. + + ```swift + let results = realm.objects(Dog.self) + print("dogs.count: \(dogs?.count)") // => 0 + let token = dogs.observe { changes in + switch changes { + case .initial(let dogs): + // Will print "dogs.count: 1" + print("dogs.count: \(dogs.count)") + break + case .update: + // Will not be hit in this example + break + case .error: + break + } + } + try! realm.write { + let dog = Dog() + dog.name = "Rex" + person.dogs.append(dog) + } + // end of run loop execution context + ``` + + You must retain the returned token for as long as you want updates to be sent to the block. To stop receiving + updates, call `invalidate()` on the token. + + - warning: This method cannot be called during a write transaction, or when the containing Realm is read-only. + + - parameter block: The block to be called whenever a change occurs. + - returns: A token which must be held for as long as you want updates to be delivered. + */ + public func observe(_ block: @escaping (RealmCollectionChange) -> Void) + -> NotificationToken { return base._observe(block) } + + /// :nodoc: + public func _observe(_ block: @escaping (RealmCollectionChange) -> Void) + -> NotificationToken { return base._observe(block) } +} + +// MARK: AssistedObjectiveCBridgeable + +private struct AnyRealmCollectionBridgingMetadata { + var baseMetadata: Any? + var baseType: _AnyRealmCollectionBase.Type +} + +extension AnyRealmCollection: AssistedObjectiveCBridgeable { + static func bridging(from objectiveCValue: Any, with metadata: Any?) -> AnyRealmCollection { + guard let metadata = metadata as? AnyRealmCollectionBridgingMetadata else { preconditionFailure() } + return AnyRealmCollection(base: metadata.baseType.bridging(from: objectiveCValue, with: metadata.baseMetadata)) + } + + var bridged: (objectiveCValue: Any, metadata: Any?) { + return ( + objectiveCValue: base.bridged.objectiveCValue, + metadata: AnyRealmCollectionBridgingMetadata(baseMetadata: base.bridged.metadata, baseType: type(of: base)) + ) + } +} + +// MARK: Unavailable + +extension RealmCollection { + @available(*, unavailable, renamed: "sorted(byKeyPath:ascending:)") + func sorted(byProperty property: String, ascending: Bool) -> Results { fatalError() } + + @available(*, unavailable, renamed: "observe(_:)") + public func addNotificationBlock(_ block: @escaping (RealmCollectionChange) -> Void) -> NotificationToken { + fatalError() + } +}