-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Description
Feature gate: #![feature(error_generic_member_multi_access)]
This is a tracking issue for the generic member multi access API on the error trait, which allows non-O(n^2) access to multiple provided Error members.
What is being stabilized
core::error::provide gets the following new sealed traits:
MultiResponse- represents a response containing values from multiple types, and allows fecthing these responsesfor<'a> IntoMultiRequest<'a>, representing the types, which does not have functions that are usable by users, but is rather used to represent the "type chain" (if we decide we stabilize this API only once we have variadic generics, we could replace it with a tuple of "values/references").
The MultiResponse trait has the following accessors:
fn retrieve_ref<R: ?Sized + 'static>(&mut self) -> Option<R>
where
R: ?Sized + 'static;
fn retrieve_value<V: 'static>(&mut self) -> Option<V>and the following new structs, all PhantomData-like:
MultiRequestBuilder<T: IntoMultiRequest>EmptyMultiRequestBuilder: IntoMultiRequestChainRefMultiRequestBuilder<R: 'static + ?Sized, NEXT: IntoMultiRequest>: IntoMultiRequestChainValMultiRequestBuilder<V: 'static, NEXT: IntoMultiRequest>: IntoMultiRequest
EmptyMultiRequestBuilder, ChainRefMultiRequestBuilder and ChainValMultiRequestBuilder don't have any methods on them and are only supposed to be used as the type parameter for MultiRequestBuilder.
MultiRequestBuilder has the following functions which allow building it up:
MultiRequestBuilder::<EmptyMultiRequestBuilder>::new() -> Self
MultiRequestBuilder::<T>::with_value::<V: 'static>(&self) -> MultiRequestBuilder<ChainValMultiRequestBuilder<V, T>>
MultiRequestBuilder::<T>::with_ref::<R: 'static + ?Sized>(&self) -> MultiRequestBuilder<ChainRefMultiRequestBuilder<R, T>>
MultiRequestBuilder<T> also has a request function:
MultiRequestBuilder::<T>::request::<'a>(self, err: &'a (impl Error + ?Sized)) -> impl MultiResponse<'a>
The request function calls the error's provide function to gather up all the responses requested in the request, and packs them into a MultiResponse.
EmptyMultiResponse , ChainRefMultiResponse and ChainValMultiResponse are only supposed to be used behind the impl MultiResponse and are not really user-visible.
An example use looks like:
#![feature(error_generic_member_access)]
use core::fmt;
use core::error::{Error, provide::MultiResponse, Request};
#[derive(Debug)]
struct MyError {
str_field: &'static str,
val_field: MyExitCode,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct MyExitCode(u32);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Example Error")
}
}
impl Error for MyError {
fn provide<'a>(&'a self, request: &mut Request<'a>) {
request
.provide_ref::<str>(self.str_field)
.provide_value::<MyExitCode>(self.val_field);
}
}
fn main() {
let e = MyError {
str_field: "hello",
val_field: MyExitCode(3),
};
let mut request= core::error::provide::MultiRequestBuilder::new()
// request by reference
.with_ref::<str>()
// and by value
.with_value::<MyExitCode>()
// and some type that isn't in the error
.with_value::<String>()
.request(&e);
assert_eq!(request.retrieve_value::<MyExitCode>(, Some(MyExitCode(3)));
assert_eq!(request.retrieve_ref::<str>(), Some("hello"));
assert_eq!(request.retrieve_value::<String>(), None);
}Steps / History
Implemented in #149615
Unresolved Questions
- Is this API necessary? If we can make the implementation of
Error::providealways O(1) by better LLVM optimizations, then we might not need it. - Are there any users? Currently this API exists to ensure there is a path forward for users, but all known users of the provide API are not making a large number of requests.