supplier/
lib.rs

1//! Supply values dynamically.
2//!
3//! API is very unstable. It will likely include a breaking change with any patch version.
4//!
5//! This is intended to replace the `Provider` API that was proposed for the core rust library,
6//! but has been decided to not include.
7use core::any::TypeId;
8use core::fmt;
9
10/// Trait implemented by a type which can dynamically supply values based on type.
11pub trait Supplier {
12    /// Data suppliers should implement this method to supply *all* values they are able to
13    /// supply by using `demand`.
14    ///
15    /// Note that the `supply_*` methods on `Demand` have short-circuit semantics: if an earlier
16    /// method has successfully supplied a value, then later methods will not get an opportunity to
17    /// supply.
18    ///
19    /// # Examples
20    ///
21    /// Supplies a reference to a field with type `String` as a `&str`, and a value of
22    /// type `i32`.
23    ///
24    /// ```rust
25    /// use supplier::{Supplier, Demand};
26    /// # struct SomeConcreteType { field: String, num_field: i32 }
27    ///
28    /// impl Supplier for SomeConcreteType {
29    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
30    ///         demand.supply_ref::<str>(&self.field)
31    ///             .supply_value::<i32>(self.num_field);
32    ///     }
33    /// }
34    /// ```
35    fn supply<'a>(&'a self, demand: &mut Demand<'a>);
36}
37
38/// Request a value from the `Supplier`.
39///
40/// # Examples
41///
42/// Get a string value from a supplier.
43///
44/// ```rust
45/// use supplier::{Supplier, request_value};
46///
47/// fn get_string(supplier: &impl Supplier) -> String {
48///     request_value::<String>(supplier).unwrap()
49/// }
50/// ```
51pub fn request_value<'a, T>(supplier: &'a (impl Supplier + ?Sized)) -> Option<T>
52where
53    T: 'static,
54{
55    request_by_type_tag::<'a, tags::Value<T>>(supplier)
56}
57
58/// Request a reference from the `Supplier`.
59///
60/// # Examples
61///
62/// Get a string reference from a supplier.
63///
64/// ```rust
65/// use supplier::{Supplier, request_ref};
66///
67/// fn get_str(supplier: &impl Supplier) -> &str {
68///     request_ref::<str>(supplier).unwrap()
69/// }
70/// ```
71pub fn request_ref<'a, T>(supplier: &'a (impl Supplier + ?Sized)) -> Option<&'a T>
72where
73    T: 'static + ?Sized,
74{
75    request_by_type_tag::<'a, tags::Ref<tags::MaybeSizedValue<T>>>(supplier)
76}
77
78/// Request a specific value by tag from the `Supplier`.
79fn request_by_type_tag<'a, I>(supplier: &'a (impl Supplier + ?Sized)) -> Option<I::Reified>
80where
81    I: tags::Type<'a>,
82{
83    let mut tagged = TaggedOption::<'a, I>(None);
84    supplier.supply(tagged.as_demand());
85    tagged.0
86}
87
88///////////////////////////////////////////////////////////////////////////////
89// Demand and its methods
90///////////////////////////////////////////////////////////////////////////////
91
92/// A helper object for supplying data by type.
93///
94/// A data supplier supplies values by calling this type's supply methods.
95#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
96pub struct Demand<'a>(dyn Erased<'a> + 'a);
97
98impl<'a> Demand<'a> {
99    /// Create a new `&mut Demand` from a `&mut dyn Erased` trait object.
100    fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Demand<'a> {
101        // SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Demand<'a>` is safe since
102        // `Demand` is repr(transparent).
103        unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Demand<'a>) }
104    }
105
106    /// Supply a value or other type with only static lifetimes.
107    ///
108    /// # Examples
109    ///
110    /// Supplies an `u8`.
111    ///
112    /// ```rust
113    /// use supplier::{Supplier, Demand};
114    /// # struct SomeConcreteType { field: u8 }
115    ///
116    /// impl Supplier for SomeConcreteType {
117    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
118    ///         demand.supply_value::<u8>(self.field);
119    ///     }
120    /// }
121    /// ```
122    pub fn supply_value<T>(&mut self, value: T) -> &mut Self
123    where
124        T: 'static,
125    {
126        self.supply::<tags::Value<T>>(value)
127    }
128
129    /// Supply a value or other type with only static lifetimes computed using a closure.
130    ///
131    /// # Examples
132    ///
133    /// Supplies a `String` by cloning.
134    ///
135    /// ```rust
136    /// use supplier::{Supplier, Demand};
137    /// # struct SomeConcreteType { field: String }
138    ///
139    /// impl Supplier for SomeConcreteType {
140    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
141    ///         demand.supply_value_with::<String>(|| self.field.clone());
142    ///     }
143    /// }
144    /// ```
145    pub fn supply_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
146    where
147        T: 'static,
148    {
149        self.supply_with::<tags::Value<T>>(fulfil)
150    }
151
152    /// Supply a reference. The referee type must be bounded by `'static`,
153    /// but may be unsized.
154    ///
155    /// # Examples
156    ///
157    /// Supplies a reference to a field as a `&str`.
158    ///
159    /// ```rust
160    /// use supplier::{Supplier, Demand};
161    /// # struct SomeConcreteType { field: String }
162    ///
163    /// impl Supplier for SomeConcreteType {
164    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
165    ///         demand.supply_ref::<str>(&self.field);
166    ///     }
167    /// }
168    /// ```
169    pub fn supply_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self {
170        self.supply::<tags::Ref<tags::MaybeSizedValue<T>>>(value)
171    }
172
173    /// Supply a reference computed using a closure. The referee type
174    /// must be bounded by `'static`, but may be unsized.
175    ///
176    /// # Examples
177    ///
178    /// Supplies a reference to a field as a `&str`.
179    ///
180    /// ```rust
181    /// use supplier::{Supplier, Demand};
182    /// # struct SomeConcreteType { business: String, party: String }
183    /// # fn today_is_a_weekday() -> bool { true }
184    ///
185    /// impl Supplier for SomeConcreteType {
186    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
187    ///         demand.supply_ref_with::<str>(|| {
188    ///             if today_is_a_weekday() {
189    ///                 &self.business
190    ///             } else {
191    ///                 &self.party
192    ///             }
193    ///         });
194    ///     }
195    /// }
196    /// ```
197    pub fn supply_ref_with<T: ?Sized + 'static>(
198        &mut self,
199        fulfil: impl FnOnce() -> &'a T,
200    ) -> &mut Self {
201        self.supply_with::<tags::Ref<tags::MaybeSizedValue<T>>>(fulfil)
202    }
203
204    /// Supply a value with the given `Type` tag.
205    fn supply<I>(&mut self, value: I::Reified) -> &mut Self
206    where
207        I: tags::Type<'a>,
208    {
209        if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() {
210            res.0 = Some(value);
211        }
212        self
213    }
214
215    /// Supply a value with the given `Type` tag, using a closure to prevent unnecessary work.
216    fn supply_with<I>(&mut self, fulfil: impl FnOnce() -> I::Reified) -> &mut Self
217    where
218        I: tags::Type<'a>,
219    {
220        if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() {
221            res.0 = Some(fulfil());
222        }
223        self
224    }
225
226    /// Check if the `Demand` would be satisfied if supplied with a
227    /// value of the specified type. If the type does not match or has
228    /// already been supplied, returns false.
229    ///
230    /// # Examples
231    ///
232    /// Check if an `u8` still needs to be supplied and then supplies
233    /// it.
234    ///
235    /// ```rust
236    /// use supplier::{Supplier, Demand};
237    ///
238    /// struct Parent(Option<u8>);
239    ///
240    /// impl Supplier for Parent {
241    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
242    ///         if let Some(v) = self.0 {
243    ///             demand.supply_value::<u8>(v);
244    ///         }
245    ///     }
246    /// }
247    ///
248    /// struct Child {
249    ///     parent: Parent,
250    /// }
251    ///
252    /// impl Child {
253    ///     // Pretend that this takes a lot of resources to evaluate.
254    ///     fn an_expensive_computation(&self) -> Option<u8> {
255    ///         Some(99)
256    ///     }
257    /// }
258    ///
259    /// impl Supplier for Child {
260    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
261    ///         // In general, we don't know if this call will supply
262    ///         // an `u8` value or not...
263    ///         self.parent.supply(demand);
264    ///
265    ///         // ...so we check to see if the `u8` is needed before
266    ///         // we run our expensive computation.
267    ///         if demand.would_be_satisfied_by_value_of::<u8>() {
268    ///             if let Some(v) = self.an_expensive_computation() {
269    ///                 demand.supply_value::<u8>(v);
270    ///             }
271    ///         }
272    ///
273    ///         // The demand will be satisfied now, regardless of if
274    ///         // the parent supplied the value or we did.
275    ///         assert!(!demand.would_be_satisfied_by_value_of::<u8>());
276    ///     }
277    /// }
278    ///
279    /// let parent = Parent(Some(42));
280    /// let child = Child { parent };
281    /// assert_eq!(Some(42), supplier::request_value::<u8>(&child));
282    ///
283    /// let parent = Parent(None);
284    /// let child = Child { parent };
285    /// assert_eq!(Some(99), supplier::request_value::<u8>(&child));
286    /// ```
287    pub fn would_be_satisfied_by_value_of<T>(&self) -> bool
288    where
289        T: 'static,
290    {
291        self.would_be_satisfied_by::<tags::Value<T>>()
292    }
293
294    /// Check if the `Demand` would be satisfied if supplied with a
295    /// reference to a value of the specified type. If the type does
296    /// not match or has already been supplied, returns false.
297    ///
298    /// # Examples
299    ///
300    /// Check if a `&str` still needs to be supplied and then supplies
301    /// it.
302    ///
303    /// ```rust
304    /// use supplier::{Supplier, Demand};
305    ///
306    /// struct Parent(Option<String>);
307    ///
308    /// impl Supplier for Parent {
309    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
310    ///         if let Some(v) = &self.0 {
311    ///             demand.supply_ref::<str>(v);
312    ///         }
313    ///     }
314    /// }
315    ///
316    /// struct Child {
317    ///     parent: Parent,
318    ///     name: String,
319    /// }
320    ///
321    /// impl Child {
322    ///     // Pretend that this takes a lot of resources to evaluate.
323    ///     fn an_expensive_computation(&self) -> Option<&str> {
324    ///         Some(&self.name)
325    ///     }
326    /// }
327    ///
328    /// impl Supplier for Child {
329    ///     fn supply<'a>(&'a self, demand: &mut Demand<'a>) {
330    ///         // In general, we don't know if this call will supply
331    ///         // a `str` reference or not...
332    ///         self.parent.supply(demand);
333    ///
334    ///         // ...so we check to see if the `&str` is needed before
335    ///         // we run our expensive computation.
336    ///         if demand.would_be_satisfied_by_ref_of::<str>() {
337    ///             if let Some(v) = self.an_expensive_computation() {
338    ///                 demand.supply_ref::<str>(v);
339    ///             }
340    ///         }
341    ///
342    ///         // The demand will be satisfied now, regardless of if
343    ///         // the parent supplied the reference or we did.
344    ///         assert!(!demand.would_be_satisfied_by_ref_of::<str>());
345    ///     }
346    /// }
347    ///
348    /// let parent = Parent(Some("parent".into()));
349    /// let child = Child { parent, name: "child".into() };
350    /// assert_eq!(Some("parent"), supplier::request_ref::<str>(&child));
351    ///
352    /// let parent = Parent(None);
353    /// let child = Child { parent, name: "child".into() };
354    /// assert_eq!(Some("child"), supplier::request_ref::<str>(&child));
355    /// ```
356    pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool
357    where
358        T: ?Sized + 'static,
359    {
360        self.would_be_satisfied_by::<tags::Ref<tags::MaybeSizedValue<T>>>()
361    }
362
363    fn would_be_satisfied_by<I>(&self) -> bool
364    where
365        I: tags::Type<'a>,
366    {
367        matches!(self.0.downcast::<I>(), Some(TaggedOption(None)))
368    }
369}
370impl<'a> fmt::Debug for Demand<'a> {
371    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372        f.debug_struct("Demand").finish_non_exhaustive()
373    }
374}
375///////////////////////////////////////////////////////////////////////////////
376// Type tags
377///////////////////////////////////////////////////////////////////////////////
378
379mod tags {
380    //! Type tags are used to identify a type using a separate value. This module includes type tags
381    //! for some very common types.
382    //!
383    //! Currently type tags are not exposed to the user. But in the future, if you want to use the
384    //! Supplier API with more complex types (typically those including lifetime parameters), you
385    //! will need to write your own tags.
386
387    use core::marker::PhantomData;
388
389    /// This trait is implemented by specific tag types in order to allow
390    /// describing a type which can be requested for a given lifetime `'a`.
391    ///
392    /// A few example implementations for type-driven tags can be found in this
393    /// module, although crates may also implement their own tags for more
394    /// complex types with internal lifetimes.
395    pub trait Type<'a>: Sized + 'static {
396        /// The type of values which may be tagged by this tag for the given
397        /// lifetime.
398        type Reified: 'a;
399    }
400
401    /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a
402    /// `?Sized` bound). E.g., `str`.
403    pub trait MaybeSizedType<'a>: Sized + 'static {
404        type Reified: 'a + ?Sized;
405    }
406
407    impl<'a, T: Type<'a>> MaybeSizedType<'a> for T {
408        type Reified = T::Reified;
409    }
410
411    /// Type-based tag for types bounded by `'static`, i.e., with no borrowed elements.
412    #[derive(Debug)]
413    pub struct Value<T: 'static>(PhantomData<T>);
414
415    impl<'a, T: 'static> Type<'a> for Value<T> {
416        type Reified = T;
417    }
418
419    /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `?Sized` bound).
420    #[derive(Debug)]
421    pub struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>);
422
423    impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue<T> {
424        type Reified = T;
425    }
426
427    /// Type-based tag for reference types (`&'a T`, where T is represented by
428    /// `<I as MaybeSizedType<'a>>::Reified`.
429    #[derive(Debug)]
430    pub struct Ref<I>(PhantomData<I>);
431
432    impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref<I> {
433        type Reified = &'a I::Reified;
434    }
435}
436
437/// An `Option` with a type tag `I`.
438///
439/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed
440/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically
441/// checked for the concrete type, there is some degree of type safety.
442#[repr(transparent)]
443struct TaggedOption<'a, I: tags::Type<'a>>(Option<I::Reified>);
444
445impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> {
446    fn as_demand(&mut self) -> &mut Demand<'a> {
447        Demand::new(self as &mut (dyn Erased<'a> + 'a))
448    }
449}
450
451/// Represents a type-erased but identifiable object.
452///
453/// This trait is exclusively implemented by the `TaggedOption` type.
454unsafe trait Erased<'a>: 'a {
455    /// The `TypeId` of the erased type.
456    fn tag_id(&self) -> TypeId;
457}
458
459unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {
460    fn tag_id(&self) -> TypeId {
461        TypeId::of::<I>()
462    }
463}
464
465impl<'a> dyn Erased<'a> + 'a {
466    /// Returns some reference to the dynamic value if it is tagged with `I`,
467    /// or `None` otherwise.
468    #[inline]
469    fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>>
470    where
471        I: tags::Type<'a>,
472    {
473        if self.tag_id() == TypeId::of::<I>() {
474            // SAFETY: Just checked whether we're pointing to an I.
475            Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
476        } else {
477            None
478        }
479    }
480
481    /// Returns some mutable reference to the dynamic value if it is tagged with `I`,
482    /// or `None` otherwise.
483    #[inline]
484    fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>>
485    where
486        I: tags::Type<'a>,
487    {
488        if self.tag_id() == TypeId::of::<I>() {
489            // SAFETY: Just checked whether we're pointing to an I.
490            Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
491        } else {
492            None
493        }
494    }
495}
496
497#[cfg(test)]
498mod tests {
499    use crate::{request_ref, Supplier};
500
501    struct Container {
502        x: u8,
503        y: String,
504        z: Vec<u8>,
505    }
506
507    impl Supplier for Container {
508        fn supply<'a>(&'a self, demand: &mut crate::Demand<'a>) {
509            demand
510                .supply_ref(&self.x)
511                .supply_ref(&*self.y)
512                .supply_ref(&*self.z);
513        }
514    }
515
516    #[test]
517    fn it_works() {
518        let c = Container {
519            x: 42,
520            y: "foobar".to_string(),
521            z: vec![1, 2, 3],
522        };
523
524        assert_eq!(request_ref::<u8>(&c).unwrap(), &42);
525        assert_eq!(request_ref::<str>(&c).unwrap(), "foobar");
526        assert_eq!(request_ref::<[u8]>(&c).unwrap(), &[1, 2, 3]);
527    }
528}