|
1 |
| -//! This module implements the `Any` trait, which enables dynamic typing |
2 |
| -//! of any `'static` type through runtime reflection. |
| 1 | +//! This module contains the `Any` trait, which enables dynamic typing |
| 2 | +//! of any `'static` type through runtime reflection. It also contains the |
| 3 | +//! `Provider` trait and accompanying API, which enable trait objects to provide |
| 4 | +//! data based on typed requests, an alternate form of runtime reflection. |
| 5 | +//! |
| 6 | +//! # `Any` and `TypeId` |
3 | 7 | //!
|
4 | 8 | //! `Any` itself can be used to get a `TypeId`, and has more features when used
|
5 | 9 | //! as a trait object. As `&dyn Any` (a borrowed trait object), it has the `is`
|
|
37 | 41 | //! assert_eq!(boxed_id, TypeId::of::<Box<dyn Any>>());
|
38 | 42 | //! ```
|
39 | 43 | //!
|
40 |
| -//! # Examples |
| 44 | +//! ## Examples |
41 | 45 | //!
|
42 | 46 | //! Consider a situation where we want to log out a value passed to a function.
|
43 | 47 | //! We know the value we're working on implements Debug, but we don't know its
|
|
81 | 85 | //! do_work(&my_i8);
|
82 | 86 | //! }
|
83 | 87 | //! ```
|
| 88 | +//! |
| 89 | +//! # `Provider` and `Demand` |
| 90 | +//! |
| 91 | +//! `Provider` and the associated APIs support generic, type-driven access to data, and a mechanism |
| 92 | +//! for implementers to provide such data. The key parts of the interface are the `Provider` |
| 93 | +//! trait for objects which can provide data, and the [`request_value`] and [`request_ref`] |
| 94 | +//! functions for requesting data from an object which implements `Provider`. Note that end users |
| 95 | +//! should not call `request_*` directly, they are helper functions for intermediate implementers |
| 96 | +//! to use to implement a user-facing interface. |
| 97 | +//! |
| 98 | +//! Typically, a data provider is a trait object of a trait which extends `Provider`. A user will |
| 99 | +//! request data from the trait object by specifying the type. |
| 100 | +//! |
| 101 | +//! ## Data flow |
| 102 | +//! |
| 103 | +//! * A user requests an object, which is delegated to `request_value` or `request_ref` |
| 104 | +//! * `request_*` creates a `Demand` object and passes it to `Provider::provide` |
| 105 | +//! * The object provider's implementation of `Provider::provide` tries providing values of |
| 106 | +//! different types using `Demand::provide_*`. If the type matches the type requested by |
| 107 | +//! the user, it will be stored in the `Demand` object. |
| 108 | +//! * `request_*` unpacks the `Demand` object and returns any stored value to the user. |
| 109 | +//! |
| 110 | +//! ## Examples |
| 111 | +//! |
| 112 | +//! ``` |
| 113 | +//! # #![allow(incomplete_features)] |
| 114 | +//! # #![feature(provide_any)] |
| 115 | +//! # #![feature(trait_upcasting)] |
| 116 | +//! use std::any::{Provider, Demand, request_ref}; |
| 117 | +//! |
| 118 | +//! // Definition of MyTrait |
| 119 | +//! trait MyTrait: Provider { |
| 120 | +//! // ... |
| 121 | +//! } |
| 122 | +//! |
| 123 | +//! // Methods on `MyTrait` trait objects. |
| 124 | +//! impl dyn MyTrait + '_ { |
| 125 | +//! /// Common case: get a reference to a field of the error. |
| 126 | +//! pub fn get_context_ref<T: ?Sized + 'static>(&self) -> Option<&T> { |
| 127 | +//! request_ref::<T>(self) |
| 128 | +//! } |
| 129 | +//! } |
| 130 | +//! |
| 131 | +//! // Downstream implementation of `MyTrait` and `Provider`. |
| 132 | +//! # struct SomeConcreteType { some_string: String } |
| 133 | +//! impl MyTrait for SomeConcreteType { |
| 134 | +//! // ... |
| 135 | +//! } |
| 136 | +//! |
| 137 | +//! impl Provider for SomeConcreteType { |
| 138 | +//! fn provide<'a>(&'a self, req: &mut Demand<'a>) { |
| 139 | +//! req.provide_ref::<String>(&self.some_string); |
| 140 | +//! } |
| 141 | +//! } |
| 142 | +//! |
| 143 | +//! // Downstream usage of `MyTrait`. |
| 144 | +//! fn use_my_trait(obj: &dyn MyTrait) { |
| 145 | +//! // Request a &String from obj. |
| 146 | +//! let _ = obj.get_context_ref::<String>().unwrap(); |
| 147 | +//! } |
| 148 | +//! ``` |
| 149 | +//! |
| 150 | +//! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then |
| 151 | +//! the `get_context_ref` call will return a reference to `obj.some_string`. |
84 | 152 |
|
85 | 153 | #![stable(feature = "rust1", since = "1.0.0")]
|
86 | 154 |
|
87 | 155 | use crate::fmt;
|
88 | 156 | use crate::intrinsics;
|
| 157 | +use crate::mem::transmute; |
89 | 158 |
|
90 | 159 | ///////////////////////////////////////////////////////////////////////////////
|
91 | 160 | // Any trait
|
@@ -700,3 +769,201 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
|
700 | 769 | pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
|
701 | 770 | type_name::<T>()
|
702 | 771 | }
|
| 772 | + |
| 773 | +/////////////////////////////////////////////////////////////////////////////// |
| 774 | +// Provider trait |
| 775 | +/////////////////////////////////////////////////////////////////////////////// |
| 776 | + |
| 777 | +/// Trait implemented by a type which can dynamically provide values based on type. |
| 778 | +#[unstable(feature = "provide_any", issue = "none")] |
| 779 | +pub trait Provider { |
| 780 | + /// Object providers should implement this method to provide *all* values they are able to |
| 781 | + /// provide using `req`. |
| 782 | + #[unstable(feature = "provide_any", issue = "none")] |
| 783 | + fn provide<'a>(&'a self, req: &mut Demand<'a>); |
| 784 | +} |
| 785 | + |
| 786 | +/// Request a value from the `Provider`. |
| 787 | +#[unstable(feature = "provide_any", issue = "none")] |
| 788 | +pub fn request_value<'a, T: 'static>(provider: &'a dyn Provider) -> Option<T> { |
| 789 | + request_by_type_tag::<'a, tags::Value<T>>(provider) |
| 790 | +} |
| 791 | + |
| 792 | +/// Request a reference from the `Provider`. |
| 793 | +#[unstable(feature = "provide_any", issue = "none")] |
| 794 | +pub fn request_ref<'a, T: ?Sized + 'static>(provider: &'a dyn Provider) -> Option<&'a T> { |
| 795 | + request_by_type_tag::<'a, tags::Ref<tags::MaybeSizedValue<T>>>(provider) |
| 796 | +} |
| 797 | + |
| 798 | +/// Request a specific value by tag from the `Provider`. |
| 799 | +fn request_by_type_tag<'a, I>(provider: &'a dyn Provider) -> Option<I::Reified> |
| 800 | +where |
| 801 | + I: tags::Type<'a>, |
| 802 | +{ |
| 803 | + let mut tagged = TaggedOption::<'a, I>(None); |
| 804 | + provider.provide(tagged.as_demand()); |
| 805 | + tagged.0 |
| 806 | +} |
| 807 | + |
| 808 | +/////////////////////////////////////////////////////////////////////////////// |
| 809 | +// Demand and its methods |
| 810 | +/////////////////////////////////////////////////////////////////////////////// |
| 811 | + |
| 812 | +/// A helper object for providing objects by type. |
| 813 | +/// |
| 814 | +/// An object provider provides values by calling this type's provide methods. |
| 815 | +#[allow(missing_debug_implementations)] |
| 816 | +#[unstable(feature = "provide_any", issue = "none")] |
| 817 | +// SAFETY: `TaggedOption::as_demand` relies on this precise definition. |
| 818 | +#[repr(transparent)] |
| 819 | +pub struct Demand<'a>(dyn Erased<'a> + 'a); |
| 820 | + |
| 821 | +impl<'a> Demand<'a> { |
| 822 | + /// Provide a value or other type with only static lifetimes. |
| 823 | + #[unstable(feature = "provide_any", issue = "none")] |
| 824 | + pub fn provide_value<T, F>(&mut self, fulfil: F) -> &mut Self |
| 825 | + where |
| 826 | + T: 'static, |
| 827 | + F: FnOnce() -> T, |
| 828 | + { |
| 829 | + self.provide_with::<tags::Value<T>, F>(fulfil) |
| 830 | + } |
| 831 | + |
| 832 | + /// Provide a reference, note that the referee type must be bounded by `'static`, but may be unsized. |
| 833 | + #[unstable(feature = "provide_any", issue = "none")] |
| 834 | + pub fn provide_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self { |
| 835 | + self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value) |
| 836 | + } |
| 837 | + |
| 838 | + /// Provide a value with the given `Type` tag. |
| 839 | + fn provide<I>(&mut self, value: I::Reified) -> &mut Self |
| 840 | + where |
| 841 | + I: tags::Type<'a>, |
| 842 | + { |
| 843 | + if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() { |
| 844 | + res.0 = Some(value); |
| 845 | + } |
| 846 | + self |
| 847 | + } |
| 848 | + |
| 849 | + /// Provide a value with the given `Type` tag, using a closure to prevent unnecessary work. |
| 850 | + fn provide_with<I, F>(&mut self, fulfil: F) -> &mut Self |
| 851 | + where |
| 852 | + I: tags::Type<'a>, |
| 853 | + F: FnOnce() -> I::Reified, |
| 854 | + { |
| 855 | + if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() { |
| 856 | + res.0 = Some(fulfil()); |
| 857 | + } |
| 858 | + self |
| 859 | + } |
| 860 | +} |
| 861 | + |
| 862 | +/////////////////////////////////////////////////////////////////////////////// |
| 863 | +// Type tags |
| 864 | +/////////////////////////////////////////////////////////////////////////////// |
| 865 | + |
| 866 | +mod tags { |
| 867 | + //! Type tags are used to identify a type using a separate value. This module includes type tags |
| 868 | + //! for some very common types. |
| 869 | + //! |
| 870 | + //! Many users of the provider APIs will not need to use type tags at all. But if you want to |
| 871 | + //! use them with more complex types (typically those including lifetime parameters), you will |
| 872 | + //! need to write your own tags. |
| 873 | +
|
| 874 | + use crate::marker::PhantomData; |
| 875 | + |
| 876 | + /// This trait is implemented by specific tag types in order to allow |
| 877 | + /// describing a type which can be requested for a given lifetime `'a`. |
| 878 | + /// |
| 879 | + /// A few example implementations for type-driven tags can be found in this |
| 880 | + /// module, although crates may also implement their own tags for more |
| 881 | + /// complex types with internal lifetimes. |
| 882 | + pub trait Type<'a>: Sized + 'static { |
| 883 | + /// The type of values which may be tagged by this tag for the given |
| 884 | + /// lifetime. |
| 885 | + type Reified: 'a; |
| 886 | + } |
| 887 | + |
| 888 | + /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a |
| 889 | + /// `'Sized` bound). E.g., `str`. |
| 890 | + pub trait MaybeSizedType<'a>: Sized + 'static { |
| 891 | + type Reified: 'a + ?Sized; |
| 892 | + } |
| 893 | + |
| 894 | + impl<'a, T: Type<'a>> MaybeSizedType<'a> for T { |
| 895 | + type Reified = T::Reified; |
| 896 | + } |
| 897 | + |
| 898 | + /// Type-based tag for types bounded by `'static`, i.e., with no borrowed element. |
| 899 | + #[derive(Debug)] |
| 900 | + pub struct Value<T: 'static>(PhantomData<T>); |
| 901 | + |
| 902 | + impl<'a, T: 'static> Type<'a> for Value<T> { |
| 903 | + type Reified = T; |
| 904 | + } |
| 905 | + |
| 906 | + /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `'Sized` bound). |
| 907 | + #[derive(Debug)] |
| 908 | + pub struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>); |
| 909 | + |
| 910 | + impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue<T> { |
| 911 | + type Reified = T; |
| 912 | + } |
| 913 | + |
| 914 | + /// Type-based tag for `&'a T` types. |
| 915 | + #[derive(Debug)] |
| 916 | + pub struct Ref<I>(PhantomData<I>); |
| 917 | + |
| 918 | + impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref<I> { |
| 919 | + type Reified = &'a I::Reified; |
| 920 | + } |
| 921 | +} |
| 922 | + |
| 923 | +/// An `Option` with a type tag `I`. |
| 924 | +/// |
| 925 | +/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed |
| 926 | +/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically |
| 927 | +/// checked for the concrete type, there is some degree of type safety. |
| 928 | +#[repr(transparent)] |
| 929 | +struct TaggedOption<'a, I: tags::Type<'a>>(Option<I::Reified>); |
| 930 | + |
| 931 | +impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> { |
| 932 | + fn as_demand(&mut self) -> &mut Demand<'a> { |
| 933 | + // SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Demand<'a>` is safe since |
| 934 | + // `Demand` is repr(transparent) and holds only a `dyn Erased<'a> + 'a`. |
| 935 | + unsafe { transmute(self as &mut (dyn Erased<'a> + 'a)) } |
| 936 | + } |
| 937 | +} |
| 938 | + |
| 939 | +/// Represents a type-erased but identifiable object. |
| 940 | +/// |
| 941 | +/// This trait is exclusively implemented by the `TaggedOption` type. |
| 942 | +trait Erased<'a>: 'a { |
| 943 | + /// The `TypeId` of the erased type. |
| 944 | + fn tag_id(&self) -> TypeId; |
| 945 | +} |
| 946 | + |
| 947 | +impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> { |
| 948 | + fn tag_id(&self) -> TypeId { |
| 949 | + TypeId::of::<I>() |
| 950 | + } |
| 951 | +} |
| 952 | + |
| 953 | +#[unstable(feature = "provide_any", issue = "none")] |
| 954 | +impl<'a> dyn Erased<'a> { |
| 955 | + /// Returns some reference to the dynamic value if it is tagged with `I`, |
| 956 | + /// or `None` if it isn't. |
| 957 | + #[inline] |
| 958 | + fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>> |
| 959 | + where |
| 960 | + I: tags::Type<'a>, |
| 961 | + { |
| 962 | + if self.tag_id() == TypeId::of::<I>() { |
| 963 | + // SAFETY: Just checked whether we're pointing to an I. |
| 964 | + Some(unsafe { &mut *(self as *mut Self as *mut TaggedOption<'a, I>) }) |
| 965 | + } else { |
| 966 | + None |
| 967 | + } |
| 968 | + } |
| 969 | +} |
0 commit comments