Skip to content

Tracking Issue for error_generic_member_multi_access #149822

@arielb1

Description

@arielb1

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions