(** Module layout information. Contains information about aliasing, wrapping. *)

open Import

type t

val to_dyn : t -> Dyn.t

val lib
  :  obj_dir:Path.Build.t
  -> main_module_name:Module_name.t option
  -> wrapped:Wrapped.t
  -> stdlib:Ocaml_stdlib.t option
  -> lib_name:Lib_name.Local.t
  -> implements:bool
  -> has_instances:bool
  -> modules:Module.t Module_trie.t
  -> for_:Compilation_mode.t
  -> t

val decode : src_dir:Path.t -> t Dune_lang.Decoder.t
val fold : t -> init:'acc -> f:(Module.t -> 'acc -> 'acc) -> 'acc

module Group : sig
  type t

  val alias : t -> Module.t
  val lib_interface : t -> Module.t
  val for_alias : t -> (Module_name.t * Module.t) list
end

val exe_unwrapped : Module.t Module_trie.t -> obj_dir:Path.Build.t -> t

val make_wrapped
  :  obj_dir:Path.Build.t
  -> modules:Module.t Module_trie.t
  -> has_instances:bool
  -> [ `Exe | `Melange ]
  -> t

val fold_user_written : t -> f:(Module.t -> 'acc -> 'acc) -> init:'acc -> 'acc
val map_user_written : t -> f:(Module.t -> Module.t Memo.t) -> t Memo.t
val fold_user_available : t -> f:(Module.t -> 'acc -> 'acc) -> init:'acc -> 'acc

module Sourced_module : sig
  type t =
    | Normal of Module.t
    | Imported_from_vlib of Module.t
    | Impl_of_virtual_module of Module.t Ml_kind.Dict.t

  val to_module : t -> Module.t
end

val obj_map : t -> Sourced_module.t Module_name.Unique.Map.t

(** Returns only the virtual module names in the library *)
val virtual_module_names : t -> Module_name.Path.Set.t

val wrapped : t -> Wrapped.t
val source_dirs : t -> Path.Set.t
val compat_for_exn : t -> Module.t -> Module.t

(** List of entry modules visible to users of the library. For wrapped
    libraries, this is always one module. For unwrapped libraries, this could
    be more than one. *)
val entry_modules : t -> Module.t list

module With_vlib : sig
  type modules := t
  type t

  val drop_vlib : t -> modules
  val to_dyn : t -> Dyn.t
  val encode : t -> src_dir:Path.t -> Dune_lang.t
  val impl : modules -> vlib:modules -> t

  val find_dep
    :  t
    -> of_:Module.t
    -> Module_name.t
    -> (Module.t list, [ `Parent_cycle ]) result

  (** Additional dependencies that aren't always reported by [ocamldep], such
      as `(modules_before_stdlib ..)` in `(stdlib ..)` libraries. *)
  val implicit_deps : t -> of_:Module.t -> Module.t list

  val find : t -> Module_name.t -> Module.t option
  val impl_only : t -> Module.t list

  (** A set of modules from a single module. Not suitable for single module exe as
      this produce an unwrapped set of modules. Use [singleton_exe] instead for
      executables. *)
  val singleton : Module.t -> t

  val canonical_path : t -> Group.t -> Module.t -> Module_name.Path.t

  val fold_no_vlib_with_aliases
    :  t
    -> init:'acc
    -> normal:(Module.t -> 'acc -> 'acc)
    -> alias:(Group.t -> 'acc -> 'acc)
    -> 'acc

  val map : t -> f:(Module.t -> Module.t) -> t

  (** For wrapped libraries, this is the user written entry module for the
      library. For single module libraries, it's the sole module in the library *)
  val lib_interface : t -> Module.t option

  (** Returns all the compatibility modules. *)
  val wrapped_compat : t -> Module.Name_map.t

  val version_installed : t -> src_root:Path.t -> install_dir:Path.t -> t
  val alias_for : t -> Module.t -> Module.t list
  val local_open : t -> Module.t -> Module_name.t list
  val is_stdlib_alias : t -> Module.t -> bool
  val exit_module : t -> Module.t option
  val as_singleton : t -> Module.t option

  type split_by_lib =
    { vlib : Module.t list
    ; impl : Module.t list
    }

  val split_by_lib : t -> split_by_lib

  (** [has_impl t] is true if there's at least one implementation in [t]*)
  val has_impl : t -> bool

  val modules : modules -> t
  val singleton_exe : Module.t -> t
  val obj_map : t -> Sourced_module.t Module_name.Unique.Map.t
  val wrapped : t -> Wrapped.t
end
