supply 0.3.1

Provider API for arbitrary number of lifetimes.
Documentation
//! [`supply`](crate) implements an API similar to that proposed in
//! [RFC 3192](https://rust-lang.github.io/rfcs/3192-dyno.html).
//! It was proposed to provide [`Error`](core::error::Error) and API to expose extra context
//! information for errors. While the original RFC was a general API, the current implementation in
//! `core`/`std` is specifically for `Error`. The original proof of concept implementation can be
//! found at <https://github.com/nrc/provide-any>.
//!
//! [`supply`](crate) is a reimagining of the provide API to be more flexable and general purpose.
//! The motivation section of RFC 3192 states the problem this API is trying to solve very well.
//!
//! > However, in practice some kind of partial abstraction is required, where objects are treated
//! > abstractly but can be queried for data only present in a subset of all types which implement
//! > the trait interface. In this case there are only bad options: speculatively downcasting to
//! > concrete types (inefficient, boilerplatey, and fragile due to breaking abstraction) or adding
//! > numerous methods to the trait which might be functionally implemented, typically returning an
//! > Option where None means not applicable for the concrete type (boilerplatey, confusing, and
//! > leads to poor abstractions).
//!
//! <sub> <https://rust-lang.github.io/rfcs/3192-dyno.html#motivation> </sub>
//!
//! A similar pattern that is very useful but rarely seen in the wild is that proposed by
//! [`gdbstub`](https://docs.rs/gdbstub/latest/gdbstub/target/ext/index.html).
//! That of so called Inlineable Dyn Extension Traits (IDETs). You can think of the provide API
//! as an abstract form of this pattern.
//!
//! The core idea of the provide pattern is to use an output parameter to receive a type erased value.
//!
//! You may ask why just returning a type erased value is an issue, and its a good question. The
//! answer is that returning ownership directly requires something like a `Box`. However, we
//! don't always have access to a box or don't want the extra allocation. But wait what if we just
//! returned a `&dyn Any`? This doesn't need a box. However, this prevents returning owned values.
//! We are limited to things that can be borrowed from the source.
//!
//! Instead we take another approach. We construct a "hole". A place a value should go. We then
//! give a borrow of this hole to a value for it to "fill".
//!
//! This design has some major advantages.
//! For one it solves the returning ownership issue. Instead the provider transfers ownership into
//! the existing hole we gave it. Because as the requester we know the type of data we want we can
//! use some stack space to store the hole and eventual value.
//! Additionally, this design allows a requester to change the behavior of the hole. For example
//! we can have many holes that all need to be filled by the provider in one operation.
//!
//! Another aspect that `supply` expands on over the RFC is the use of arbitrary length lifetime
//! lists. We won't get into those here. See the [`ty-tag`](https://crates.io/crates/ty-tag) crate for
//! more information about those.
//!
//! Connecting this theoretical design to `supply`'s implementation we get the following.
//! The hole is represented by something implementing the [`Want`] trait. This trait has methods
//! for providing it a value to store. The provider then implements [`Provider`] and when it's
//! methods are called provides any values it can to the passed in want.
//!
//! A requester uses a provider by first constructing an empty [`Want`] implementer. Then, the
//! requester calls `.provide()` on the [`Provider`] to give the want a value. Then the requester
//! can remove the value from the want and use it however it needs to. Using [`ProviderExt`] we
//! can use a simple method
//! call of the form `provider.request::<Request>()` to request values from a provider.
//!
//! It is recommended to use the prelude which has the common API elements.
//! ```
//! use supply::prelude::*;
//! ```
//!
//! Most users should start with implementing the [`Provider`] trait on one or more
//! types they want to expose extra information from. Then the `.request::<T>()` method
//! can be used to request a specific type of information from the provider. This
//! is the core API flow of `supply`. Below is an example with a couple of the more advanced
//! features for demonstration.
//!
//! ### Examples
//!
//! ```
//! use supply::prelude::*;
//!
//! struct Person<'a> {
//!     name: &'a str,
//!     age: u8,
//! }
//!
//! // Implementing Provider allows requesting data from a Person value.
//! impl<'r, 'a> Provider<'r> for Person<'a> {
//!     type Lifetimes = l!['a];
//!
//!     fn provide(&'r self, want: &mut dyn Want<Self::Lifetimes>) {
//!         // Provide the name and age fields.
//!         want.provide_value(self.name)
//!             .provide_value(self.age);
//!     }
//! }
//!
//! // Make an example person to request data from.
//! let name = String::from("bob");
//!
//! let provided_name;
//! {
//!     let person = Person {
//!         name: &name,
//!         age: 42,
//!     };
//!
//!     // Convert to a trait object to show Provider is object safe.
//!     let provider: &dyn ProviderDyn<l!['_]> = &person;
//!
//!     // Request the person's name.
//!     provided_name = provider.request::<&str>();
//!     assert_eq!(provided_name, Some("bob"));
//!
//!     // Request the person's age.
//!     let provided_age = provider.request::<u8>();
//!     assert_eq!(provided_age, Some(42));
//!
//!     // Request something Person doesn't provide.
//!     // We just don't get a value from the request.
//!     let provided_something = provider.request::<f32>();
//!     assert_eq!(provided_something, None);
//! };
//!
//! // Because the name was tagged as &'a str we can still access it here.
//! assert_eq!(provided_name, Some("bob"));
//! ```
//!
//! ## `no_std` Support
//!
//! This crate is always `#![no_std]`, it can be used anywhere Rust can.
//!
//! ## Minimum Supported Rust Version
//!
//! Requires Rust 1.83.0.
//!
//! This crate follows the ["Latest stable Rust" policy](https://gist.github.com/alexheretic/d1e98d8433b602e57f5d0a9637927e0c). The listed MSRV won't be changed unless needed.
//! However, updating the MSRV anywhere up to the latest stable at time of release
//! is allowed.

#![cfg_attr(not(test), no_std)]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![warn(clippy::multiple_unsafe_ops_per_block)]
#![warn(unsafe_op_in_unsafe_fn)]

pub mod provide;
mod request;
pub mod want;

/// Commonly needed traits.
pub mod prelude {
    /// Re-export from `ty-tag`.
    #[doc(inline)]
    pub use ty_tag::l;

    pub use crate::provide::ProviderDyn;
    pub use crate::{Provider, ProviderExt, Want};
}

pub use request::*;
use ty_tag::lifetime_list::{LifetimeList, L0};
use ty_tag::TagTypeId;
use want::ErasedWantFor;

/// Provider of values.
///
/// Provided values may contain lifetimes from the `Self` type and the `'r` lifetime.
pub trait Provider<'r> {
    /// Lifetimes the provider wants to use.
    ///
    /// A lifetime cannot be used in [`Self::provide`] or [`Self::provide_mut`]
    /// unless it is named in this associated type.
    type Lifetimes: LifetimeList;

    /// Provide values given a `&T`.
    ///
    /// Values are provided to the passed in [`Want`].
    ///
    /// The default impl provides no values.
    fn provide(&'r self, want: &mut dyn Want<Self::Lifetimes>) {
        _ = want;
    }

    /// Provide values given a `&mut T`.
    ///
    /// Values are provided to the passed in [`Want`]. It is recommended that implementers
    /// call `provide` in addition to `&mut self` unique values.
    ///
    /// The default impl calls `self.provide`.
    fn provide_mut(&'r mut self, want: &mut dyn Want<Self::Lifetimes>) {
        self.provide(want);
    }
}

/// A want for some number of values.
pub trait Want<L: LifetimeList = L0> {
    /// Try to get a [`WantFor`](want::WantFor) for the type described by `tag_type_id`.
    ///
    /// In most cases `<dyn Want>::try_for` should be used instead.
    ///
    /// Returning `Some` from this method means the want will accept a value
    /// of the described type to become partially or fully satisfied.
    ///
    /// When implementing this method the returned [`ErasedWantFor`] should be downcastable
    /// to a `&mut dyn WantFor<T::Reified>` where `T` is the tag type given by `tag_type_id`.
    /// If this is not the case then the returned value is likely to be ignored as invalid.
    fn try_for_id(&mut self, tag_type_id: TagTypeId<L>) -> Option<ErasedWantFor<'_, L>>;

    /// Checks if the want is fully satisfied.
    ///
    /// Once satisfied, no more values need to be provided.
    fn is_satisfied(&self) -> bool {
        false
    }
}