Convertible.swift 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Convertible.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 Foundation
  19. /// A type with a customized bytes representation.
  20. public protocol CustomBytesConvertible {
  21. /// A bytes representation of this instance.
  22. var bytes: Bytes { get }
  23. }
  24. public protocol LosslessBytesConvertible: CustomBytesConvertible {
  25. /// Instantiates an instance of the conforming type from bytes
  26. /// representation.
  27. init(_ bytes: Bytes) throws
  28. }
  29. // MARK: - Streamable Boolean Bytes
  30. extension Bool: LosslessBytesConvertible {
  31. public init(_ bytes: Bytes) throws {
  32. guard bytes.lenght == MemoryLayout<Self>.size else { throw BinaryError.invalidLenght }
  33. self = bytes.withUnsafeBytes { $0.load(as: Self.self) }
  34. }
  35. public var bytes: Bytes {
  36. withUnsafeBytes(of: self) { Bytes($0) }
  37. }
  38. }
  39. // MARK: - Streamable Integer
  40. extension LosslessBytesConvertible where Self: BinaryInteger {
  41. public init(_ bytes: Bytes) throws {
  42. guard bytes.lenght == MemoryLayout<Self>.size else { throw BinaryError.invalidLenght }
  43. self = bytes.withUnsafeBytes { $0.load(as: Self.self) }
  44. }
  45. public var bytes: Bytes {
  46. withUnsafeBytes(of: self) { Bytes($0) }
  47. }
  48. }
  49. extension Int: LosslessBytesConvertible {}
  50. extension Int8: LosslessBytesConvertible {}
  51. extension Int16: LosslessBytesConvertible {}
  52. extension Int32: LosslessBytesConvertible {}
  53. extension Int64: LosslessBytesConvertible {}
  54. extension UInt: LosslessBytesConvertible {}
  55. extension UInt8: LosslessBytesConvertible {}
  56. extension UInt16: LosslessBytesConvertible {}
  57. extension UInt32: LosslessBytesConvertible {}
  58. extension UInt64: LosslessBytesConvertible {}
  59. // MARK: - Streamable Floating Point
  60. extension LosslessBytesConvertible where Self: FloatingPoint {
  61. public init(_ bytes: Bytes) throws {
  62. guard bytes.lenght == MemoryLayout<Self>.size else { throw BinaryError.invalidLenght }
  63. self = bytes.withUnsafeBytes { $0.load(as: Self.self) }
  64. }
  65. public var bytes: Bytes {
  66. withUnsafeBytes(of: self) { Bytes($0) }
  67. }
  68. }
  69. extension Double: LosslessBytesConvertible {}
  70. extension Float: LosslessBytesConvertible {}
  71. // MARK: - RawRepresentable Bytes
  72. extension LosslessBytesConvertible where Self: RawRepresentable, RawValue: LosslessBytesConvertible {
  73. public init(_ bytes: Bytes) throws {
  74. let rawValue = try RawValue(bytes)
  75. guard let value = Self(rawValue: rawValue) else { throw BinaryError.invalidValue }
  76. self = value
  77. }
  78. public var bytes: Bytes { rawValue.bytes }
  79. }
  80. // MARK: - Bytes
  81. extension Bytes: LosslessBytesConvertible {
  82. public init(_ bytes: Bytes) throws {
  83. self = bytes
  84. }
  85. public var bytes: Bytes { self }
  86. }
  87. // MARK: - Bytes Array
  88. extension Array where Element == Bytes {
  89. subscript<T>(_ index: Int) -> T? where T: LosslessBytesConvertible {
  90. try? T(self[index])
  91. }
  92. }
  93. // MARK: - Bytes Dictionary
  94. extension Dictionary where Value == Bytes {
  95. subscript<T>(_ key: Key) -> T? where T: LosslessBytesConvertible {
  96. guard let bytes = self[key] else { return nil }
  97. return try? T(bytes)
  98. }
  99. }
  100. // MARK: - String Bytes
  101. extension String: LosslessBytesConvertible {
  102. public var bytes: Bytes { bytes(using: .utf8) ?? [] }
  103. public init(_ bytes: Bytes) throws {
  104. guard let string = String(bytes: bytes, encoding: .utf8) else { throw BinaryError.invalidValue }
  105. self = string
  106. }
  107. }
  108. // MARK: - Data Bytes
  109. extension Data: LosslessBytesConvertible {
  110. public var bytes: Bytes { Bytes(data: self) }
  111. public init(_ bytes: Bytes) throws {
  112. self = Data(bytes.rawValue)
  113. }
  114. }
  115. // MARK: - UUID Bytes
  116. extension UUID: LosslessBytesConvertible {
  117. public var bytes: Bytes {
  118. withUnsafeBytes(of: uuid) { Bytes($0) }
  119. }
  120. public init(_ bytes: Bytes) throws {
  121. guard bytes.lenght == MemoryLayout<uuid_t>.size else { throw BinaryError.invalidLenght }
  122. let uuid = bytes.withUnsafeBytes { $0.load(as: uuid_t.self) }
  123. self = UUID(uuid: uuid)
  124. }
  125. }
  126. extension Optional where Wrapped: LosslessBytesConvertible {
  127. public init(_ bytes: Bytes?) {
  128. if let bytes = bytes, let wrapped = try? Wrapped(bytes) {
  129. self = .some(wrapped)
  130. } else {
  131. self = .none
  132. }
  133. }
  134. }