I want to be able to construct enum values by giving the variant constructor a value:
use self::Variants::*;
#[derive(Clone, Debug)]
enum Variants {
Unit(()),
One(u8),
}
fn emit<C: Fn(S) -> T, S, T>(constructor: C, value: S) -> T {
constructor(value)
}
fn main() {
let unit: Variants = emit(&Unit, ());
println!("{:?}", unit); // Prints Unit(()).
let one: Variants = emit(&One, 10);
println!("{:?}", one); // Prints One(10).
}
The issue with this example is that I need () in Unit(()) instead of the more normal Unit (without parameter).
I tried using specialization:
#![feature(specialization)]
trait Constructor<S, T> {
fn construct(self, value: S) -> T;
}
impl<T> Constructor<(), T> for T {
fn construct(self, _value: ()) -> T {
self
}
}
impl<F: Fn(S) -> T, S, T> Constructor<S, T> for F {
default fn construct(self, value: S) -> T {
self(value)
}
}
fn emit<C: Constructor<I, R>, I, R>(callback: &C, value: I) -> R {
callback.construct(value)
}
use self::Variants::*;
#[derive(Clone, Debug)]
enum Variants {
Unit,
One(u8),
}
fn main() {
let unit: Variants = emit(&Unit, ());
println!("{:?}", unit); // Should prints Unit.
let one: Variants = emit(&One, 10);
println!("{:?}", one); // Prints One(10).
}
but this fails at compile time with:
conflicting implementations of trait `Constructor<(), _>`:
From my understanding of the RFC, this fails because no one of these impls is a subset of the other. I think it is because the T in for T of the first impl is more generic than the F of the for F of the second implementation. Hence, it cannot be the specialization.
On the other hand, it cannot be the general (default) implementation because Constructor<(), T> for T (and even Constructor<S, T> for T) is more specific than Constructor<S, T> for F because T is written twice in the former.
This is my understanding from reading the RFC. Please tell me if I'm wrong.
How could I make the first example work without having to give a useless parameter to Unit?
I am open to solutions that require the nightly compiler.
What about implementing Fn for Variants? (Note: Fn requires FnMut and FnMut requires FnOnce, so we have to implement all three.)
#![feature(fn_traits)]
#![feature(unboxed_closures)]
use self::Variants::*;
#[derive(Clone, Debug)]
enum Variants {
Unit,
One(u8),
}
impl FnOnce<((),)> for Variants {
type Output = Variants;
extern "rust-call" fn call_once(self, args: ((),)) -> Self::Output {
self.call(args)
}
}
impl FnMut<((),)> for Variants {
extern "rust-call" fn call_mut(&mut self, args: ((),)) -> Self::Output {
self.call(args)
}
}
impl Fn<((),)> for Variants {
extern "rust-call" fn call(&self, _: ((),)) -> Self::Output {
self.clone()
}
}
fn emit<C: Fn(S) -> T, S, T>(callback: &C, value: S) -> T {
callback(value)
}
fn main() {
let unit: Variants = emit(&Unit, ());
println!("{:?}", unit); // Prints Unit.
let one: Variants = emit(&One, 10);
println!("{:?}", one); // Prints One(10).
}
The only weird aspect of this solution is that you could now pass values such as &One(10) as the first argument to emit (though the second argument could only be ()).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With