Row.swift 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Row.swift
  2. // This file is part of KeePass.swift
  3. //
  4. // Copyright © 2021 Maxime Epain. All rights reserved.
  5. //
  6. // KeePass.swift 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. // KeePass.swift 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 KeePass.swift. If not, see <https://www.gnu.org/licenses/>.
  18. import Binary
  19. import Foundation
  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: LosslessBytesConvertible {
  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?
  60. where T: LosslessBytesConvertible {
  61. try first(where: {
  62. guard let bytes = $0[column] else { return false }
  63. return try predicate(T(bytes))
  64. })
  65. }
  66. public func sorted<T>(column: Element.Column, by areInIncreasingOrder: (T, T) throws -> Bool) throws -> [Element]
  67. where T: LosslessBytesConvertible {
  68. try sorted(by: {
  69. guard let rhs = $0[column], let lhs = $1[column] else { return false }
  70. return try areInIncreasingOrder(T(rhs), T(lhs))
  71. })
  72. }
  73. }