Row.swift 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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 protocol Row {
  21. associatedtype Field: Streamable, Equatable
  22. init()
  23. var fields: [TLV<Field, UInt32>] { get set }
  24. static var End: Field { get }
  25. }
  26. extension Row {
  27. public subscript (_ field: Field) -> Bytes? {
  28. get { fields.first(where: { $0.type == field })?.value }
  29. set {
  30. fields.removeAll(where: { $0.type == field })
  31. guard let value = newValue else { return }
  32. let tlv = TLV<Field, UInt32>(type: field, value: value)
  33. fields.insert(tlv, at: 0)
  34. }
  35. }
  36. public subscript <T>(_ field: Field) -> T? where T: BytesRepresentable {
  37. get {
  38. guard let bytes = self[field] else { return nil }
  39. return try? T(bytes)
  40. }
  41. set { self[field] = newValue?.bytes }
  42. }
  43. }
  44. extension Readable where Self: Row {
  45. public init(from input: Input) throws {
  46. self.init()
  47. while true {
  48. let field: TLV<Field, UInt32> = try input.read()
  49. guard field.type != Self.End else { break }
  50. fields.append(field)
  51. }
  52. }
  53. }
  54. extension Writable where Self: Row {
  55. public func write(to output: Output) throws {
  56. try output.write(fields)
  57. let end = TLV<Field, UInt32>(type: Self.End, value: [])
  58. try output.write(end)
  59. }
  60. }
  61. extension Sequence where Element: Row {
  62. public func first<T>(where field: Element.Field, _ predicate: (T) throws -> Bool) throws -> Element? where T: BytesRepresentable {
  63. return try first(where: {
  64. guard let bytes = $0[field] else { return false }
  65. return try predicate(try T(bytes))
  66. })
  67. }
  68. public func sorted<T>(field: Element.Field, by areInIncreasingOrder: (T, T) throws -> Bool) throws -> [Self.Element] where T: BytesRepresentable {
  69. return try sorted(by: {
  70. guard let rhs = $0[field], let lhs = $1[field] else { return false }
  71. return try areInIncreasingOrder(try T(rhs), try T(lhs))
  72. })
  73. }
  74. }