containerization-framework 0.3.0

Rust bindings for Apple's Containerization framework: Linux containers in lightweight VMs, in-process and without a daemon.
//===----------------------------------------------------------------------===//
// Rust's values for images, content and unpacking read into Containerization's,
// and a `Platform` filled back into Rust's.
//===----------------------------------------------------------------------===//

import Containerization
import ContainerizationEXT4
import ContainerizationExtras
import ContainerizationOCI
import Foundation

// MARK: Rust to Swift

extension Platform {
  init(_ platform: RustPlatformRef) {
    self.init(
      arch: platform.architecture().toString(),
      os: platform.os().toString(),
      osVersion: platform.osVersion()?.toString(),
      osFeatures: platform.hasOsFeatures() ? strings(platform.osFeaturesLen(), platform.osFeaturesAt) : nil,
      variant: platform.variant()?.toString()
    )
  }
}

extension Descriptor {
  init(_ descriptor: RustDescriptorRef) {
    self.init(
      mediaType: descriptor.mediaType().toString(),
      digest: descriptor.digest().toString(),
      size: descriptor.size(),
      urls: descriptor.hasUrls() ? strings(descriptor.urlsLen(), descriptor.urlsAt) : nil,
      annotations: descriptor.hasAnnotations()
        ? dictionary(descriptor.annotationsLen(), descriptor.annotationKeyAt, descriptor.annotationValueAt) : nil,
      platform: descriptor.hasPlatform() ? Platform(descriptor.platform()) : nil,
      artifactType: descriptor.artifactType()?.toString()
    )
  }
}

extension Containerization.Image.Description {
  init(_ description: RustImageDescription) {
    self.init(reference: description.reference().toString(), descriptor: Descriptor(description.descriptor()))
  }
}

extension EXT4Unpacker {
  init(_ unpacker: RustExt4Unpacker) {
    var journal: EXT4.JournalConfig?
    if unpacker.hasJournal() {
      var mode: EXT4.JournalConfig.JournalMode?
      if unpacker.hasJournalMode() {
        mode =
          switch unpacker.journalMode() {
          case .Writeback: .writeback
          case .Ordered: .ordered
          case .Journal: .journal
          }
      }
      journal = EXT4.JournalConfig(size: unpacker.journalSize(), defaultMode: mode)
    }

    self.init(capacityInBytes: unpacker.capacityInBytes(), journal: journal)
  }
}

/// Rust's `ProgressHandler?`. Swift may call it from several threads at once,
/// and Rust's is `Sync`.
func progressHandler(_ handler: RustProgressHandler) -> ProgressHandler? {
  guard handler.isSome() else {
    return nil
  }
  nonisolated(unsafe) let handler = handler

  return { events in
    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)
  }
}

// MARK: Swift to Rust

func currentPlatform() -> CzOutcome {
  CzOutcome { Platform.current }
}