summaryrefslogtreecommitdiffstats
path: root/library/core/src/any.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/any.rs')
-rw-r--r--library/core/src/any.rs244
1 files changed, 234 insertions, 10 deletions
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index f20c497a1..1a379ecc1 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -1,7 +1,4 @@
-//! This module contains the `Any` trait, which enables dynamic typing
-//! of any `'static` type through runtime reflection. It also contains the
-//! `Provider` trait and accompanying API, which enable trait objects to provide
-//! data based on typed requests, an alternate form of runtime reflection.
+//! Utilities for dynamic typing or type reflection.
//!
//! # `Any` and `TypeId`
//!
@@ -799,7 +796,7 @@ pub trait Provider {
/// impl Provider for SomeConcreteType {
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
/// demand.provide_ref::<str>(&self.field)
- /// .provide_value::<i32>(|| self.num_field);
+ /// .provide_value::<i32>(self.num_field);
/// }
/// }
/// ```
@@ -884,28 +881,55 @@ impl<'a> Demand<'a> {
///
/// # Examples
///
+ /// Provides an `u8`.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ /// # struct SomeConcreteType { field: u8 }
+ ///
+ /// impl Provider for SomeConcreteType {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_value::<u8>(self.field);
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn provide_value<T>(&mut self, value: T) -> &mut Self
+ where
+ T: 'static,
+ {
+ self.provide::<tags::Value<T>>(value)
+ }
+
+ /// Provide a value or other type with only static lifetimes computed using a closure.
+ ///
+ /// # Examples
+ ///
/// Provides a `String` by cloning.
///
/// ```rust
- /// # #![feature(provide_any)]
+ /// #![feature(provide_any)]
+ ///
/// use std::any::{Provider, Demand};
/// # struct SomeConcreteType { field: String }
///
/// impl Provider for SomeConcreteType {
/// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
- /// demand.provide_value::<String>(|| self.field.clone());
+ /// demand.provide_value_with::<String>(|| self.field.clone());
/// }
/// }
/// ```
#[unstable(feature = "provide_any", issue = "96024")]
- pub fn provide_value<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
+ pub fn provide_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
where
T: 'static,
{
self.provide_with::<tags::Value<T>>(fulfil)
}
- /// Provide a reference, note that the referee type must be bounded by `'static`,
+ /// Provide a reference. The referee type must be bounded by `'static`,
/// but may be unsized.
///
/// # Examples
@@ -913,7 +937,8 @@ impl<'a> Demand<'a> {
/// Provides a reference to a field as a `&str`.
///
/// ```rust
- /// # #![feature(provide_any)]
+ /// #![feature(provide_any)]
+ ///
/// use std::any::{Provider, Demand};
/// # struct SomeConcreteType { field: String }
///
@@ -928,6 +953,40 @@ impl<'a> Demand<'a> {
self.provide::<tags::Ref<tags::MaybeSizedValue<T>>>(value)
}
+ /// Provide a reference computed using a closure. The referee type
+ /// must be bounded by `'static`, but may be unsized.
+ ///
+ /// # Examples
+ ///
+ /// Provides a reference to a field as a `&str`.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ /// # struct SomeConcreteType { business: String, party: String }
+ /// # fn today_is_a_weekday() -> bool { true }
+ ///
+ /// impl Provider for SomeConcreteType {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_ref_with::<str>(|| {
+ /// if today_is_a_weekday() {
+ /// &self.business
+ /// } else {
+ /// &self.party
+ /// }
+ /// });
+ /// }
+ /// }
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn provide_ref_with<T: ?Sized + 'static>(
+ &mut self,
+ fulfil: impl FnOnce() -> &'a T,
+ ) -> &mut Self {
+ self.provide_with::<tags::Ref<tags::MaybeSizedValue<T>>>(fulfil)
+ }
+
/// Provide a value with the given `Type` tag.
fn provide<I>(&mut self, value: I::Reified) -> &mut Self
where
@@ -949,6 +1008,156 @@ impl<'a> Demand<'a> {
}
self
}
+
+ /// Check if the `Demand` would be satisfied if provided with a
+ /// value of the specified type. If the type does not match or has
+ /// already been provided, returns false.
+ ///
+ /// # Examples
+ ///
+ /// Check if an `u8` still needs to be provided and then provides
+ /// it.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ ///
+ /// struct Parent(Option<u8>);
+ ///
+ /// impl Provider for Parent {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// if let Some(v) = self.0 {
+ /// demand.provide_value::<u8>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// struct Child {
+ /// parent: Parent,
+ /// }
+ ///
+ /// impl Child {
+ /// // Pretend that this takes a lot of resources to evaluate.
+ /// fn an_expensive_computation(&self) -> Option<u8> {
+ /// Some(99)
+ /// }
+ /// }
+ ///
+ /// impl Provider for Child {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // an `u8` value or not...
+ /// self.parent.provide(demand);
+ ///
+ /// // ...so we check to see if the `u8` is needed before
+ /// // we run our expensive computation.
+ /// if demand.would_be_satisfied_by_value_of::<u8>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// demand.provide_value::<u8>(v);
+ /// }
+ /// }
+ ///
+ /// // The demand will be satisfied now, regardless of if
+ /// // the parent provided the value or we did.
+ /// assert!(!demand.would_be_satisfied_by_value_of::<u8>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some(42));
+ /// let child = Child { parent };
+ /// assert_eq!(Some(42), std::any::request_value::<u8>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent };
+ /// assert_eq!(Some(99), std::any::request_value::<u8>(&child));
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn would_be_satisfied_by_value_of<T>(&self) -> bool
+ where
+ T: 'static,
+ {
+ self.would_be_satisfied_by::<tags::Value<T>>()
+ }
+
+ /// Check if the `Demand` would be satisfied if provided with a
+ /// reference to a value of the specified type. If the type does
+ /// not match or has already been provided, returns false.
+ ///
+ /// # Examples
+ ///
+ /// Check if a `&str` still needs to be provided and then provides
+ /// it.
+ ///
+ /// ```rust
+ /// #![feature(provide_any)]
+ ///
+ /// use std::any::{Provider, Demand};
+ ///
+ /// struct Parent(Option<String>);
+ ///
+ /// impl Provider for Parent {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// if let Some(v) = &self.0 {
+ /// demand.provide_ref::<str>(v);
+ /// }
+ /// }
+ /// }
+ ///
+ /// struct Child {
+ /// parent: Parent,
+ /// name: String,
+ /// }
+ ///
+ /// impl Child {
+ /// // Pretend that this takes a lot of resources to evaluate.
+ /// fn an_expensive_computation(&self) -> Option<&str> {
+ /// Some(&self.name)
+ /// }
+ /// }
+ ///
+ /// impl Provider for Child {
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// // In general, we don't know if this call will provide
+ /// // a `str` reference or not...
+ /// self.parent.provide(demand);
+ ///
+ /// // ...so we check to see if the `&str` is needed before
+ /// // we run our expensive computation.
+ /// if demand.would_be_satisfied_by_ref_of::<str>() {
+ /// if let Some(v) = self.an_expensive_computation() {
+ /// demand.provide_ref::<str>(v);
+ /// }
+ /// }
+ ///
+ /// // The demand will be satisfied now, regardless of if
+ /// // the parent provided the reference or we did.
+ /// assert!(!demand.would_be_satisfied_by_ref_of::<str>());
+ /// }
+ /// }
+ ///
+ /// let parent = Parent(Some("parent".into()));
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("parent"), std::any::request_ref::<str>(&child));
+ ///
+ /// let parent = Parent(None);
+ /// let child = Child { parent, name: "child".into() };
+ /// assert_eq!(Some("child"), std::any::request_ref::<str>(&child));
+ /// ```
+ #[unstable(feature = "provide_any", issue = "96024")]
+ pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool
+ where
+ T: ?Sized + 'static,
+ {
+ self.would_be_satisfied_by::<tags::Ref<tags::MaybeSizedValue<T>>>()
+ }
+
+ fn would_be_satisfied_by<I>(&self) -> bool
+ where
+ I: tags::Type<'a>,
+ {
+ matches!(self.0.downcast::<I>(), Some(TaggedOption(None)))
+ }
}
#[unstable(feature = "provide_any", issue = "96024")]
@@ -1053,6 +1262,21 @@ impl<'a> dyn Erased<'a> + 'a {
/// Returns some reference to the dynamic value if it is tagged with `I`,
/// or `None` otherwise.
#[inline]
+ fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>>
+ where
+ I: tags::Type<'a>,
+ {
+ if self.tag_id() == TypeId::of::<I>() {
+ // SAFETY: Just checked whether we're pointing to an I.
+ Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
+ } else {
+ None
+ }
+ }
+
+ /// Returns some mutable reference to the dynamic value if it is tagged with `I`,
+ /// or `None` otherwise.
+ #[inline]
fn downcast_mut<I>(&mut self) -> Option<&mut TaggedOption<'a, I>>
where
I: tags::Type<'a>,