Row.swift 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Row.swift
  2. // This file is part of KeePassKit.
  3. //
  4. // Copyright © 2019 Maxime Epain. All rights reserved.
  5. //
  6. // KeePassKit is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // KeePassKit is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with KeePassKit. If not, see <https://www.gnu.org/licenses/>.
  18. import Foundation
  19. import Binary
  20. public typealias Property<Type> = TLV<Type, UInt32>
  21. public protocol Row: class {
  22. associatedtype `Type`: Streamable, Equatable
  23. static var End: Type { get }
  24. var properties: [Property<Type>] { get set }
  25. init()
  26. }
  27. extension Row {
  28. public subscript(_ type: Type) -> Bytes? {
  29. get { properties.first(where: { $0.type == type })?.value }
  30. set {
  31. properties.removeAll(type)
  32. guard let value = newValue else { return }
  33. let tlv = Property(type: type, value: value)
  34. properties.insert(tlv, at: 0)
  35. }
  36. }
  37. public func set(_ field: Property<Type>) {
  38. properties.removeAll(field.type)
  39. properties.insert(field, at: 0)
  40. }
  41. public func set(_ date: Date, at type: Type) {
  42. self[type] = Database.bytes(from: date)
  43. }
  44. public func date(at type: Type) -> Date? {
  45. guard let bytes = self[type] else { return nil }
  46. return Database.date(from: bytes)
  47. }
  48. public subscript<T>(_ type: Type) -> T? where T: BytesRepresentable {
  49. get {
  50. guard let bytes = self[type] else { return nil }
  51. return try? T(bytes)
  52. }
  53. set { self[type] = newValue?.bytes }
  54. }
  55. public func remove(_ type: Type) {
  56. properties.removeAll(type)
  57. }
  58. }
  59. extension Readable where Self: Row {
  60. public init(from input: Input) throws {
  61. self.init()
  62. while true {
  63. let field = try input.read() as Property<Type>
  64. guard field.type != Self.End else { break }
  65. properties.append(field)
  66. }
  67. }
  68. }
  69. extension Writable where Self: Row {
  70. public func write(to output: Output) throws {
  71. try output.write(properties)
  72. let end = Property(type: Self.End, value: [])
  73. try output.write(end)
  74. }
  75. }
  76. extension Sequence where Element: Row {
  77. public func first<T>(where type: Element.`Type`, _ predicate: (T) throws -> Bool) throws -> Element? where T: BytesRepresentable {
  78. return try first(where: {
  79. guard let bytes = $0[type] else { return false }
  80. return try predicate(try T(bytes))
  81. })
  82. }
  83. public func sorted<T>(field: Element.`Type`, by areInIncreasingOrder: (T, T) throws -> Bool) throws -> [Self.Element] where T: BytesRepresentable {
  84. return try sorted(by: {
  85. guard let rhs = $0[field], let lhs = $1[field] else { return false }
  86. return try areInIncreasingOrder(try T(rhs), try T(lhs))
  87. })
  88. }
  89. }