package provider

  1. Overview
  2. Docs

Manipulating the set of traits implemented by a provider.

This module provides functions for creating an interface, as well as retrieving and extending the traits implemented by an interface, making it easy to manage the functionalities that a provider supports.

type ('t, -'tags) t

An interface is essentially a collection of traits that a provider implements, each of which providing a specific functionality (one trait implementation = one first-class module with type t = 't).

  • 't is the internal state of the provider.
  • 'tags indicate which functionality are supported by the provider. It is a phantom type using polymorphic variants. To give an example, in the tests for this library, we have two modules defining each their own tag:
module Directory_reader = struct
  type tag = [ `Directory_reader ]
end

module File_reader = struct
  type tag = [ `File_reader ]
end

Then, the type of the interface for a provider whose internal state is state, that would implement both functionalities would be:

(state, [ Directory_reader.tag | File_reader.tag ]) Provider.Interface.t

Building interfaces

val make : 't Trait.Implementation.t Base.list -> ('t, _) t

make implementations create a new interface from a list of implementation. It only keeps the last implementation supplied for each trait. This means that the resulting interface will not contain any duplicate traits, and the order of the implementations in the input list can affect its contents.

val implementations : ('t, _) t -> 't Trait.Implementation.t Base.list

implementations t returns a list of trait implementations that the interface t supports. See also extend.

val extend : ('t, _) t -> with_:'t Trait.Implementation.t Base.list -> ('t, _) t

extend t ~with_ extends the interface t and returns a new interface that includes both the original and additional implementations. The resulting interface only contains the last occurrence of each trait, prioritizing the rightmost elements in the combined list implementations t @ with_.

Lookup

A lookup operation is used to retrieve the implementation of a specific trait within an interface.

val is_empty : ('t, _) t -> Base.bool

is_empty t checks if an interface t implements any traits. An empty interface may be created using make []. It will cause any lookup operation to fail. It can be useful for initializing data structures or providing a base case for algorithms that process interfaces.

val lookup : ('t, 'tags) t -> trait:('t, 'implementation, 'tags) Trait.t -> 'implementation

lookup t ~trait retrieves the implementation for a given trait from an interface.

If the provider has correctly exported their implementation using the appropriate tags, the compiler will ensure that this function does not fail in user code (a failure of this function would typically indicate a programming error in the provider's setup).

val lookup_opt : ('t, _) t -> trait:('t, 'implementation, _) Trait.t -> 'implementation Base.option

lookup_opt t ~trait returns the implementation of the trait (Some implementation) or indicates that the trait is not implemented (None).

This is particularly useful in scenarios where a part of a program needs to adapt behavior at runtime based on whether certain functionalities are available or not.

val implements : ('t, _) t -> trait:('t, _, _) Trait.t -> Base.bool

implements t ~trait says wether an interface implements a trait. This is true iif lookup_opt t ~trait returns Some _.