dynamic_provider/
provide.rs

1use core::{
2    convert::{identity, Infallible},
3    marker::PhantomData,
4    ptr::NonNull,
5};
6
7use crate::{
8    query::QueryUsing,
9    tag::{Mut, Ref, TagFor, Value},
10    Lt, Query, TagId,
11};
12
13/// Provides access to values of arbitrary type.
14///
15/// Requested values are specified using a [`ResourceTag`][crate::ResourceTag] implementation, or to be more specific, a [`TagFor<L>`]
16/// implementation.
17pub trait Provide<L: Lt = ()>: Sized {
18    /// Supplies the requested value to the given [`Query`], if available.
19    ///
20    /// Implementations are expected to return `Some(self)` if the query was not fulfilled.
21    fn provide(self, query: &mut Query<'_, L>) -> Option<Self>;
22
23    /// Requests the value specified by `Tag`. Returns `Err(self)` if the value was not available.
24    ///
25    /// `arg` should contain whatever data is needed to request the tagged type.
26    /// If no arguments are necessary, this will usually be the unit type `()`.
27    fn request<Tag: TagFor<L>>(self, arg: Tag::ArgValue) -> Result<Tag::Value, Self> {
28        match Query::new_with::<Tag, _>(|q| self.provide(q), arg) {
29            (_, Some(value)) => Ok(value),
30            (Some(this), None) => Err(this),
31            (None, None) => panic!("'self' not returned when 'provide' failed"),
32        }
33    }
34
35    /// Requests a value of type `T`, marked by the tag [`Value<T>`].
36    /// Values of type `T` must not hold any borrowed data.
37    fn request_value<T: 'static>(self) -> Result<T, Self> {
38        self.request::<Value<T>>(())
39    }
40
41    /// Requests a shared reference to a value of type `T`, marked by the tag [`Ref<Value<T>>`].
42    /// Values of type `T` must not hold any borrowed data.
43    fn request_ref<'x, T: 'static + ?Sized>(self) -> Result<&'x T, Self>
44    where
45        Ref<Value<T>>: TagFor<L, ArgValue = (), Value = &'x T>,
46    {
47        self.request::<Ref<Value<T>>>(())
48    }
49
50    /// Requests a unique reference to a value of type `T`, marked by the tag [`Mut<Value<T>>`].
51    /// Values of type `T` must not hold any borrowed data.
52    fn request_mut<'x, T: 'static + ?Sized>(self) -> Result<&'x mut T, Self>
53    where
54        Mut<Value<T>>: TagFor<L, ArgValue = (), Value = &'x mut T>,
55    {
56        self.request::<Mut<Value<T>>>(())
57    }
58}
59
60impl<L: Lt, P: Provide<L>> Provide<L> for Option<P> {
61    fn provide(self, query: &mut Query<'_, L>) -> Option<Self> {
62        self.map(|this| this.provide(query))
63    }
64
65    fn request<Tag: TagFor<L>>(self, arg: Tag::ArgValue) -> Result<Tag::Value, Self> {
66        match Query::new_with::<Tag, _>(|q| self?.provide(q), arg) {
67            (_, Some(value)) => Ok(value),
68            (this, None) => Err(this),
69        }
70    }
71}
72
73impl<LTail: Lt, P: ProvideRef<LTail>> ProvideRef<LTail> for &mut Option<P> {
74    fn provide_ref<'this>(&'this self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
75        if let Some(this) = self {
76            this.provide_ref(query);
77        }
78    }
79
80    fn provide_mut<'this>(&'this mut self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
81        if let Some(this) = self {
82            this.provide_mut(query);
83        }
84    }
85}
86
87/// Provides access to values of arbitrary type from a reference.
88///
89/// Requested values are specified using a [`ResourceTag`][crate::ResourceTag] implementation,
90/// or to be more specific, a [`TagFor<LTail>`]
91/// implementation.
92///
93/// `ProvideRef` implementations autmatically implement [`Provide<Lt!['x, ..LTail]>`][Provide] for all `'x`.
94pub trait ProvideRef<LTail: Lt = ()> {
95    /// Supplies the requested value to the given [`Query`] from a shared reference to `Self`, if available.
96    ///
97    /// The default implementation supplies nothing;
98    /// override this method to supply values from a shared reference.
99    fn provide_ref<'this>(&'this self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
100        let _ = query;
101    }
102
103    /// Supplies the requested value to the given [`Query`] from a unique reference to `Self`, if available.
104    ///
105    /// The default implementation supplies nothing;
106    /// override this method to supply values from a shared reference.
107    fn provide_mut<'this>(&'this mut self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
108        let _ = query;
109    }
110}
111
112impl<'x, P: ?Sized + ProvideRef<LTail>, LTail: Lt> Provide<Lt!['x, ..LTail]> for &'x P {
113    fn provide(self, query: &mut Query<'_, Lt!['x, ..LTail]>) -> Option<Self> {
114        self.provide_ref(query);
115
116        Some(self)
117    }
118}
119
120impl<'x, P: ?Sized + ProvideRef<LTail>, LTail: Lt> Provide<Lt!['x, ..LTail]> for &'x mut P {
121    fn provide(mut self, query: &mut Query<'_, Lt!['x, ..LTail]>) -> Option<Self> {
122        self = provide_mut_with(self, query, |this, q| {
123            this.provide_mut(q);
124        })
125        .1?;
126
127        self = provide_mut_with(self, query, |this, q| {
128            this.provide_ref(q);
129        })
130        .1?;
131
132        Some(self)
133    }
134}
135
136/// Provides a value given a unique reference to `T`, returning the reference if a value was not supplied.
137fn provide_mut_with<'x, T: ?Sized, LTail: Lt, R>(
138    in_ref: &'x mut T,
139    query: &mut Query<'_, Lt!['x, ..LTail]>,
140    f: impl for<'y> FnOnce(&'y mut T, &mut Query<'_, Lt!['y, .. LTail]>) -> R,
141) -> (R, Option<&'x mut T>) {
142    let mut in_ref_ptr = NonNull::from(&mut *in_ref);
143
144    // SAFETY: in_ref will only be used again if the query is not fulfilled.
145    // Since the lifetime of the reference and query are erased, the only way for borrowed data to
146    // escape from in_ref is by fulfilling the query.
147    let out = unsafe {
148        let short_lived_ref = in_ref_ptr.as_mut();
149        f(short_lived_ref, query)
150    };
151
152    let out_ref = if query.is_fulfilled() {
153        // Query has been fulfilled and possibly contains data borrowed from *in_ref, so we must
154        // discard in_ref.
155        None
156    } else {
157        // Query has not been fulfilled, so nothing should be borrowed from *in_ref besides in_ref.
158        Some(in_ref)
159    };
160
161    (out, out_ref)
162}
163
164/// Implements [`Provide`] by delegating to a function of type `F`.
165///
166/// Return type for [`provide_with()`].
167#[derive(Clone, Copy)]
168pub struct FnProvider<T, F> {
169    value: T,
170    f: F,
171}
172
173impl<T: core::fmt::Debug, F> core::fmt::Debug for FnProvider<T, F> {
174    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
175        f.debug_struct("FnProvider")
176            .field("value", &self.value)
177            .finish_non_exhaustive()
178    }
179}
180
181impl<T, F, L: Lt> Provide<L> for FnProvider<T, F>
182where
183    F: for<'q> FnMut(QueryUsing<'q, T, L>) -> QueryUsing<'q, T, L>,
184{
185    fn provide(self, query: &mut Query<'_, L>) -> Option<Self> {
186        let Self { value, mut f } = self;
187
188        f(query.using(value))
189            .finish()
190            .map(|value| Self { value, f })
191    }
192}
193
194impl<T, F> FnProvider<T, F> {
195    pub fn into_inner(self) -> T {
196        self.value
197    }
198}
199
200/// Returns a [`Provide`] implementation that delegates to the given function.
201///
202/// ```
203/// use dynamic_provider::{provide_with, Provide};
204///
205/// let provider = provide_with(
206///     String::from("Hello, world!"),
207///     |query| query.put_value(|this| this).put_value(Vec::<u8>::from),
208/// );
209///
210/// assert_eq!(Provide::<()>::request_value::<Vec<u8>>(provider).unwrap(), b"Hello, world!");
211/// ```
212pub fn provide_with<T, F, L: Lt>(value: T, provide: F) -> FnProvider<T, F>
213where
214    F: for<'q> FnMut(QueryUsing<'q, T, L>) -> QueryUsing<'q, T, L>,
215{
216    FnProvider { value, f: provide }
217}
218
219/// Implements [`ProvideRef`] by delegating to a function of type `F`.
220///
221/// Return type for [`provide_by_ref_with()`].
222#[derive(Clone, Copy)]
223pub struct FnRefProvider<T, FRef, FMut> {
224    value: T,
225    f_ref: FRef,
226    f_mut: FMut,
227}
228
229impl<T: core::fmt::Debug, FRef, FMut> core::fmt::Debug for FnRefProvider<T, FRef, FMut> {
230    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
231        f.debug_struct("FnRefProvider")
232            .field("value", &self.value)
233            .finish_non_exhaustive()
234    }
235}
236
237impl<T, FRef, FMut, L: Lt> ProvideRef<L> for FnRefProvider<T, FRef, FMut>
238where
239    FRef:
240        for<'q, 'x> Fn(QueryUsing<'q, &'x T, Lt!['x, ..L]>) -> QueryUsing<'q, &'x T, Lt!['x, ..L]>,
241    FMut: for<'q, 'x> FnMut(
242        QueryUsing<'q, &'x mut T, Lt!['x, ..L]>,
243    ) -> QueryUsing<'q, &'x mut T, Lt!['x, ..L]>,
244{
245    fn provide_ref<'this>(&'this self, query: &mut Query<'_, Lt!['this, ..L]>) {
246        let Self { value, f_ref, .. } = self;
247
248        let _ = f_ref(query.using(value)).finish();
249    }
250
251    fn provide_mut<'this>(&'this mut self, query: &mut Query<'_, Lt!['this, ..L]>) {
252        let Self { value, f_mut, .. } = self;
253
254        let _ = f_mut(query.using(value)).finish();
255    }
256}
257
258impl<T, FRef, FMut> FnRefProvider<T, FRef, FMut> {
259    pub fn into_inner(self) -> T {
260        self.value
261    }
262}
263
264/// Returns a [`ProvideRef`] implementation that delegates to the given function.
265///
266/// ```
267/// use dynamic_provider::{Lt, provide_by_ref_with, Provide};
268///
269/// let provider = provide_by_ref_with(
270///     String::from("Hello, world!"),
271///     |query| query.put_value(Clone::clone).put_ref(|s| s.as_bytes()),
272///     |query| query,
273/// );
274///
275/// assert_eq!(Provide::<Lt!['_]>::request_ref::<[u8]>(&provider).unwrap(), b"Hello, world!");
276/// ```
277pub fn provide_by_ref_with<T, FRef, FMut, LTail: Lt>(
278    value: T,
279    provide_ref: FRef,
280    provide_mut: FMut,
281) -> FnRefProvider<T, FRef, FMut>
282where
283    FRef: for<'q, 'x> Fn(
284        QueryUsing<'q, &'x T, Lt!['x, ..LTail]>,
285    ) -> QueryUsing<'q, &'x T, Lt!['x, ..LTail]>,
286    FMut: for<'q, 'x> FnMut(
287        QueryUsing<'q, &'x mut T, Lt!['x, ..LTail]>,
288    ) -> QueryUsing<'q, &'x mut T, Lt!['x, ..LTail]>,
289{
290    FnRefProvider {
291        value,
292        f_ref: provide_ref,
293        f_mut: provide_mut,
294    }
295}
296
297impl<L: Lt> Provide<L> for () {
298    fn provide(self, _: &mut Query<'_, L>) -> Option<Self> {
299        Some(self)
300    }
301}
302
303impl<L: Lt> ProvideRef<L> for () {}
304
305impl<L: Lt> ProvideRef<L> for str {
306    fn provide_ref<'x>(&'x self, query: &mut Query<'_, Lt!['x, ..L]>) {
307        let mut query = query.using(self);
308
309        query = query.put_ref(identity).put_ref(str::as_bytes);
310
311        #[cfg(feature = "alloc")]
312        {
313            use alloc::borrow::ToOwned;
314            query = query
315                .put_value(str::to_owned)
316                .put_value(|this| this.to_owned().into_boxed_str())
317                .put_value(|this| this.as_bytes().to_owned())
318                .put_value(|this| this.as_bytes().to_owned().into_boxed_slice());
319        }
320
321        query.finish();
322    }
323}
324
325impl<L: Lt> Provide<L> for Infallible {
326    fn provide(self, _: &mut Query<'_, L>) -> Option<Self> {
327        match self {}
328    }
329}
330
331impl<L: Lt> ProvideRef<L> for Infallible {}
332
333enum WhenProviderState<P, Cx, Out> {
334    Provider { provider: P, context: Cx },
335    Output { out: Out },
336}
337
338pub struct HasContext<Cx>(Cx);
339pub struct NoContext;
340
341/// Helper function for requesting one of multiple possible values.
342/// See also [`request!`][macro@crate::request] and [`Provide::request()`].
343///
344/// See [`WhenProvider`] information about the methods used to request values.
345///
346/// ## Example
347#[doc = include_str!("./when_provider.md")]
348pub fn when_provider<L: Lt, P: Provide<L>, Out>(provider: P) -> WhenProvider<L, P, NoContext, Out> {
349    WhenProvider {
350        state: WhenProviderState::Provider {
351            provider,
352            context: NoContext,
353        },
354        _l: PhantomData,
355    }
356}
357
358/// Return type of [`when_provider()`].
359///
360/// ## Example
361#[doc = include_str!("./when_provider.md")]
362pub struct WhenProvider<L, P, Cx, Out> {
363    state: WhenProviderState<P, Cx, Out>,
364    _l: PhantomData<L>,
365}
366
367macro_rules! impl_when_provider_methods {
368    (has_context = $has_context:ident) => {
369        /// Handle the case where the type marked by `Tag` is supplied by the provider.
370        pub fn has<Tag: TagFor<L>>(
371            mut self,
372            arg: Tag::ArgValue,
373            transform: transform_type!(has_context = $has_context, arg = Tag::Value),
374        ) -> Self {
375            if let WhenProviderState::Provider {
376                provider,
377                context: _context,
378            } = self.state
379            {
380                self.state = match provider.request::<Tag>(arg) {
381                    Ok(out) => WhenProviderState::Output {
382                        out: transform_call!(
383                            has_context = $has_context,
384                            transform = transform,
385                            out = out,
386                            context = _context
387                        ),
388                    },
389                    Err(provider) => WhenProviderState::Provider {
390                        provider,
391                        context: _context,
392                    },
393                }
394            }
395
396            self
397        }
398
399        /// Handle the case where a value of type `T`, marked by [`Value<T>`], is supplied by the provider.
400        pub fn has_value<T: 'static>(
401            self,
402            transform: transform_type!(has_context = $has_context, arg = T),
403        ) -> Self {
404            self.has::<Value<T>>((), transform)
405        }
406    };
407    (ref/has_context = $has_context:ident) => {
408        /// Handle the case where a shared reference to a value of type `T`,
409        /// marked by [`Ref<Value<T>>`], is supplied by the provider.
410        pub fn has_ref<T: 'static + ?Sized>(
411            self,
412    transform: transform_type!(has_context = $has_context, arg = &'x T),
413        ) -> Self {
414            self.has::<Ref<Value<T>>>((), transform)
415        }
416
417        /// Handle the case where a unique reference to a value of type `T`,
418        /// marked by [`Mut<Value<T>>`], is supplied by the provider.
419        pub fn has_mut<T: 'static + ?Sized>(
420            self,
421    transform: transform_type!(has_context = $has_context, arg = &'x mut T),
422        ) -> Self {
423            self.has::<Mut<Value<T>>>((), transform)
424        }
425    };
426}
427
428macro_rules! transform_type {
429    (has_context = true, arg = $Arg:ty) => {
430        impl FnOnce($Arg, Cx) -> Out
431    };
432    (has_context = false, arg = $Arg:ty) => {
433        impl FnOnce($Arg) -> Out
434    };
435}
436
437macro_rules! transform_call {
438    (has_context = true, transform = $transform:ident, out = $out:ident, context = $context:ident) => {
439        $transform($out, $context.0)
440    };
441    (has_context = false, transform = $transform:ident, out = $out:ident, context = $context:ident) => {
442        $transform($out)
443    };
444}
445
446impl<L: Lt, P: Provide<L>, Out> WhenProvider<L, P, NoContext, Out> {
447    /// Returns the output of the successful request if there is one, or an `Err` containing the original
448    /// provider.
449    pub fn finish(self) -> Result<Out, P> {
450        match self.state {
451            WhenProviderState::Provider {
452                provider,
453                context: NoContext,
454            } => Err(provider),
455            WhenProviderState::Output { out } => Ok(out),
456        }
457    }
458
459    /// Returns the output of the successful request if there is one, or the return value of the given
460    /// function that accepts the original provider.
461    pub fn or_else(self, f: impl FnOnce(P) -> Out) -> Out {
462        self.finish().unwrap_or_else(f)
463    }
464
465    /// Adds a context value to all subsequent request handlers, which will be passed as the second
466    /// callback parameter.
467    pub fn with<Cx>(self, context: Cx) -> WhenProvider<L, P, HasContext<Cx>, Out> {
468        WhenProvider {
469            state: match self.state {
470                WhenProviderState::Provider {
471                    provider,
472                    context: NoContext,
473                } => WhenProviderState::Provider {
474                    provider,
475                    context: HasContext(context),
476                },
477                WhenProviderState::Output { out } => WhenProviderState::Output { out },
478            },
479            _l: PhantomData,
480        }
481    }
482
483    impl_when_provider_methods!(has_context = false);
484}
485
486impl<'x, L: Lt, P: Provide<Lt!['x, ..L]>, Out> WhenProvider<Lt!['x, ..L], P, NoContext, Out> {
487    impl_when_provider_methods!(ref/has_context = false);
488}
489
490impl<L: Lt, P: Provide<L>, Cx, Out> WhenProvider<L, P, HasContext<Cx>, Out> {
491    /// Returns the output of the successful request if there is one, or an `Err` containing the original
492    /// provider and the context value.
493    pub fn finish(self) -> Result<Out, (P, Cx)> {
494        match self.state {
495            WhenProviderState::Provider {
496                provider,
497                context: HasContext(context),
498            } => Err((provider, context)),
499            WhenProviderState::Output { out } => Ok(out),
500        }
501    }
502
503    /// Returns the output of the successful request if there is one, or the return value of the given
504    /// function that accepts the original provider and the context value.
505    pub fn or_else(self, f: impl FnOnce(P, Cx) -> Out) -> Out {
506        self.finish()
507            .unwrap_or_else(|(provider, cx)| f(provider, cx))
508    }
509
510    impl_when_provider_methods!(has_context = true);
511}
512
513impl<'x, L: Lt, P: Provide<Lt!['x, ..L]>, Cx, Out>
514    WhenProvider<Lt!['x, ..L], P, HasContext<Cx>, Out>
515{
516    impl_when_provider_methods!(ref/has_context = true);
517}
518
519/// Given a provider, calls the given callback for each [`TagId`] it provides.
520///
521/// Returns the original provider.
522pub fn for_each_provided_tag_id<L: Lt, P: Provide<L>>(
523    provider: P,
524    on_provide_attempt: impl FnMut(TagId),
525) -> P {
526    Query::capture_tag_ids(|q| provider.provide(q), on_provide_attempt).unwrap()
527}
528
529/// Given a provider, creates a collection of [`TagId`]s it provides.
530///
531#[cfg_attr(
532    feature = "alloc",
533    doc = r#"
534```
535use dynamic_provider::{Lt, Mut, Ref, TagId, Value};
536
537let provider = String::from("Hello, world!");
538
539let tag_ids = dynamic_provider::get_provided_tag_ids::<Lt!['_], Vec<_>>(&provider);
540
541assert!(tag_ids.contains(&TagId::of::<Ref<Value<str>>>()));
542assert!(tag_ids.contains(&TagId::of::<Ref<Value<[u8]>>>()));
543assert!(tag_ids.contains(&TagId::of::<Value<String>>()));
544```
545"#
546)]
547pub fn get_provided_tag_ids<L: Lt, Out>(provider: impl Provide<L>) -> Out
548where
549    Out: Default + Extend<TagId>,
550{
551    let mut out = Out::default();
552    for_each_provided_tag_id(provider, |tag_id| out.extend([tag_id]));
553    out
554}