containerization-framework 0.10.0

Rust bindings for Apple's Containerization framework: Linux containers in lightweight VMs, in-process and without a daemon.
//===----------------------------------------------------------------------===//
// ContainerizationExtras' `ProgressEvent`, `ProgressHandler` and `ProxyUtils`.
//===----------------------------------------------------------------------===//

import ContainerizationExtras
import Foundation

extension ProgressEvent {
  init(_ kind: ProgressKind, _ value: Int64) {
    self =
      switch kind {
      case .Items: .addItems(Int(value))
      case .TotalItems: .addTotalItems(Int(value))
      case .Size: .addSize(value)
      case .TotalSize: .addTotalSize(value)
      }
  }
}

/// Rust's `ProgressHandler?`. Swift may call it from several threads at once,
/// and Rust's is `Sync`. Swift's handler is `async`, so Rust's can run off the
/// cooperative pool, where it may call back into Swift.
func progressHandler(_ handler: RustProgressHandler) -> ProgressHandler? {
  guard handler.isSome() else {
    return nil
  }
  nonisolated(unsafe) let handler = handler

  return { events in
    await offPool { call(handler, with: events) }
  }
}

private func call(_ handler: RustProgressHandler, with events: [ProgressEvent]) {
  let kinds = RustVec<ProgressKind>()
  let values = RustVec<Int64>()
  for event in events {
    switch event {
    case .addItems(let value):
      kinds.push(value: .Items)
      values.push(value: Int64(value))
    case .addTotalItems(let value):
      kinds.push(value: .TotalItems)
      values.push(value: Int64(value))
    case .addSize(let value):
      kinds.push(value: .Size)
      values.push(value: value)
    case .addTotalSize(let value):
      kinds.push(value: .TotalSize)
      values.push(value: value)
    }
  }
  handler.call(kinds, values)
}

func progressEventEvent(kind: ProgressKind, value: Int64) -> CzOutcome {
  let event = ProgressEvent(kind, value)

  return CzOutcome { event.event }
}

/// The outcome holds the URL's `absoluteString`, or `Absent`.
func proxyFromEnvironment(
  scheme: RustString?,
  host: RustStr,
  hasEnv: Bool,
  envKeys: RustVec<RustString>,
  envValues: RustVec<RustString>
) -> CzOutcome {
  let scheme = scheme?.toString()
  let host = host.toString()
  let env = hasEnv ? dictionary(envKeys, envValues) : nil

  return CzOutcome {
    let proxy =
      if let env {
        ProxyUtils.proxyFromEnvironment(scheme: scheme, host: host, env: env)
      } else {
        ProxyUtils.proxyFromEnvironment(scheme: scheme, host: host)
      }

    return absent(proxy?.absoluteString)
  }
}