Skip to content

Instantly share code, notes, and snippets.

@japaric
Created December 17, 2014 06:38
Show Gist options
  • Save japaric/6659252624ec03ef3ff1 to your computer and use it in GitHub Desktop.
Save japaric/6659252624ec03ef3ff1 to your computer and use it in GitHub Desktop.
`Fn*` traits with associated types
#![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