Expand description
Dynamically request arbitrarily-typed values from providers with borrowed data.
§Motivation
Rust’s Any trait allows for downcasting to access the underlying type of a dyn object. Unfortunately, this is limited to 'static types (types that contain no borrowed data) because there’s no way to distinguish types with different lifetimes by their TypeIds.
This crate provides the dynamically-sized Query type with lifetime parameters and an internal tag indicating what type of value it’s meant to hold,
potentially containing those lifetimes.
The Provide and ProvideRef traits supply values to queries, the latter being dyn-capable.
§Prior Art
§Concepts
Lifetime lists
Lists of lifetime variables are represented by types implementing Lt.
You can describe a lifetime list with the Lt! macro:
use dynamic_provider::Lt;
/// Lifetime list for retrieving values from `'data` with an argument that
/// borrows `'input`.
type CustomLifetimes<'data, 'input> = Lt!['data, 'input];
/// Prepend a `'local` lifetime to lifetime list `L`.
type PrependLifetime<'local, L> = Lt!['local, ..L];Type functions
TypeFn implementations describe a type that is parameterized over an arbitrary
lifetime list.
A simple type function can be described with the TypeFn! macro:
type RefPair<A, B> = dynamic_provider::TypeFn![for<'a, 'b> (&'a A, &'b B)];Providers
- [`Provide
`][`Provide`] -
Supplies values with the lifetime variables in
Lto theQueryobject passed to theprovide()method. - [`ProvideRef
`][`ProvideRef`] - ****
Supplies values from a reference to
Selfwith the lifetime of the reference and the lifetime variables inL.A reference to a
Provideimplementation (say,&'x impl ProvideRef<L>or&'x mut impl ProvideRef<L>) automatically implementsProvide<'x, ..L>for all'x.
§Examples
§Dynamic field access
use dynamic_provider::{define_tag, request, Lt, Provide, ProvideRef, Query};
define_tag! {
/// Represents dynamic access to a field.
///
/// The argument of type `&'key str` indicates the name of the field being
/// accessed.
pub tag Field<T: ?Sized>: for<'data, 'key> &'key str => &'data T;
}
struct MyData {
foo: String,
bar: String,
baz: Vec<u8>,
}
impl<'key> ProvideRef<Lt!['key]> for MyData {
fn provide_ref<'data>(&'data self, query: &mut Query<Lt!['data, 'key]>) {
query
.put_where::<Field<str>>(|key| *key == "foo", |_| &self.foo)
.put_where::<Field<str>>(|key| *key == "bar", |_| &self.bar)
.put_where::<Field<[u8]>>(|key| *key == "baz", |_| &self.baz);
}
}
/// Dynamically gets a reference to the field with name `key` and type `T`, if
/// provided.
fn get_field<'data, T: ?Sized + 'static>(
data: &'data dyn for<'key> ProvideRef<Lt!['key]>,
key: &str,
) -> Option<&'data T> {
request! { from data;
tag x: Field<T> where arg <- key => Some(x),
else => None,
}
}
// Retrieve fields from a value of type MyData:
let data = MyData {
foo: "foo!".into(),
bar: "bar!".into(),
baz: b"baz!".into(),
};
assert_eq!(get_field::<str>(&data, "foo").unwrap(), "foo!");
assert_eq!(get_field::<str>(&data, "bar").unwrap(), "bar!");
assert_eq!(get_field::<[u8]>(&data, "baz").unwrap(), b"baz!");
// Use () when you need an empty provider:
assert!(get_field::<str>(&(), "foo").is_none());§Features
§"alloc"
Adds the ProvideBox trait.
Adds trait implementations for Rc, Box, and String,
and enables additional provided values for std types.
Macros§
- Lifetime
Hkt - Evaluates to a
LifetimeHktimplementation. - Lt
- Evaluates to an
Ltimplementation with the given list of lifetime specifiers. - TypeFn
- Evaluates to a
TypeFnimplementation. - define_
tag - Declares one or more
ResourceTagimplementations. - request
- Requests one of a set of possible values, refs, or tags from a provider.
Structs§
- Mut
- A
ResourceTagthat corresponds to a unique reference to the output value ofTag. Can also be used as an operator onTypeFnimplementations. - Query
- A type-erased query ready to pass to
Provide::provide(). - Query
Using - Packs a context value of type
Calongside the query that will be passed to a function fulfilling the query. - Ref
- A
ResourceTagthat corresponds to a shared reference to the output value ofTag. Can also be used as an operator onTypeFnimplementations. - TagId
- A unique identifier for a specific
ResourceTag-implementing type. - Value
- A
TypeFnthat corresponds toTfor all lifetime arguments. Can be used as aResourceTagwhenThas a fixed size and contains no borrowed data (i.e.T: Sized + 'static). - When
Provider - Return type of
when_provider().
Traits§
- Lifetime
Hkt - Represents a type parameterized by a single lifetime.
The
LifetimeHkt!macro is used to get an implementation of this trait. - Lt
- Represents a list of zero or more lifetime variables
- Provide
- Provides access to values of arbitrary type.
- Provide
Box alloc - Provides values from a
Box. - Provide
Ref - Provides access to values of arbitrary type from a reference.
- Resource
Tag - A marker type used as a key for requesting values from
Provide. - TagFor
- A
ResourceTagthat is defined over the given lifetimes. - TypeFn
- Represents a type that is parameterized over one or more lifetime variables.
Functions§
- for_
each_ provided_ tag_ id - Given a provider, calls the given callback for each
TagIdit provides. - get_
provided_ tag_ ids - Given a provider, creates a collection of
TagIds it provides. - provide_
by_ ref_ with - Returns a
ProvideRefimplementation that delegates to the given function. - provide_
with - Returns a
Provideimplementation that delegates to the given function. - when_
provider - Helper function for requesting one of multiple possible values.
See also
request!andProvide::request().