diff --git a/Sources/Automerge/ChangeHash.swift b/Sources/Automerge/ChangeHash.swift index 43dd836f..f839f4ff 100644 --- a/Sources/Automerge/ChangeHash.swift +++ b/Sources/Automerge/ChangeHash.swift @@ -1,4 +1,5 @@ import AutomergeUniffi +import Foundation /// An opaque hash that represents a change within an Automerge document. public struct ChangeHash: Equatable, Hashable, CustomDebugStringConvertible, Sendable { @@ -9,3 +10,33 @@ public struct ChangeHash: Equatable, Hashable, CustomDebugStringConvertible, Sen bytes.map { String(format: "%02hhx", $0) }.joined() } } + +public extension Set { + + /// Transforms each `ChangeHash` in the set into its byte array (`[UInt8]`). This raw byte representation + /// captures the state of the document at a specific point in its history, allowing for efficient storage + /// and retrieval of document states. + func raw() -> Data { + let rawBytes = map(\.bytes).sorted { lhs, rhs in + lhs.debugDescription > rhs.debugDescription + } + return Data(rawBytes.joined()) + } +} + +public extension Data { + + /// Interprets the data to return the data as a set of change hashes that represent a state within an Automerge document. If the data is not a multiple of 32 bytes, returns nil. + func heads() -> Set? { + let rawBytes: [UInt8] = Array(self) + guard rawBytes.count % 32 == 0 else { return nil } + let totalHashes = rawBytes.count / 32 + let heads = (0..