Created
December 17, 2014 06:38
-
-
Save japaric/6659252624ec03ef3ff1 to your computer and use it in GitHub Desktop.
`Fn*` traits with associated types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![crate_type = "lib"] | |
#![feature(associated_types)] | |
#![no_implicit_prelude] | |
use std::boxed::Box; | |
trait Fn { | |
type Args; | |
type Result; | |
extern "rust-call" fn call(&self, <Self as Fn>::Args) -> <Self as Fn>::Result; | |
} | |
impl<'a, F, A, R> Fn for &'a F where F: Fn<Args=A, Result=R> { | |
type Args = A; | |
type Result = R; | |
#[inline(always)] | |
extern "rust-call" fn call(&self, args: A) -> R { | |
Fn::call(*self, args) | |
} | |
} | |
// This should be automatically derived by the compiler | |
// XXX I have no idea why this collides with the Fn hierarchy | |
impl<'a, 'b, A, R> Fn for &'a (Fn<Args=A, Result=R> + 'b) { | |
type Args = A; | |
type Result = R; | |
extern "rust-call" fn call(&self, args: A) -> R { | |
(*self).call(args) | |
} | |
} | |
trait FnMut { | |
type Args; | |
type Result; | |
extern "rust-call" fn call_mut(&mut self, <Self as FnMut>::Args) -> <Self as FnMut>::Result; | |
} | |
impl<'a, F, A, R> FnMut for &'a mut F where | |
F: FnMut<Args=A, Result=R>, | |
//Self: !Fn, // XXX I think this is required to avoid a collision with the Fn hierarchy | |
{ | |
type Args = A; | |
type Result = R; | |
#[inline(always)] | |
extern "rust-call" fn call_mut(&mut self, args: A) -> R { | |
FnMut::call_mut(*self, args) | |
} | |
} | |
// This should be automatically derived by the compiler | |
// XXX I have no idea why this collides with the Fn hierarchy | |
impl<'a, 'b, A, R> FnMut for &'a mut (FnMut<Args=A, Result=R> + 'b) { | |
type Args = A; | |
type Result = R; | |
extern "rust-call" fn call_mut(&mut self, args: A) -> R { | |
(*self).call_mut(args) | |
} | |
} | |
trait FnOnce { | |
type Args; | |
type Result; | |
extern "rust-call" fn call_once(self, <Self as FnOnce>::Args) -> <Self as FnOnce>::Result; | |
} | |
trait FnBox { | |
type Args; | |
type Result; | |
extern "rust-call" fn call_box(self: Box<Self>, <Self as FnBox>::Args) -> <Self as FnBox>::Result; | |
} | |
impl<F, A, R> FnBox for F where F: FnOnce<Args=A, Result=R> { | |
type Args = A; | |
type Result = R; | |
extern "rust-call" fn call_box(self: Box<F>, args: A) -> R { | |
(*self).call_once(args) | |
} | |
} | |
// `Box<FnOnce>` is not object safe, instead we use `Box<FnBox>`. And `Box<FnBox>` should implement | |
// `FnOnce` | |
// XXX I have no idea why this collides with the Fn hierarchy | |
impl<'a, A, R> FnOnce for Box<FnBox<Args=A, Result=R> + 'a> { | |
type Args = A; | |
type Result = R; | |
extern "rust-call" fn call_once(self, args: A) -> R { | |
self.call_box(args) | |
} | |
} | |
// Fn Hierarchy | |
impl<F, A, R> FnMut for F where F: Fn<Args=A, Result=R> { | |
type Args = A; | |
type Result = R; | |
extern "rust-call" fn call_mut(&mut self, args: A) -> R { | |
self.call(args) | |
} | |
} | |
impl<F, A, R> FnOnce for F where F: FnMut<Args=A, Result=R> { | |
type Args = A; | |
type Result = R; | |
extern "rust-call" fn call_once(mut self, args: A) -> R { | |
self.call_mut(args) | |
} | |
} | |
// "Tests" | |
fn is_fn<F, A, R>(_: F) where F: Fn<Args=A, Result=R> {} | |
fn is_fn_mut<F, A, R>(_: F) where F: FnMut<Args=A, Result=R> {} | |
fn is_fn_once<F, A, R>(_: F) where F: FnOnce<Args=A, Result=R> {} | |
fn fn_implementor_is_fn_mut<F, A, R>(f: F) where F: Fn<Args=A, Result=R> { | |
is_fn_mut(f) | |
} | |
fn fn_implementor_is_fn_once<F, A, R>(f: F) where F: Fn<Args=A, Result=R> { | |
is_fn_once(f) | |
} | |
fn fn_mut_implementor_is_fn_once<F, A, R>(f: F) where F: FnMut<Args=A, Result=R> { | |
is_fn_once(f) | |
} | |
fn ref_fn_trait_object_is_fn<A, R>(f: &Fn<Args=A, Result=R>) { | |
is_fn(f) | |
} | |
fn mut_ref_fn_mut_trait_object_is_fn_mut<A, R>(f: &mut FnMut<Args=A, Result=R>) { | |
is_fn_mut(f) | |
} | |
fn boxed_fn_box_trait_object_is_fn_once<'a, A, R>(f: Box<FnBox<Args=A, Result=R> + 'a>) { | |
is_fn_once(f) | |
} | |
fn ref_to_fn_implementor_is_fn<F, A, R>(f: F) where F: Fn<Args=A, Result=R> { | |
is_fn(&f) | |
} | |
fn mut_ref_to_fn_mut_implementor_is_fn_mut<F, A, R>(mut f: F) where F: FnMut<Args=A, Result=R> { | |
is_fn_mut(&mut f) | |
} | |
fn box_fn_box_is_fn_once<A, R>(f: Box<FnBox<Args=A, Result=R>>) { | |
is_fn_once(f) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment