1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
use crate::Context;
/// A can construct a [`Service`] which references objects either inside itself or the provided
/// [`Context`].
///
/// Any type implementing the appropriate [`Fn`] trait can be used as a provider:
/// ```
/// # use dfdi::{Service, Context};
/// # use std::convert::Infallible;
/// // A service providing a random number
/// #[derive(Service)]
/// struct Random(u64);
///
/// // Create a context and bind Random to a provider
/// let mut cx = Context::new();
/// cx.bind_fn::<Random>(|_cx: &Context| Random(rand::random()));
///
/// // Print a random number
/// println!("{}", cx.resolve::<Random>().0);
/// ```
pub trait Provider<'cx, S: Service>: 'cx {
/// Build the output object
// #! Remember to keep in sync with `ProvideFn`
fn provide(&'cx self, cx: &'cx Context) -> S::Output<'cx>;
}
/// A pointer to the underlying provider function.
///
/// The first argument must be a pointer, otherwise miri's stacked borrows will reject this code.
/// This is because casting a `*const ()` to, say, a `&'cx ()` resizes the alloc range that the
/// reference has access to down to zero bytes, causing Miri to report undefined behaviour.
///
/// As such, it is up to the caller to ensure that the first argument lives for a lifetime of 'cx.
///
/// # SAFETY
/// - The first argument must have the correct type
/// - The first argument must live for 'cx
// #! This __MUST__ be kept in sync with `Provider::provide` or bad things will happen
pub(crate) type ProvideFn<'cx, S> =
unsafe fn(*const (), &'cx Context) -> <S as Service>::Output<'cx>;
/// A key to an object that can be created by a [`Provider`] and stored in a [`Context`].
///
/// In most cases, an implementation of this trait is trivial boilerplate, and so it is recommended
/// to use the provided derive macro.
pub trait Service: 'static {
/// The result of a service resolution
type Output<'cx>;
}