field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraNativeRecoverySchedule.swift (3040B)


      1 import Foundation
      2 import TeraKitBindings
      3 
      4 struct TeraNativeRecoverySchedule: Sendable, Equatable {
      5   let author: String
      6   let revision: UInt64
      7   let after: String?
      8 }
      9 
     10 extension TeraRuntimeBackend {
     11   func nativeRecoverySchedule() async throws -> TeraNativeRecoverySchedule {
     12     throw TeraComposerAcknowledgment.unconfirmed
     13   }
     14 
     15   func advanceNativeRecoverySchedule(expected _: TeraNativeRecoverySchedule, after _: String?) async throws -> TeraNativeRecoverySchedule {
     16     throw TeraComposerAcknowledgment.unconfirmed
     17   }
     18 }
     19 
     20 extension TeraRuntimeClient {
     21   func nativeRecoverySchedule() async throws -> TeraNativeRecoverySchedule {
     22     try await addOperation("runtime.recovery.schedule") { try await $0.nativeRecoverySchedule() }
     23   }
     24 
     25   func advanceNativeRecoverySchedule(expected: TeraNativeRecoverySchedule, after: String?) async throws -> TeraNativeRecoverySchedule {
     26     try await addOperation("runtime.recovery.schedule.advance") { try await $0.advanceNativeRecoverySchedule(expected: expected, after: after) }
     27   }
     28 }
     29 
     30 extension TeraGeneratedRuntimeBackend {
     31   func nativeRecoverySchedule() async throws -> TeraNativeRecoverySchedule {
     32     do {
     33       return try await runtime.nativeRecoverySchedule(schemaVersion: 1).appValue()
     34     } catch { throw TeraGeneratedRuntimeFailure.from(error) }
     35   }
     36 
     37   func advanceNativeRecoverySchedule(expected: TeraNativeRecoverySchedule, after: String?) async throws -> TeraNativeRecoverySchedule {
     38     do {
     39       let value = try await runtime.advanceNativeRecoverySchedule(expected: .init(schemaVersion: 1, author: expected.author,
     40                                                                                   revision: expected.revision, after: expected.after), after: after).appValue()
     41       guard value.author == expected.author, value.after == after,
     42             value.revision == expected.revision + (expected.after == after ? 0 : 1)
     43       else { throw TeraComposerAcknowledgment.unconfirmed }
     44       return value
     45     } catch { throw TeraGeneratedRuntimeFailure.from(error) }
     46   }
     47 }
     48 
     49 private extension FfiNativeRecoverySchedule {
     50   func appValue() throws -> TeraNativeRecoverySchedule {
     51     let canonical = { (value: String) in value.utf8.count == 64 && value.utf8.allSatisfy { (48 ... 57).contains($0) || (97 ... 102).contains($0) } }
     52     guard schemaVersion == 1, canonical(author), revision <= UInt64(Int64.max),
     53           after.map(canonical) ?? true, revision > 0 || after == nil
     54     else { throw TeraComposerAcknowledgment.unconfirmed }
     55     return .init(author: author, revision: revision, after: after)
     56   }
     57 }
     58 
     59 /// One pass owns this handle. Failed persistence never advances its local view.
     60 actor TeraNativeRecoveryContinuation {
     61   private var value: TeraNativeRecoverySchedule
     62   private let client: TeraRuntimeClient
     63 
     64   init(_ value: TeraNativeRecoverySchedule, client: TeraRuntimeClient) {
     65     self.value = value
     66     self.client = client
     67   }
     68 
     69   func advance(_ after: String?) async throws {
     70     value = try await client.advanceNativeRecoverySchedule(expected: value, after: after)
     71   }
     72 }