-
Notifications
You must be signed in to change notification settings - Fork 14.1k
[semi-wip] implement error multi provider #149615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer |
This comment was marked as resolved.
This comment was marked as resolved.
API Sketch
The fn retrieve_ref<R: ?Sized + 'static>(&mut self, fulfil: impl FnOnce(&'a R)) -> &mut Self
where
R: ?Sized + 'static;
fn retrieve_value<V: 'static>(&mut self, fulfil: impl FnOnce(V)) -> &mut Selfand the following new structs, all
The
An example use looks like: #![feature(error_generic_member_access)]
use core::fmt;
use core::error::{Error, 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 str_val = None;
let mut exit_code_val = None;
let mut string_val = None;
let mut value = core::error::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)
// The error has str by reference
.retrieve_ref::<str>(|val| str_val = Some(val))
// The error has MyExitCode by value
.retrieve_value::<MyExitCode>(|val| exit_code_val = Some(val))
// The error does not have a string field, consume will not be called
.retrieve_value::<String>(|val| string_val = Some(val));
assert_eq!(exit_code_val, Some(MyExitCode(3)));
assert_eq!(str_val, Some("hello"));
assert_eq!(string_val, None);
}Alternatives
|
3afed4d to
a87888f
Compare
|
done the rebase |
This comment was marked as resolved.
This comment was marked as resolved.
Will do that |
a87888f to
bc38a1b
Compare
|
The alternative would look like this: #![feature(error_generic_member_access)]
use core::fmt;
use core::error::{Error, 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 str_val = None;
let mut exit_code_val = None;
let mut string_val = None;
let mut value = core::error::MultiRequestBuilder::new()
// request by reference
.with_ref::<str>(&mut str_val)
// and by value
.with_value::<MyExitCode>(&mut exit_code_val)
// and some type that isn't in the error
.with_value::<String>(&mut string_val)
.request(&e);
assert_eq!(exit_code_val, Some(MyExitCode(3)));
assert_eq!(str_val, Some("hello"));
assert_eq!(string_val, None);
}Does feel somewhat better. Should we switch? In some sense like the builder not having mutable references to things, but this does feel OK. |
This comment has been minimized.
This comment has been minimized.
bc38a1b to
a3209a5
Compare
Implement an error multi provider which allows retrieving multiple types from an Error without
O(n^2)performance.This does make the current
RequestAPI slightly slower in some cases because it ends up loading the type id from memory multiple times. I do think there are a few ways around this that require some compiler support - for example, we could somehow store the type id in the vtable. However, the currentRequestAPI is very rarely hot so I do not think this is a big problem, and it will not actually become super-slow, it will just perform several reads and branches which are normally fairly fast operations.cc https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/Pushing.20error_generic_member_access.20forward/with/538480946
cc #99301
This still needs to be cleaned up a little, and I'm not that sure this is the best API, but it works and I want to put it for review
r? @the8472