| Crates.io | dynamic-provider |
| lib.rs | dynamic-provider |
| version | 0.1.2 |
| created_at | 2025-01-27 06:22:24.698388+00 |
| updated_at | 2025-01-27 09:07:00.1625+00 |
| description | Dynamically request arbitrarily-typed values from providers with borrowed data. |
| homepage | |
| repository | https://github.com/youngspe/dynamic-provider.rs |
| max_upload_size | |
| id | 1532076 |
| size | 83,080 |
Dynamically request arbitrarily-typed values from providers with borrowed data.
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.
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];
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)];
Supplies values with the lifetime variables in L to the Query object passed to the
provide() method.
Supplies values from a reference to Self with the lifetime of the reference and the lifetime
variables in L.
A reference to a Provide implementation (say, &'x impl ProvideRef<L> or &'x mut impl ProvideRef<L>) automatically implements Provide<'x, ..L> for all 'x.
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());
"alloc"Adds the ProvideBox trait.
Adds trait implementations for Rc, Box, and String,
and enables additional provided values for std types.