(* Copyright (C) 2023--2025  Petter A. Urkedal <paurkedal@gmail.com>
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version, with the LGPL-3.0 Linking Exception.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * and the LGPL-3.0 Linking Exception along with this library.  If not, see
 * <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively.
 *)

(** Switch implementation used where not available.

    A switch provides scoped release of resources.  The signature here is
    provided on platforms where we don't use its native implementation, either
    because it does not exist or lacks functionality on which we rely. *)

module type S = sig
  type 'a fiber
  type t
  type hook

  exception Off

  (** {1 Explicit Construction and Release}

      The following functions are resource-unsafe, since do not scope the
      lifetime of constructed switches to a function call like {!run}.
      They are nevertheless useful for applications which do not follow the
      EIO-style resource handling discipline.
      The [caqti-eio] package uses the native EIO switch implementation, which
      excludes these functions. *)

  val eternal : t
  (** A switch which is never released. *)

  val create : unit -> t
  (** Create a fresh releasable switch which is initially on. *)

  val release : t -> unit fiber
  (** [release sw] calls all cleanup handlers on [sw] in reverse order of
      registration and marks the switch as being off. *)

  (** {1 EIO-Compatible Interface} *)

  val run : (t -> 'a fiber) -> 'a fiber
  (** [run f] calls [f] with a fresh switch which will be released upon exit or
      in case of failure. *)

  val check : t -> unit
  (** [check sw] raises [Off] if [sw] has been turned off. *)

  val on_release_cancellable : t -> (unit -> unit fiber) -> hook
  (** [on_release_cancellable sw f] registers [f] to be called upon the evetual
      release of [sw] unless {!remove_hook} is called on the returned hook
      before that happen. *)

  val remove_hook : hook -> unit
  (** Given a [hook] returned by {!on_release_cancellable}, [remove_hook hook]
      cancels the cleanup registered by that call. *)
end
