Repository navigation
Tracking Issue for Provider API #96024
Copy link
Copy link
Open
Labels
B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.B-RFC-implementedBlocker: Approved by a merged RFC and implemented but not stabilized.Blocker: Approved by a merged RFC and implemented but not stabilized.B-unstableBlocker: Implemented in the nightly compiler and unstable.Blocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Description
Feature gate: #![feature(provide_any)]
This is a tracking issue for RFC 3192
This RFC proposes extending the
anymodule of the core library with a generic API for objects to provide type-based access to data. (In contrast to the existing APIs which provides type-driven downcasting, the proposed extension integrates downcasting into data access to provide a safer and more ergonomic API).
The initial motivating use case for this API is to provide the necessary functionality to add generic member access to the Error trait to generalize extracting context like Backtrace and to make it possible to move the Error trait into core while leaving Backtrace in std.
Public API
// core::any
pub trait Provider {
fn provide<'a>(&'a self, demand: &mut Demand<'a>);
}
pub fn request_value<'a, T>(provider: &'a (impl Provider + ?Sized)) -> Option<T>
where
T: 'static;
pub fn request_ref<'a, T>(provider: &'a (impl Provider + ?Sized)) -> Option<&'a T>
where
T: 'static + ?Sized;
#[repr(transparent)]
pub struct Demand<'a>(_);
impl<'a> Demand<'a> {
pub fn provide_value<T>(&mut self, value: T) -> &mut Self
where
T: 'static;
pub fn provide_value_with<T>(&mut self, fulfil: impl FnOnce() -> T) -> &mut Self
where
T: 'static;
pub fn provide_ref<T: ?Sized + 'static>(&mut self, value: &'a T) -> &mut Self;
pub fn provide_ref_with<T: ?Sized + 'static>(
&mut self,
fulfil: impl FnOnce() -> &'a T,
) -> &mut Self;
pub fn would_be_satisfied_by_value_of<T>(&self) -> bool
where
T: 'static;
pub fn would_be_satisfied_by_ref_of<T>(&self) -> bool
where
T: ?Sized + 'static,
}
impl<'a> fmt::Debug for Demand<'a> {}
// core::error
impl<E> Provider for E
where
E: Error + ?Sized;Steps / History
- Implementation: Add the Provider api to core::any #91970
- Delete the
Providertrait and merge its functionality intoError. - Pick either
demandorrequestand use that name consistently. - LLVM is unable to optimize multiple
.provide_*calls into a switch table because each call fetches the type id fromErased::type_idseparately each time and the compiler doesn't know that these calls all return the same value. This should be fixed. See Add provide_any module to core rfcs#3192 (comment) for one possible solution (although alternative solutions may be possible). - Final comment period (FCP)
- Stabilization PR
Unresolved Questions
- Should the APIs be named
demand_*orrequest_*?
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
B-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.B-RFC-implementedBlocker: Approved by a merged RFC and implemented but not stabilized.Blocker: Approved by a merged RFC and implemented but not stabilized.B-unstableBlocker: Implemented in the nightly compiler and unstable.Blocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Activity
yaahc commentedon Jul 8, 2022
#98912 updates the
request_*functions to have an APIT (arg position impl trait) parameter instead of a standard generic parameter to remove unnecessary inferred parameters while turbofishing.Callers change:
dtolnay commentedon Aug 31, 2022
One minor thing that weirds me out about this API is this impl:
rust/library/core/src/error.rs
Lines 197 to 199 in 02654a0
Since this is a blanket impl (
Selftype is a generic parameter), it is the one blanket impl thatProvideris ever going to be able to have, at least absent some far-future negative impls feature in the language. Any other blanket impl would be considered overlapping and violate coherence.But it's a blanket impl of
core::any::Provider, which is envisioned as being as general-purpose as theAnytrait, for types which implementcore::error::Error, which is a much narrower use case. In some sense this relationship is saying that "Errors are the one true canonical/privileged implementers of the Provider trait; any other application of Provider is second-class".I am wondering which one of the following would be feasible:
Yes, errors are the one privileged application of Provider, and while Provider may be useful for some other things sometimes, all of those are second-class.
a. Maybe move Provider to
core::errorto double down on this view?Remove the blanket impl. What are the things that make the blanket impl necessary for usability of this API, and can those be mitigated a different way?
yaahc commentedon Aug 31, 2022
We could go back to what we had before we move Error into core which was a provide impl just on dyn Error which caused some other paper cuts but I can't remember exactly what those issues were.
thomcc commentedon Aug 31, 2022
Another issue for the provider API that matters for non-error cases is the lack of support for &mut.
I think the initial proposal did support this, at some cost to complexity. While I don't know that we need to support it out of the gate (I've wanted it multiple times when playing around with the API), it would be good to be sure we know it would look like, so that if we want to add it in the future, that we have not painted ourselves into a corner where we cannot do so.
yaahc commentedon Aug 31, 2022
@thomcc I believe all we have to do is expose the tag APIs to support those cases. We didn't change the impl, only the exposed API.
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
Rollup merge of rust-lang#99583 - shepmaster:provider-plus-plus, r=yaahc
62 remaining items
waynr commentedon Jul 29, 2023
@yaahc I think we've captured everything but
in the TODOs for the
error_generic_member_accesstracking issue so we should be able to close this tracking issue, right?Auto merge of #12426 - rust-lang:renovate/compatible, r=epage
Auto merge of rust-lang#113464 - waynr:remove-provider-trait, r=Amanieu
jmjoy commentedon Aug 18, 2023
How about add an optional key? Just like:
then we can provide multi value with the same type, such as:
waynr commentedon Aug 18, 2023
FEI, the Provider API has been rejected by the libs meeting folks. For more background, please see my earlier comment in this issue: #96024 (comment)
The TL;DR is that the
Providertrait has been rejected, leaving just theRequesttype (aka the type formerly known asDemand) and the newprovidemethod on theErrortrait. TheRequesttype and its associated internal-only machinery has been moved from thecore::anymodule intocore::error. This is the state of affairs in latest nightly after #113464 was merged earlier this week.The only thing that's left to do as far as this tracking issue is concerned is to close it (as far as I understand).
TennyZhuang commentedon Sep 5, 2023
Is there any third-party crate to maintain the
Providertrait in the future? Although it may not be suitable to be merged in thestd::any, it's still a useful pattern in some scenarios.waynr commentedon Sep 5, 2023
@TennyZhuang the closest thing I know of was mentioned in the notes for this feature's RFC, which can be found here: provide-any
I don't know how similar this is to what was unstable here in the standard library and there are no published crates.
conradludgate commentedon Sep 5, 2023
There is also the supplier crate that I made in response to this feature being removed. I also consider it unstable but it's a direct lift and shift from the latest provider impl that std had in nightly
https://docs.rs/supplier/0.0.2/supplier/
I had plans to change the API but all my attempts so far have failed to be beneficial
Auto merge of #113464 - waynr:remove-provider-trait, r=Amanieu
lib: remove the provide_any feature when backtrace is activated
lib: remove the provide_any feature when backtrace is activated
lib: remove the provide_any feature when backtrace is activated
lib: remove the provide_any feature when backtrace is activated