Skip to content

Instantly share code, notes, and snippets.

@oscartbeaumont
Created January 4, 2023 13:10
Show Gist options
  • Save oscartbeaumont/f6e7281cfb1257be2d9d7166bc5cf1cd to your computer and use it in GitHub Desktop.
Save oscartbeaumont/f6e7281cfb1257be2d9d7166bc5cf1cd to your computer and use it in GitHub Desktop.
pub trait Function {}
pub trait Function<TMarker> {
type Args;
type Result;
fn exec(&self, args: Self::Args) -> Self::Result;
}
// TODO: Duplicate all the impls for `FnOnce` and `FnMut`
// TODO: Support up to 12 args per functions.
pub enum TMarker {}
impl<R, TFunc: Fn() -> R> Function<TMarker> for TFunc {
type Args = ();
type Result = R;
fn exec(&self, _: Self::Args) -> Self::Result {
(self)()
}
}
impl<T, R, TFunc: Fn(T) -> R> Function<(T, R)> for TFunc {
type Args = T;
type Result = R;
fn exec(&self, args: Self::Args) -> Self::Result {
(self)(args)
}
}
impl<T, T1, R, TFunc: Fn(T, T1) -> R> Function<(T, T1, R)> for TFunc {
type Args = (T, T1);
type Result = R;
fn exec(&self, args: Self::Args) -> Self::Result {
(self)(args.0, args.1)
}
}
impl<T, T1, T2, R, TFunc: Fn(T, T1, T2) -> R> Function<(T, T1, T2, R)> for TFunc {
type Args = (T, T1, T2);
type Result = R;
fn exec(&self, args: Self::Args) -> Self::Result {
(self)(args.0, args.1, args.2)
}
}
fn joiner<A, TMarker1, B, TMarker2>(
a: A,
b: B,
) -> impl Function<
(
<A as Function<TMarker1>>::Args,
<B as Function<TMarker2>>::Result,
),
Args = <A as Function<TMarker1>>::Args,
Result = <B as Function<TMarker2>>::Result,
>
where
A: Function<TMarker1>,
B: Function<TMarker2, Args = A::Result>,
{
move |args: A::Args| b.exec(a.exec(args))
}
fn from_into_string(s: impl Into<String>) -> i32 {
s.into().parse::<i32>().unwrap()
}
pub trait SpecialType {}
#[derive(Clone)]
pub struct Demo;
impl SpecialType for Demo {}
fn only_special_types(_s: impl SpecialType) -> &'static str {
"my precious"
}
fn main() {
let a = |a: i32| a.to_string();
let b = |a: String| a.parse::<i32>().unwrap();
// i32 to String -> String to i32
let c = joiner(a, b);
println!("{}", c.exec(42));
// i32 to String -> `impl Into<String>` to i32
let c = joiner(a, from_into_string);
println!("{}", c.exec(42));
let a = Demo {}; // Will compile
// let a = "this is not the special type"; // Will not compile because it doesn't satisfy the trait bound on `only_special_types`
let c = joiner(move || a.clone(), only_special_types);
println!("{}", c.exec(()));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment