type t = Unix.stats

let null_stat =
  { Unix.
    st_dev = -1; st_ino = -1; st_kind = Unix.S_REG; st_nlink = -1;
    st_perm = -1; st_uid = -1; st_gid = -1; st_rdev = -1; st_size = -1;
    st_atime = nan; st_mtime = nan; st_ctime = nan }

let get_res filename =
  try Result.ok @@ Unix.stat filename
  with _ -> Error ("Stat for" ^ filename ^ "couldn't be gathered")

let get filename =
  match get_res filename with Ok fn -> fn | Error _ -> null_stat

let check a b =
  a == b || (
    (a != null_stat) && (b != null_stat) &&
    let open Unix in
    a.st_mtime = b.st_mtime &&
    a.st_size = b.st_size &&
    a.st_ino = b.st_ino &&
    a.st_dev = b.st_dev
  )

let cache = ref None

let with_cache k =
  Std.let_ref cache (Some (Hashtbl.create 7)) k

let get filename =
  match !cache with
  | None -> get filename
  | Some table ->
    match Hashtbl.find table filename with
    | stats ->
      Logger.log ~section:"stat_cache" ~title:"reuse cache" "%s" filename;
      stats
    | exception Not_found ->
      let stats = get filename in
      Hashtbl.add table filename stats;
      stats
