rust-lang / rust-lang/rust

Tracking Issue for `error_generic_member_multi_access`

Open
#149,822 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

C-tracking-issue
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

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:

  1. MultiResponse - represents a response containing values from multiple types, and allows fecthing these responses
  2. for<'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:

  1. MultiRequestBuilder<T: IntoMultiRequest>
  2. EmptyMultiRequestBuilder: IntoMultiRequest
  3. ChainRefMultiRequestBuilder<R: 'static + ?Sized, NEXT: IntoMultiRequest> : IntoMultiRequest
  4. ChainValMultiRequestBuilder<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
  1. Is this API necessary? If we can make the implementation of Error::provide always O(1) by better LLVM optimizations, then we might not need it.
  2. 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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the implementation referenced in #149615 and the core::error::provide API described here. Check the Error::provide interaction and the example's requested reference and value behavior; done means the unresolved necessity and user-demand questions have an agreed stabilization direction.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.