///|
pub suberror SnapshotCodecError {
  UnsupportedVersion(Int)
  InvalidSnapshot(String)
} derive(Eq, Debug)

///|
pub fn snapshot_to_json(snapshot : Snapshot, pretty? : Bool = true) -> String {
  let json = ToJson::to_json(snapshot)
  if pretty {
    json.stringify(indent=2)
  } else {
    json.stringify()
  }
}

///|
pub fn snapshot_from_json(source : String) -> Snapshot raise {
  try {
    let snapshot : Snapshot = @json.from_json(@json.parse(source))
    if snapshot.format_version != 1 {
      raise UnsupportedVersion(snapshot.format_version)
    }
    for entry in snapshot.entries {
      if entry.path != normalize_relative_path(entry.path) {
        raise InvalidSnapshot(
          "Entry path is not a normalized relative path: " + entry.path,
        )
      }
      if entry.size < 0L {
        raise InvalidSnapshot("Entry size cannot be negative: " + entry.path)
      }
    }
    snapshot
  } catch {
    UnsupportedVersion(_) as error => raise error
    InvalidSnapshot(_) as error => raise error
    error => raise InvalidSnapshot(@debug.to_string(error))
  }
}

///|
pub async fn write_snapshot(path : String, snapshot : Snapshot) -> Unit {
  @fs.write_file(path, snapshot_to_json(snapshot))
}

///|
pub async fn read_snapshot(path : String) -> Snapshot {
  let data = @fs.read_file(path)
  snapshot_from_json(data.text())
}

///|
pub async fn write_text_file(path : String, content : String) -> Unit {
  @fs.write_file(path, content)
}