|
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`. Generally, end users |
| 95 | +//! should not call `request_*` directly, they are helper functions for intermediate implementers |
| 96 | +//! to use to implement a user-facing interface. This is purely for the sake of ergonomics, there is |
| 97 | +//! safety concern here; intermediate implementers can typically support methods rather than |
| 98 | +//! free functions and use more specific names. |
| 99 | +//! |
| 100 | +//! Typically, a data provider is a trait object of a trait which extends `Provider`. A user will |
| 101 | +//! request data from a trait object by specifying the type of the data. |
| 102 | +//! |
| 103 | +//! ## Data flow |
| 104 | +//! |
| 105 | +//! * A user requests an object of a specific type, which is delegated to `request_value` or |
| 106 | +//! `request_ref` |
| 107 | +//! * `request_*` creates a `Demand` object and passes it to `Provider::provide` |
| 108 | +//! * The data provider's implementation of `Provider::provide` tries providing values of |
| 109 | +//! different types using `Demand::provide_*`. If the type matches the type requested by |
| 110 | +//! the user, the value will be stored in the `Demand` object. |
| 111 | +//! * `request_*` unpacks the `Demand` object and returns any stored value to the user. |
| 112 | +//! |
| 113 | +//! ## Examples |
| 114 | +//! |
| 115 | +//! ``` |
| 116 | +//! # #![feature(provide_any)] |
| 117 | +//! use std::any::{Provider, Demand, request_ref}; |
| 118 | +//! |
| 119 | +//! // Definition of MyTrait, a data provider. |
| 120 | +//! trait MyTrait: Provider { |
| 121 | +//! // ... |
| 122 | +//! } |
| 123 | +//! |
| 124 | +//! // Methods on `MyTrait` trait objects. |
| 125 | +//! impl dyn MyTrait + '_ { |
| 126 | +//! /// Get a reference to a field of the implementing struct. |
| 127 | +//! pub fn get_context_by_ref<T: ?Sized + 'static>(&self) -> Option<&T> { |
| 128 | +//! request_ref::<T, _>(self) |
| 129 | +//! } |
| 130 | +//! } |
| 131 | +//! |
| 132 | +//! // Downstream implementation of `MyTrait` and `Provider`. |
| 133 | +//! # struct SomeConcreteType { some_string: String } |
| 134 | +//! impl MyTrait for SomeConcreteType { |
| 135 | +//! // ... |
| 136 | +//! } |
| 137 | +//! |
| 138 | +//! impl Provider for SomeConcreteType { |
| 139 | +//! fn provide<'a>(&'a self, demand: &mut Demand<'a>) { |
| 140 | +//! // Provide a string reference. We could provide multiple values with |
| 141 | +//! // different types here. |
| 142 | +//! demand.provide_ref::<String>(&self.some_string); |
| 143 | +//! } |
| 144 | +//! } |
| 145 | +//! |
| 146 | +//! // Downstream usage of `MyTrait`. |
| 147 | +//! fn use_my_trait(obj: &dyn MyTrait) { |
| 148 | +//! // Request a &String from obj. |
| 149 | +//! let _ = obj.get_context_by_ref::<String>().unwrap(); |
| 150 | +//! } |
| 151 | +//! ``` |
| 152 | +//! |
| 153 | +//! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then |
| 154 | +//! the `get_context_ref` call will return a reference to `obj.some_string` with type `&String`. |
84 | 155 |
|
85 | 156 | #![stable(feature = "rust1", since = "1.0.0")]
|
86 | 157 |
|
@@ -700,3 +771,302 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
|
700 | 771 | pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
|
701 | 772 | type_name::<T>()
|
702 | 773 | }
|
| 774 | + |
| 775 | +/////////////////////////////////////////////////////////////////////////////// |
| 776 | +// Provider trait |
| 777 | +/////////////////////////////////////////////////////////////////////////////// |
| 778 | + |
| 779 | +/// Trait implemented by a type which can dynamically provide values based on type. |
| 780 | +#[unstable(feature = "provide_any", issue = "96024")] |
| 781 | +pub trait Provider { |
| 782 | + /// Data providers should implement this method to provide *all* values they are able to |
| 783 | + /// provide by using `demand`. |
| 784 | + /// |
| 785 | + /// Note that the `provide_*` methods on `Demand` have short-circuit semantics: if an earlier |
| 786 | + /// method has successfully provided a value, then later methods will not get an opportunity to |
| 787 | + /// provide. |
| 788 | + /// |
| 789 | + /// # Examples |
| 790 | + /// |
| 791 | + /// Provides a reference to a field with type `String` as a `&str`, and a value of |
| 792 | + /// type `i32`. |
| 793 | + /// |
| 794 | + /// ```rust |
| 795 | + /// # #![feature(provide_any)] |
| 796 | + /// use std::any::{Provider, Demand}; |
| 797 | + /// # struct SomeConcreteType { field: String, num_field: i32 } |
| 798 | + /// |
| 799 | + /// impl Provider for SomeConcreteType { |
| 800 | + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { |
| 801 | + /// demand.provide_ref::<str>(&self.field) |
| 802 | + /// .provide_value::<i32, _>(|| self.num_field); |
| 803 | + /// } |
| 804 | + /// } |
| 805 | + /// ``` |
| 806 | + #[unstable(feature = "provide_any", issue = "96024")] |
| 807 | + fn provide<'a>(&'a self, demand: &mut Demand<'a>); |
| 808 | +} |
| 809 | + |
| 810 | +/// Request a value from the `Provider`. |
| 811 | +/// |
| 812 | +/// # Examples |
| 813 | +/// |
| 814 | +/// Get a string value from a provider. |
| 815 | +/// |
| 816 | +/// ```rust |
| 817 | +/// # #![feature(provide_any)] |
| 818 | +/// use std::any::{Provider, request_value}; |
| 819 | +/// |
| 820 | +/// fn get_string<P: Provider>(provider: &P) -> String { |
| 821 | +/// request_value::<String, _>(provider).unwrap() |
| 822 | +/// } |
| 823 | +/// ``` |
| 824 | +#[unstable(feature = "provide_any", issue = "96024")] |
| 825 | +pub fn request_value<'a, T, P>(provider: &'a P) -> Option<T> |
| 826 | +where |
| 827 | + T: 'static, |
| 828 | + P: Provider + ?Sized, |
| 829 | +{ |
| 830 | + request_by_type_tag::<'a, tags::Value<T>, P>(provider) |
| 831 | +} |
| 832 | + |
| 833 | +/// Request a reference from the `Provider`. |
| 834 | +/// |
| 835 | +/// # Examples |
| 836 | +/// |
| 837 | +/// Get a string reference from a provider. |
| 838 | +/// |
| 839 | +/// ```rust |
| 840 | +/// # #![feature(provide_any)] |
| 841 | +/// use std::any::{Provider, request_ref}; |
| 842 | +/// |
| 843 | +/// fn get_str<P: Provider>(provider: &P) -> &str { |
| 844 | +/// request_ref::<str, _>(provider).unwrap() |
| 845 | +/// } |
| 846 | +/// ``` |
| 847 | +#[unstable(feature = "provide_any", issue = "96024")] |
| 848 | +pub fn request_ref<'a, T, P>(provider: &'a P) -> Option<&'a T> |
| 849 | +where |
| 850 | + T: 'static + ?Sized, |
| 851 | + P: Provider + ?Sized, |
| 852 | +{ |
| 853 | + request_by_type_tag::<'a, tags::Ref<tags::MaybeSizedValue<T>>, P>(provider) |
| 854 | +} |
| 855 | + |
| 856 | +/// Request a specific value by tag from the `Provider`. |
| 857 | +fn request_by_type_tag<'a, I, P>(provider: &'a P) -> Option<I::Reified> |
| 858 | +where |
| 859 | + I: tags::Type<'a>, |
| 860 | + P: Provider + ?Sized, |
| 861 | +{ |
| 862 | + let mut tagged = TaggedOption::<'a, I>(None); |
| 863 | + provider.provide(tagged.as_demand()); |
| 864 | + tagged.0 |
| 865 | +} |
| 866 | + |
| 867 | +/////////////////////////////////////////////////////////////////////////////// |
| 868 | +// Demand and its methods |
| 869 | +/////////////////////////////////////////////////////////////////////////////// |
| 870 | + |
| 871 | +/// A helper object for providing data by type. |
| 872 | +/// |
| 873 | +/// A data provider provides values by calling this type's provide methods. |
| 874 | +#[unstable(feature = "provide_any", issue = "96024")] |
| 875 | +#[repr(transparent)] |
| 876 | +pub struct Demand<'a>(dyn Erased<'a> + 'a); |
| 877 | + |
| 878 | +impl<'a> Demand<'a> { |
| 879 | + /// Create a new `&mut Demand` from a `&mut dyn Erased` trait object. |
| 880 | + fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Demand<'a> { |
| 881 | + // SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Demand<'a>` is safe since |
| 882 | + // `Demand` is repr(transparent). |
| 883 | + unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Demand<'a>) } |
| 884 | + } |
| 885 | + |
| 886 | + /// Provide a value or other type with only static lifetimes. |
| 887 | + /// |
| 888 | + /// # Examples |
| 889 | + /// |
| 890 | + /// Provides a `String` by cloning. |
| 891 | + /// |
| 892 | + /// ```rust |
| 893 | + /// # #![feature(provide_any)] |
| 894 | + /// use std::any::{Provider, Demand}; |
| 895 | + /// # struct SomeConcreteType { field: String } |
| 896 | + /// |
| 897 | + /// impl Provider for SomeConcreteType { |
| 898 | + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { |
| 899 | + /// demand.provide_value::<String, _>(|| self.field.clone()); |
| 900 | + /// } |
| 901 | + /// } |
| 902 | + /// ``` |
| 903 | + #[unstable(feature = "provide_any", issue = "96024")] |
| 904 | + pub fn provide_value<T, F>(&mut self, fulfil: F) -> &mut Self |
| 905 | + where |
| 906 | + T: 'static, |
| 907 | + F: FnOnce() -> T, |
| 908 | + { |
| 909 | + self.provide_with::<tags::Value<T>, F>(fulfil) |
| 910 | + } |
| 911 | + |
| 912 | + /// Provide a reference, note that the referee type must be bounded by `'static`, |
| 913 | + /// but may be unsized. |
| 914 | + /// |
| 915 | + /// # Examples |
| 916 | + /// |
| 917 | + /// Provides a reference to a field as a `&str`. |
| 918 | + /// |
| 919 | + /// ```rust |
| 920 | + /// # #![feature(provide_any)] |
| 921 | + /// use std::any::{Provider, Demand}; |
| 922 | + /// # struct SomeConcreteType { field: String } |
| 923 | + /// |
| 924 | + /// impl Provider for SomeConcreteType { |
| 925 | + /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) { |
| 926 | + /// demand.provide_ref::<str>(&self.field); |
| 927 | + /// } |
| 928 | + /// } |
| 929 | + /// ``` |
| 930 | + #[unstable(feature = "provide_any", issue = "96024")] |
| 931 | + pub fn provide_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self { |
| 932 | + self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value) |
| 933 | + } |
| 934 | + |
| 935 | + /// Provide a value with the given `Type` tag. |
| 936 | + fn provide<I>(&mut self, value: I::Reified) -> &mut Self |
| 937 | + where |
| 938 | + I: tags::Type<'a>, |
| 939 | + { |
| 940 | + if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() { |
| 941 | + res.0 = Some(value); |
| 942 | + } |
| 943 | + self |
| 944 | + } |
| 945 | + |
| 946 | + /// Provide a value with the given `Type` tag, using a closure to prevent unnecessary work. |
| 947 | + fn provide_with<I, F>(&mut self, fulfil: F) -> &mut Self |
| 948 | + where |
| 949 | + I: tags::Type<'a>, |
| 950 | + F: FnOnce() -> I::Reified, |
| 951 | + { |
| 952 | + if let Some(res @ TaggedOption(None)) = self.0.downcast_mut::<I>() { |
| 953 | + res.0 = Some(fulfil()); |
| 954 | + } |
| 955 | + self |
| 956 | + } |
| 957 | +} |
| 958 | + |
| 959 | +#[unstable(feature = "provide_any", issue = "96024")] |
| 960 | +impl<'a> fmt::Debug for Demand<'a> { |
| 961 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 962 | + f.debug_struct("Demand").finish_non_exhaustive() |
| 963 | + } |
| 964 | +} |
| 965 | + |
| 966 | +/////////////////////////////////////////////////////////////////////////////// |
| 967 | +// Type tags |
| 968 | +/////////////////////////////////////////////////////////////////////////////// |
| 969 | + |
| 970 | +mod tags { |
| 971 | + //! Type tags are used to identify a type using a separate value. This module includes type tags |
| 972 | + //! for some very common types. |
| 973 | + //! |
| 974 | + //! Currently type tags are not exposed to the user. But in the future, if you want to use the |
| 975 | + //! Provider API with more complex types (typically those including lifetime parameters), you |
| 976 | + //! will need to write your own tags. |
| 977 | +
|
| 978 | + use crate::marker::PhantomData; |
| 979 | + |
| 980 | + /// This trait is implemented by specific tag types in order to allow |
| 981 | + /// describing a type which can be requested for a given lifetime `'a`. |
| 982 | + /// |
| 983 | + /// A few example implementations for type-driven tags can be found in this |
| 984 | + /// module, although crates may also implement their own tags for more |
| 985 | + /// complex types with internal lifetimes. |
| 986 | + pub trait Type<'a>: Sized + 'static { |
| 987 | + /// The type of values which may be tagged by this tag for the given |
| 988 | + /// lifetime. |
| 989 | + type Reified: 'a; |
| 990 | + } |
| 991 | + |
| 992 | + /// Similar to the [`Type`] trait, but represents a type which may be unsized (i.e., has a |
| 993 | + /// `?Sized` bound). E.g., `str`. |
| 994 | + pub trait MaybeSizedType<'a>: Sized + 'static { |
| 995 | + type Reified: 'a + ?Sized; |
| 996 | + } |
| 997 | + |
| 998 | + impl<'a, T: Type<'a>> MaybeSizedType<'a> for T { |
| 999 | + type Reified = T::Reified; |
| 1000 | + } |
| 1001 | + |
| 1002 | + /// Type-based tag for types bounded by `'static`, i.e., with no borrowed elements. |
| 1003 | + #[derive(Debug)] |
| 1004 | + pub struct Value<T: 'static>(PhantomData<T>); |
| 1005 | + |
| 1006 | + impl<'a, T: 'static> Type<'a> for Value<T> { |
| 1007 | + type Reified = T; |
| 1008 | + } |
| 1009 | + |
| 1010 | + /// Type-based tag similar to [`Value`] but which may be unsized (i.e., has a `'Sized` bound). |
| 1011 | + #[derive(Debug)] |
| 1012 | + pub struct MaybeSizedValue<T: ?Sized + 'static>(PhantomData<T>); |
| 1013 | + |
| 1014 | + impl<'a, T: ?Sized + 'static> MaybeSizedType<'a> for MaybeSizedValue<T> { |
| 1015 | + type Reified = T; |
| 1016 | + } |
| 1017 | + |
| 1018 | + /// Type-based tag for reference types (`&'a T`, where T is represented by |
| 1019 | + /// `<I as MaybeSizedType<'a>>::Reified`. |
| 1020 | + #[derive(Debug)] |
| 1021 | + pub struct Ref<I>(PhantomData<I>); |
| 1022 | + |
| 1023 | + impl<'a, I: MaybeSizedType<'a>> Type<'a> for Ref<I> { |
| 1024 | + type Reified = &'a I::Reified; |
| 1025 | + } |
| 1026 | +} |
| 1027 | + |
| 1028 | +/// An `Option` with a type tag `I`. |
| 1029 | +/// |
| 1030 | +/// Since this struct implements `Erased`, the type can be erased to make a dynamically typed |
| 1031 | +/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically |
| 1032 | +/// checked for the concrete type, there is some degree of type safety. |
| 1033 | +#[repr(transparent)] |
| 1034 | +struct TaggedOption<'a, I: tags::Type<'a>>(Option<I::Reified>); |
| 1035 | + |
| 1036 | +impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> { |
| 1037 | + fn as_demand(&mut self) -> &mut Demand<'a> { |
| 1038 | + Demand::new(self as &mut (dyn Erased<'a> + 'a)) |
| 1039 | + } |
| 1040 | +} |
| 1041 | + |
| 1042 | +/// Represents a type-erased but identifiable object. |
| 1043 | +/// |
| 1044 | +/// This trait is exclusively implemented by the `TaggedOption` type. |
| 1045 | +unsafe trait Erased<'a>: 'a { |
| 1046 | + /// The `TypeId` of the erased type. |
| 1047 | + fn tag_id(&self) -> TypeId; |
| 1048 | +} |
| 1049 | + |
| 1050 | +unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> { |
| 1051 | + fn tag_id(&self) -> TypeId { |
| 1052 | + TypeId::of::<I>() |
| 1053 | + } |
| 1054 | +} |
| 1055 | + |
| 1056 | +#[unstable(feature = "provide_any", issue = "96024")] |
| 1057 | +impl<'a> dyn Erased<'a> + 'a { |
| 1058 | + /// Returns some reference to the dynamic value if it is tagged with `I`, |
| 1059 | + /// or `None` otherwise. |
| 1060 | + #[inline] |
| 1061 | + fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>> |
| 1062 | + where |
| 1063 | + I: tags::Type<'a>, |
| 1064 | + { |
| 1065 | + if self.tag_id() == TypeId::of::<I>() { |
| 1066 | + // SAFETY: Just checked whether we're pointing to an I. |
| 1067 | + Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() }) |
| 1068 | + } else { |
| 1069 | + None |
| 1070 | + } |
| 1071 | + } |
| 1072 | +} |
0 commit comments