///|
/// Preserve segmented execution state instead of silently flattening CS:IP.
pub(all) enum EntryPoint {
  Linear(Int64)
  Segment(Int, Int)
} derive(Eq, Debug)

///|
/// Validated execution address in the same address space as payload.
pub fn EntryPoint::address(self : EntryPoint) -> Int64 raise FirmwareError {
  match self {
    Linear(address) => {
      ignore(data_range(address, 0))
      address
    }
    Segment(cs, ip) => {
      if cs < 0 || cs > 65535 || ip < 0 || ip > 65535 {
        raise FirmwareError(
          diagnostic(AddressOverflow, "CS and IP must be 16-bit values"),
        )
      }
      cs.to_int64() * 16L + ip.to_int64()
    }
  }
}

///|
/// Provenance survives decoding. Checksums describe source records, not hashes.
pub(all) enum ChecksumStatus {
  Verified
  NotApplicable
  Derived
} derive(Eq, Debug)

///|
/// Original record statistics and S0 header bytes, with no lossy text decoding.
pub(all) struct Metadata {
  source_format : Format
  record_counts : Array[Int]
  header : Bytes?
  checksum_status : ChecksumStatus
} derive(Eq, Debug)

///|
/// Metadata for an image assembled in memory or transformed after parsing.
pub fn Metadata::new(format : Format) -> Metadata {
  {
    source_format: format,
    record_counts: Array::make(10, 0),
    header: None,
    checksum_status: if format == RawBinary {
      NotApplicable
    } else {
      Derived
    },
  }
}

///|
/// An owned sparse map, optional entry point, source metadata and warnings.
pub(all) struct FirmwareImage {
  memory : MemoryMap
  entry : EntryPoint?
  metadata : Metadata
  warnings : Array[Diagnostic]
}

///|
/// Empty image with unknown origin.
pub fn FirmwareImage::new() -> FirmwareImage {
  {
    memory: MemoryMap::new(),
    entry: None,
    metadata: Metadata::new(Unknown),
    warnings: [],
  }
}

///|
/// Deep-copy mutable state, including metadata counters and diagnostics array.
pub fn FirmwareImage::copy(self : FirmwareImage) -> FirmwareImage {
  {
    memory: self.memory.copy(),
    entry: self.entry,
    metadata: {
      ..self.metadata,
      record_counts: self.metadata.record_counts.copy(),
    },
    warnings: self.warnings.copy(),
  }
}

///|
/// Construct a raw binary image with explicit placement.
pub fn FirmwareImage::from_binary(
  bytes : Bytes,
  base_address : Int64,
) -> FirmwareImage raise FirmwareError {
  let memory = MemoryMap::new()
  memory.insert(base_address, bytes)
  { memory, entry: None, metadata: Metadata::new(RawBinary), warnings: [], }
}

///|
/// Compare memory and exact execution state, ignoring serialization metadata.
pub fn FirmwareImage::semantic_equal(
  self : FirmwareImage,
  other : FirmwareImage,
) -> Bool {
  self.entry == other.entry && self.memory.same_memory(other.memory)
}