Row.swift 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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: AnyObject {
  21. associatedtype Column
  22. var properties: [TLV<Column, UInt32>] { get set }
  23. }
  24. extension Row where Self: Writable, Column: Writable {
  25. public func write(to output: Output) throws {
  26. try output.write(properties)
  27. }
  28. }
  29. extension Row where Column: Equatable {
  30. public subscript(_ column: Column) -> Bytes? {
  31. get { properties.first(where: { $0.type == column })?.value }
  32. set {
  33. properties.removeAll(column)
  34. guard let value = newValue else { return }
  35. let tlv = TLV<Column, UInt32>(type: column, value: value)
  36. properties.insert(tlv, at: 0)
  37. }
  38. }
  39. public func set(_ property: TLV<Column, UInt32>) {
  40. properties.removeAll(property.type)
  41. properties.insert(property, at: 0)
  42. }
  43. public func set(_ date: Date, at column: Column) {
  44. self[column] = Database.bytes(from: date)
  45. }
  46. public func date(at column: Column) -> Date? {
  47. guard let bytes = self[column] else { return nil }
  48. return Database.date(from: bytes)
  49. }
  50. public subscript<T>(_ column: Column) -> T? where T: BytesRepresentable {
  51. get { T?(self[column]) }
  52. set { self[column] = newValue?.bytes }
  53. }
  54. public func remove(_ column: Column) {
  55. properties.removeAll(column)
  56. }
  57. }
  58. extension Sequence where Element: Row, Element.Column: Equatable {
  59. public func first<T>(column: Element.Column, where predicate: (T) throws -> Bool) throws -> Element? where T: BytesRepresentable {
  60. try first(where: {
  61. guard let bytes = $0[column] else { return false }
  62. return try predicate(T(bytes))
  63. })
  64. }
  65. public func sorted<T>(column: Element.Column, by areInIncreasingOrder: (T, T) throws -> Bool) throws -> [Element] where T: BytesRepresentable {
  66. try sorted(by: {
  67. guard let rhs = $0[column], let lhs = $1[column] else { return false }
  68. return try areInIncreasingOrder(T(rhs),T(lhs))
  69. })
  70. }
  71. }