FirestoreEncoder.swift 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // This file is derived from swift/stdlib/public/SDK/Foundation/JSONEncoder.swift
  2. // and swift/stdlib/public/SDK/Foundation/PlistEncoder.swift
  3. //===----------------------------------------------------------------------===//
  4. //
  5. // This source file is part of the Swift.org open source project
  6. //
  7. // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
  8. // Licensed under Apache License v2.0 with Runtime Library Exception
  9. //
  10. // See https://swift.org/LICENSE.txt for license information
  11. // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  12. //
  13. //===----------------------------------------------------------------------===//
  14. import FirebaseFirestore
  15. import Foundation
  16. extension Firestore {
  17. public struct Encoder {
  18. public init() {}
  19. /// Returns encoded data that Firestore API recognizes.
  20. ///
  21. /// If possible, all types will be converted to compatible types Firestore
  22. /// can handle. This means certain Firestore specific types will be encoded
  23. /// as pass-through: this encoder will only pass those types along since that
  24. /// is what Firestore can handle. The same types will be encoded differently
  25. /// with other encoders (for example: JSONEncoder).
  26. ///
  27. /// The Firestore pass-through types are:
  28. /// - GeoPoint
  29. /// - Timestamp
  30. /// - DocumentReference
  31. ///
  32. /// - Parameter value: The Encodable object to convert to encoded data.
  33. /// - Returns: A Map keyed by String representing a document Firestore
  34. /// API can work with.
  35. public func encode<T: Encodable>(_ value: T) throws -> [String: Any] {
  36. // SelfDocumentID, DocumentReference and FieldValue cannot be
  37. // encoded directly.
  38. guard T.self != DocumentReference.self,
  39. T.self != FieldValue.self else {
  40. throw EncodingError
  41. .invalidValue(value,
  42. EncodingError
  43. .Context(codingPath: [],
  44. debugDescription: "Top-level \(T.self) is not allowed."))
  45. }
  46. guard let topLevel = try _FirestoreEncoder().box_(value) else {
  47. throw EncodingError.invalidValue(value,
  48. EncodingError.Context(codingPath: [],
  49. debugDescription: "Top-level \(T.self) did not encode any values."))
  50. }
  51. // This is O(n) check. Consider refactoring box_ to return [String: Any].
  52. guard let dict = topLevel as? [String: Any] else {
  53. throw EncodingError.invalidValue(value,
  54. EncodingError.Context(codingPath: [],
  55. debugDescription: "Top-level \(T.self) encoded not as dictionary."))
  56. }
  57. return dict
  58. }
  59. }
  60. }
  61. private class _FirestoreEncoder: Encoder {
  62. /// A stack of data containers storing encoded results. When a new object is being encoded,
  63. /// a corresponding storage is pushed to the stack; and when the field and all of its children objects
  64. /// are encoded, the stoage should have the entire encoded result for the sub-tree, it is then poped
  65. /// out and written to the proper place of the new stack top container by referencing to the top of `codingPath`.
  66. fileprivate var storage: _FirestoreEncodingStorage
  67. /// An array used as a stack to keep track of where in the encoded data tree the encoder is trying to process
  68. /// at the moment.
  69. public fileprivate(set) var codingPath: [CodingKey]
  70. public var userInfo: [CodingUserInfoKey: Any] = [:]
  71. init() {
  72. storage = _FirestoreEncodingStorage()
  73. codingPath = []
  74. }
  75. /// Returns whether we should allocate new container to store encoded result for the current
  76. /// codingPath.
  77. ///
  78. /// `true` if no container has been allocated for this coding path; `false` otherwise.
  79. fileprivate var shouldAllocateNewContainer: Bool {
  80. // The encoder starts with storage.count == codingPath.count == 0, which means it is encoding the root
  81. // object without any container allocated, so when a container is requested, it must be allocated
  82. // first. When a container is requested again with the same codingPath however, for another field from the root object possibly,
  83. // because now storage.count == codingPath + 1, we should not allocate new containers because there are
  84. // already encoded results in the container. This relation between the two stacks is maintained
  85. // throughout the encoding process.
  86. return storage.count == codingPath.count
  87. }
  88. // MARK: - Encoder Methods
  89. public func container<Key>(keyedBy _: Key.Type) -> KeyedEncodingContainer<Key> {
  90. // If an existing keyed container was already requested, return that one.
  91. let topContainer: NSMutableDictionary
  92. if shouldAllocateNewContainer {
  93. // We haven't yet pushed a container at this level; do so here.
  94. topContainer = storage.pushKeyedContainer()
  95. } else {
  96. guard let container = storage.containers.last as? NSMutableDictionary else {
  97. preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.")
  98. }
  99. topContainer = container
  100. }
  101. let container = _FirestoreKeyedEncodingContainer<Key>(referencing: self, codingPath: codingPath,
  102. wrapping: topContainer)
  103. return KeyedEncodingContainer(container)
  104. }
  105. public func unkeyedContainer() -> UnkeyedEncodingContainer {
  106. // If an existing unkeyed container was already requested, return that one.
  107. let topContainer: NSMutableArray
  108. if shouldAllocateNewContainer {
  109. // We haven't yet pushed a container at this level; do so here.
  110. topContainer = storage.pushUnkeyedContainer()
  111. } else {
  112. guard let container = storage.containers.last as? NSMutableArray else {
  113. preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.")
  114. }
  115. topContainer = container
  116. }
  117. return _FirestoreUnkeyedEncodingContainer(referencing: self, codingPath: codingPath,
  118. wrapping: topContainer)
  119. }
  120. public func singleValueContainer() -> SingleValueEncodingContainer {
  121. return self
  122. }
  123. }
  124. private struct _FirestoreEncodingStorage {
  125. // MARK: Properties
  126. /// The container stack.
  127. /// Elements may be any one of the plist types (NSNumber, NSString, NSDate, NSArray, NSDictionary).
  128. fileprivate private(set) var containers: [NSObject] = []
  129. // MARK: - Initialization
  130. /// Initializes `self` with no containers.
  131. fileprivate init() {}
  132. // MARK: - Modifying the Stack
  133. fileprivate var count: Int {
  134. return containers.count
  135. }
  136. fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary {
  137. let dictionary = NSMutableDictionary()
  138. containers.append(dictionary)
  139. return dictionary
  140. }
  141. fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray {
  142. let array = NSMutableArray()
  143. containers.append(array)
  144. return array
  145. }
  146. fileprivate mutating func push(container: NSObject) {
  147. containers.append(container)
  148. }
  149. fileprivate mutating func popContainer() -> NSObject {
  150. precondition(containers.count > 0, "Empty container stack.")
  151. let ret = containers.popLast()!
  152. return ret
  153. }
  154. }
  155. private struct _FirestoreKeyedEncodingContainer<K: CodingKey>: KeyedEncodingContainerProtocol {
  156. typealias Key = K
  157. // MARK: Properties
  158. /// A reference to the encoder we're writing to.
  159. private let encoder: _FirestoreEncoder
  160. /// A reference to the container we're writing to.
  161. private let container: NSMutableDictionary
  162. /// The path of coding keys taken to get to this point in encoding.
  163. public private(set) var codingPath: [CodingKey]
  164. // MARK: - Initialization
  165. /// Initializes `self` with the given references.
  166. fileprivate init(referencing encoder: _FirestoreEncoder,
  167. codingPath: [CodingKey],
  168. wrapping container: NSMutableDictionary) {
  169. self.encoder = encoder
  170. self.codingPath = codingPath
  171. self.container = container
  172. }
  173. // MARK: - KeyedEncodingContainerProtocol Methods
  174. public mutating func encodeNil(forKey key: Key) throws { container[key.stringValue] = NSNull() }
  175. public mutating func encode(_ value: Bool, forKey key: Key) throws {
  176. container[key.stringValue] = encoder.box(value)
  177. }
  178. public mutating func encode(_ value: Int, forKey key: Key) throws {
  179. container[key.stringValue] = encoder.box(value)
  180. }
  181. public mutating func encode(_ value: Int8, forKey key: Key) throws {
  182. container[key.stringValue] = encoder.box(value)
  183. }
  184. public mutating func encode(_ value: Int16, forKey key: Key) throws {
  185. container[key.stringValue] = encoder.box(value)
  186. }
  187. public mutating func encode(_ value: Int32, forKey key: Key) throws {
  188. container[key.stringValue] = encoder.box(value)
  189. }
  190. public mutating func encode(_ value: Int64, forKey key: Key) throws {
  191. container[key.stringValue] = encoder.box(value)
  192. }
  193. public mutating func encode(_ value: UInt, forKey key: Key) throws {
  194. container[key.stringValue] = encoder.box(value)
  195. }
  196. public mutating func encode(_ value: UInt8, forKey key: Key) throws {
  197. container[key.stringValue] = encoder.box(value)
  198. }
  199. public mutating func encode(_ value: UInt16, forKey key: Key) throws {
  200. container[key.stringValue] = encoder.box(value)
  201. }
  202. public mutating func encode(_ value: UInt32, forKey key: Key) throws {
  203. container[key.stringValue] = encoder.box(value)
  204. }
  205. public mutating func encode(_ value: UInt64, forKey key: Key) throws {
  206. container[key.stringValue] = encoder.box(value)
  207. }
  208. public mutating func encode(_ value: String, forKey key: Key) throws {
  209. container[key.stringValue] = encoder.box(value)
  210. }
  211. public mutating func encode(_ value: Float, forKey key: Key) throws {
  212. container[key.stringValue] = encoder.box(value)
  213. }
  214. public mutating func encode(_ value: Double, forKey key: Key) throws {
  215. container[key.stringValue] = encoder.box(value)
  216. }
  217. public mutating func encode<T: Encodable>(_ value: T, forKey key: Key) throws {
  218. #if compiler(>=5.1)
  219. // `DocumentID`-annotated fields are ignored during encoding.
  220. if T.self is DocumentIDProtocol.Type {
  221. return
  222. }
  223. #endif // compiler(>=5.1)
  224. encoder.codingPath.append(key)
  225. defer {
  226. encoder.codingPath.removeLast()
  227. }
  228. container[key.stringValue] = try encoder.box(value)
  229. }
  230. public mutating func nestedContainer<NestedKey>(keyedBy _: NestedKey.Type,
  231. forKey key: Key)
  232. -> KeyedEncodingContainer<NestedKey> {
  233. let dictionary = NSMutableDictionary()
  234. self.container[key.stringValue] = dictionary
  235. codingPath.append(key)
  236. defer {
  237. codingPath.removeLast()
  238. }
  239. let container = _FirestoreKeyedEncodingContainer<NestedKey>(referencing: encoder,
  240. codingPath: codingPath,
  241. wrapping: dictionary)
  242. return KeyedEncodingContainer(container)
  243. }
  244. public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
  245. let array = NSMutableArray()
  246. container[key.stringValue] = array
  247. codingPath.append(key)
  248. defer {
  249. codingPath.removeLast()
  250. }
  251. return _FirestoreUnkeyedEncodingContainer(referencing: encoder, codingPath: codingPath,
  252. wrapping: array)
  253. }
  254. public mutating func superEncoder() -> Encoder {
  255. return _FirestoreReferencingEncoder(referencing: encoder, at: _FirestoreKey.super,
  256. wrapping: container)
  257. }
  258. public mutating func superEncoder(forKey key: Key) -> Encoder {
  259. return _FirestoreReferencingEncoder(referencing: encoder, at: key, wrapping: container)
  260. }
  261. }
  262. private struct _FirestoreUnkeyedEncodingContainer: UnkeyedEncodingContainer {
  263. // MARK: Properties
  264. /// A reference to the encoder we're writing to.
  265. private let encoder: _FirestoreEncoder
  266. /// A reference to the container we're writing to.
  267. private let container: NSMutableArray
  268. /// The path of coding keys taken to get to this point in encoding.
  269. public private(set) var codingPath: [CodingKey]
  270. /// The number of elements encoded into the container.
  271. public var count: Int {
  272. return container.count
  273. }
  274. // MARK: - Initialization
  275. /// Initializes `self` with the given references.
  276. fileprivate init(referencing encoder: _FirestoreEncoder,
  277. codingPath: [CodingKey],
  278. wrapping container: NSMutableArray) {
  279. self.encoder = encoder
  280. self.codingPath = codingPath
  281. self.container = container
  282. }
  283. // MARK: - UnkeyedEncodingContainer Methods
  284. public mutating func encodeNil() throws { container.add(NSNull()) }
  285. public mutating func encode(_ value: Bool) throws { container.add(encoder.box(value)) }
  286. public mutating func encode(_ value: Int) throws { container.add(encoder.box(value)) }
  287. public mutating func encode(_ value: Int8) throws { container.add(encoder.box(value)) }
  288. public mutating func encode(_ value: Int16) throws { container.add(encoder.box(value)) }
  289. public mutating func encode(_ value: Int32) throws { container.add(encoder.box(value)) }
  290. public mutating func encode(_ value: Int64) throws { container.add(encoder.box(value)) }
  291. public mutating func encode(_ value: UInt) throws { container.add(encoder.box(value)) }
  292. public mutating func encode(_ value: UInt8) throws { container.add(encoder.box(value)) }
  293. public mutating func encode(_ value: UInt16) throws { container.add(encoder.box(value)) }
  294. public mutating func encode(_ value: UInt32) throws { container.add(encoder.box(value)) }
  295. public mutating func encode(_ value: UInt64) throws { container.add(encoder.box(value)) }
  296. public mutating func encode(_ value: Float) throws { container.add(encoder.box(value)) }
  297. public mutating func encode(_ value: Double) throws { container.add(encoder.box(value)) }
  298. public mutating func encode(_ value: String) throws { container.add(encoder.box(value)) }
  299. public mutating func encode<T: Encodable>(_ value: T) throws {
  300. encoder.codingPath.append(_FirestoreKey(index: count))
  301. defer { encoder.codingPath.removeLast()
  302. }
  303. container.add(try encoder.box(value))
  304. }
  305. public mutating func nestedContainer<NestedKey>(keyedBy _: NestedKey
  306. .Type) -> KeyedEncodingContainer<NestedKey> {
  307. codingPath.append(_FirestoreKey(index: count))
  308. defer {
  309. self.codingPath.removeLast()
  310. }
  311. let dictionary = NSMutableDictionary()
  312. self.container.add(dictionary)
  313. let container = _FirestoreKeyedEncodingContainer<NestedKey>(referencing: encoder,
  314. codingPath: codingPath,
  315. wrapping: dictionary)
  316. return KeyedEncodingContainer(container)
  317. }
  318. public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
  319. codingPath.append(_FirestoreKey(index: count))
  320. defer {
  321. self.codingPath.removeLast()
  322. }
  323. let array = NSMutableArray()
  324. container.add(array)
  325. return _FirestoreUnkeyedEncodingContainer(referencing: encoder, codingPath: codingPath,
  326. wrapping: array)
  327. }
  328. public mutating func superEncoder() -> Encoder {
  329. return _FirestoreReferencingEncoder(referencing: encoder, at: container.count,
  330. wrapping: container)
  331. }
  332. }
  333. struct _FirestoreKey: CodingKey {
  334. public var stringValue: String
  335. public var intValue: Int?
  336. public init?(stringValue: String) {
  337. self.stringValue = stringValue
  338. intValue = nil
  339. }
  340. public init?(intValue: Int) {
  341. stringValue = "\(intValue)"
  342. self.intValue = intValue
  343. }
  344. init(index: Int) {
  345. stringValue = "Index \(index)"
  346. intValue = index
  347. }
  348. static let `super` = _FirestoreKey(stringValue: "super")!
  349. }
  350. extension _FirestoreEncoder {
  351. /// Returns the given value boxed in a container appropriate for pushing onto the container stack.
  352. fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) }
  353. fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) }
  354. fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) }
  355. fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) }
  356. fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) }
  357. fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) }
  358. fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) }
  359. fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) }
  360. fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) }
  361. fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) }
  362. fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) }
  363. fileprivate func box(_ value: Float) -> NSObject { return NSNumber(value: value) }
  364. fileprivate func box(_ value: Double) -> NSObject { return NSNumber(value: value) }
  365. fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) }
  366. fileprivate func box<T: Encodable>(_ value: T) throws -> NSObject {
  367. return try box_(value) ?? NSDictionary()
  368. }
  369. func box_<T: Encodable>(_ value: T) throws -> NSObject? {
  370. if T.self == Date.self || T.self == NSDate.self {
  371. return (value as! NSDate)
  372. } else if T.self == Data.self || T.self == NSData.self {
  373. return (value as! NSData)
  374. } else if T.self == URL.self || T.self == NSURL.self {
  375. return box((value as! URL).absoluteString)
  376. } else if T.self == Decimal.self || T.self == NSDecimalNumber.self {
  377. return (value as! NSDecimalNumber)
  378. } else if isFirestorePassthroughType(value) {
  379. // This is a native Firestore types that we don't need to encode.
  380. return (value as! NSObject)
  381. }
  382. // The value should request a container from the _FirestoreEncoder.
  383. let depth = storage.count
  384. do {
  385. try value.encode(to: self)
  386. } catch {
  387. // If the value pushed a container before throwing, pop it back off to restore state.
  388. if storage.count > depth {
  389. _ = storage.popContainer()
  390. }
  391. throw error
  392. }
  393. // The top container should be a new container.
  394. guard storage.count > depth else {
  395. return nil
  396. }
  397. return storage.popContainer()
  398. }
  399. }
  400. extension _FirestoreEncoder: SingleValueEncodingContainer {
  401. // MARK: - SingleValueEncodingContainer Methods
  402. private func assertCanEncodeNewValue() {
  403. precondition(shouldAllocateNewContainer,
  404. "Attempt to encode value through single value container when previously value already encoded.")
  405. }
  406. public func encodeNil() throws {
  407. assertCanEncodeNewValue()
  408. storage.push(container: NSNull())
  409. }
  410. public func encode(_ value: Bool) throws {
  411. assertCanEncodeNewValue()
  412. storage.push(container: box(value))
  413. }
  414. public func encode(_ value: Int) throws {
  415. assertCanEncodeNewValue()
  416. storage.push(container: box(value))
  417. }
  418. public func encode(_ value: Int8) throws {
  419. assertCanEncodeNewValue()
  420. storage.push(container: box(value))
  421. }
  422. public func encode(_ value: Int16) throws {
  423. assertCanEncodeNewValue()
  424. storage.push(container: box(value))
  425. }
  426. public func encode(_ value: Int32) throws {
  427. assertCanEncodeNewValue()
  428. storage.push(container: box(value))
  429. }
  430. public func encode(_ value: Int64) throws {
  431. assertCanEncodeNewValue()
  432. storage.push(container: box(value))
  433. }
  434. public func encode(_ value: UInt) throws {
  435. assertCanEncodeNewValue()
  436. storage.push(container: box(value))
  437. }
  438. public func encode(_ value: UInt8) throws {
  439. assertCanEncodeNewValue()
  440. storage.push(container: box(value))
  441. }
  442. public func encode(_ value: UInt16) throws {
  443. assertCanEncodeNewValue()
  444. storage.push(container: box(value))
  445. }
  446. public func encode(_ value: UInt32) throws {
  447. assertCanEncodeNewValue()
  448. storage.push(container: box(value))
  449. }
  450. public func encode(_ value: UInt64) throws {
  451. assertCanEncodeNewValue()
  452. storage.push(container: box(value))
  453. }
  454. public func encode(_ value: String) throws {
  455. assertCanEncodeNewValue()
  456. storage.push(container: box(value))
  457. }
  458. public func encode(_ value: Float) throws {
  459. assertCanEncodeNewValue()
  460. storage.push(container: box(value))
  461. }
  462. public func encode(_ value: Double) throws {
  463. assertCanEncodeNewValue()
  464. storage.push(container: box(value))
  465. }
  466. public func encode<T: Encodable>(_ value: T) throws {
  467. assertCanEncodeNewValue()
  468. try storage.push(container: box(value))
  469. }
  470. }
  471. /// Special subclass of `_FirestoreEncoder` used by `superEncoder`.
  472. /// It inherits the codingPath from the referencing `_FirestoreEncoder` but uses its own
  473. /// storage. The encoded result will be written back to the referencing encoder's storage
  474. /// when it is `deinit`-ed.
  475. private class _FirestoreReferencingEncoder: _FirestoreEncoder {
  476. // MARK: Reference types.
  477. /// The type of container we're referencing, and where to write the encoded result to.
  478. private enum Reference {
  479. /// Referencing a specific index in an array container.
  480. case array(NSMutableArray, Int)
  481. /// Referencing a specific key in a dictionary container.
  482. case dictionary(NSMutableDictionary, String)
  483. }
  484. // MARK: - Properties
  485. /// The encoder we're referencing.
  486. private let encoder: _FirestoreEncoder
  487. /// The container reference itself.
  488. private let reference: Reference
  489. // MARK: - Initialization
  490. /// Initializes `self` by referencing the given array container in the given encoder.
  491. fileprivate init(referencing encoder: _FirestoreEncoder,
  492. at index: Int,
  493. wrapping array: NSMutableArray) {
  494. self.encoder = encoder
  495. reference = .array(array, index)
  496. super.init()
  497. codingPath = encoder.codingPath
  498. codingPath.append(_FirestoreKey(index: index))
  499. }
  500. /// Initializes `self` by referencing the given dictionary container in the given encoder.
  501. fileprivate init(referencing encoder: _FirestoreEncoder,
  502. at key: CodingKey,
  503. wrapping dictionary: NSMutableDictionary) {
  504. self.encoder = encoder
  505. reference = .dictionary(dictionary, key.stringValue)
  506. super.init()
  507. codingPath = encoder.codingPath
  508. codingPath.append(key)
  509. }
  510. // MARK: - Coding Path Operations
  511. fileprivate override var shouldAllocateNewContainer: Bool {
  512. // With a regular encoder, the storage and coding path grow together.
  513. // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for.
  514. // We have to take this into account.
  515. return storage.count == codingPath.count - encoder.codingPath.count - 1
  516. }
  517. // MARK: - Deinitialization
  518. // Finalizes `self` by writing the contents of our storage to the referenced encoder's storage.
  519. deinit {
  520. let value: Any
  521. switch storage.count {
  522. case 0: value = NSDictionary()
  523. case 1: value = self.storage.popContainer()
  524. default: fatalError("Referencing encoder deallocated with multiple containers on stack.")
  525. }
  526. switch self.reference {
  527. case let .array(array, index):
  528. array.insert(value, at: index)
  529. case let .dictionary(dictionary, key):
  530. dictionary[NSString(string: key)] = value
  531. }
  532. }
  533. }