-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Open
Labels
A-specializationArea: Trait impl specializationArea: Trait impl specializationC-feature-requestCategory: A feature request, i.e: not implemented / a PR.Category: A feature request, i.e: not implemented / a PR.T-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.
Description
I am trying to implement a trait for Option<T> with a special case for Option<bool>.
It is about a trait for converting object to intermediate form for using in FFI.
The trait definition is like this:
trait IntoInterm {
type IntermT: Default + Debug + ?Sized;
fn into_interm(self) -> Result<Self::IntermT, Error>;
}Desired behavior:
-
For
Option<T>(general case):Option<T> -> IntermediateOption
-
For
Option<bool>(special case):Option<bool> -> IntermediateOptionBool
This is required for FFI reasons (ABI/layout differences).
Object definitions:
#[repr(C)]
#[derive(Debug, Default)]
pub struct IntermOption {
pub value: *mut c_void,
pub item_type: IntermType
}#[repr(C)]
#[derive(Debug, Default)]
pub struct IntermOptionBool {
pub kind: OptionKind, // Some | None,
pub value: bool
}The reason for such a definition is to achieve generality.
Attempt 1: Stable Rust (expectedly impossible)
On stable Rust, this is not possible due to the lack of:
- specialization
- negative bounds (
T != bool) - conditional type constraints
- difference of return types
This part is understood and expected.
Attempt 2: Nightly specialization (fails)
Code
#![feature(specialization)]
impl<T> IntoInterm for Option<T>
where
T: IntoInterm,
{
default type IntermT = IntermediateOption<T::IntermT>;
default fn into_interm(self) -> Self::IntermT {
// implementations
Ok(IntermOption { /* ... */ }) // or even Ok(Self::IntermT { /* ... */ })
}
}
impl IntoInterm for Option<bool> {
type IntermT = IntermediateOptionBool;
fn into_interm(self) -> Self::IntermT {
if let Some(val) = self {
Ok(IntermOptionBool { kind: SOME, value: val })
}
else {
Ok(IntermOptionBool { kind: NONE, value: false })
}
}
}Error
error[E0308]: mismatched types
default type IntermT = IntermOption;
------------------------------------ associated type is `default` and may be overridden
Ok(IntermOption { /* ... */ })
^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `IntermOption`
Attempt 3: Indirection via helper traits (also fails)
A natural workaround is to defer construction via another trait, e.g.:
trait OptionCtor<V> {
fn some(v: V) -> Self;
fn none() -> Self;
}and then require:
where Self::IntermT: OptionCtor<T::IntermT>However, this is not allowed, constraints on Self::IntermT inside a specializing impl are rejected. So this approach is also invalid.
What's the solution?
Metadata
Metadata
Assignees
Labels
A-specializationArea: Trait impl specializationArea: Trait impl specializationC-feature-requestCategory: A feature request, i.e: not implemented / a PR.Category: A feature request, i.e: not implemented / a PR.T-typesRelevant to the types team, which will review and decide on the PR/issue.Relevant to the types team, which will review and decide on the PR/issue.