containerization-framework 0.4.0

Rust bindings for Apple's Containerization framework: Linux containers in lightweight VMs, in-process and without a daemon.
//===----------------------------------------------------------------------===//
// `VmnetNetwork` and its `Interface`, from Containerization, and the
// `Network?` the manager's inits take.
//===----------------------------------------------------------------------===//

import Containerization
import ContainerizationExtras
import vmnet

/// A `Network?`.
final class CzNetwork: Sendable {
  let network: (any Network)?

  init(_ network: (any Network)?) {
    self.network = network
  }
}

func noNetwork() -> CzNetwork {
  CzNetwork(nil)
}

/// Unchecked: the interface methods mutate `network`, and Rust's `&mut self`
/// lets only one run at a time.
final class CzVmnetNetwork: @unchecked Sendable {
  var network: VmnetNetwork

  init(_ network: VmnetNetwork) {
    self.network = network
  }

  /// A copy, as Swift passes it to the manager.
  func asNetwork() -> CzNetwork {
    CzNetwork(network)
  }

  func subnet() -> CzOutcome {
    CzOutcome.holding(network.subnet)
  }

  func prefixV6() -> CzOutcome {
    CzOutcome.holding(network.prefixV6)
  }

  func ipv4Gateway() -> CzOutcome {
    CzOutcome.holding(network.ipv4Gateway)
  }

  func ipv6Gateway() -> CzOutcome {
    CzOutcome.holding(network.ipv6Gateway)
  }

  func createInterface(id: RustStr) -> CzOutcome {
    let id = id.toString()

    return CzOutcome { absent(try vmnetInterface(network.createInterface(id))) }
  }

  func createInterface(id: RustStr, mtu: UInt32) -> CzOutcome {
    let id = id.toString()

    return CzOutcome { absent(try vmnetInterface(network.createInterface(id, mtu: mtu))) }
  }

  func createInterfaceWithoutGateway(id: RustStr) -> CzOutcome {
    let id = id.toString()

    return CzOutcome { absent(try vmnetInterface(network.createInterfaceWithoutGateway(id))) }
  }

  func releaseInterface(id: RustStr) -> CzOutcome {
    let id = id.toString()

    return CzOutcome { try network.releaseInterface(id) }
  }
}

/// What `VmnetNetwork`'s `create` methods return, which is always one of its
/// own interfaces.
private func vmnetInterface(_ interface: (any Interface)?) -> CzVmnetInterface? {
  interface.map { interface in
    guard let interface = interface as? VmnetNetwork.Interface else {
      preconditionFailure("VmnetNetwork made a \(type(of: interface))")
    }
    return CzVmnetInterface(interface)
  }
}

/// Public because swift-bridge's glue for a Rust method that takes one is.
public final class CzVmnetInterface: Sendable {
  let interface: VmnetNetwork.Interface

  init(_ interface: VmnetNetwork.Interface) {
    self.interface = interface
  }

  func duplicate() -> CzVmnetInterface {
    CzVmnetInterface(interface)
  }

  func ipv4Address() -> CzOutcome {
    CzOutcome.holding(interface.ipv4Address)
  }

  func ipv4Gateway() -> CzOutcome {
    CzOutcome.holding(interface.ipv4Gateway)
  }

  func ipv6Address() -> CzOutcome {
    CzOutcome.holding(interface.ipv6Address)
  }

  func ipv6Gateway() -> CzOutcome {
    CzOutcome.holding(interface.ipv6Gateway)
  }

  func macAddress() -> CzOutcome {
    CzOutcome.holding(interface.macAddress)
  }

  func mtu() -> UInt32 {
    interface.mtu
  }
}

func vmnetNetwork(
  mode: VmnetMode,
  subnetAddress: UInt32?,
  subnetPrefix: UInt8,
  hasPrefixV6: Bool,
  prefixV6Address: RustIPv6Address,
  prefixV6Length: UInt8
) -> CzOutcome {
  let mode: operating_modes_t =
    switch mode {
    case .Shared: .VMNET_SHARED_MODE
    case .Host: .VMNET_HOST_MODE
    case .Bridged: .VMNET_BRIDGED_MODE
    }

  return CzOutcome {
    let subnet = try subnetAddress.map { try CIDRv4(bridged: $0, prefix: subnetPrefix) }
    let prefixV6 = hasPrefixV6 ? try CIDRv6(bridged: prefixV6Address, prefix: prefixV6Length) : nil

    return CzVmnetNetwork(try VmnetNetwork(mode: mode, subnet: subnet, prefixV6: prefixV6))
  }
}