Skip to content

Commit

Permalink
capt
Browse files Browse the repository at this point in the history
  • Loading branch information
2A5F committed Apr 18, 2023
1 parent f46b6ff commit 69a4aa5
Show file tree
Hide file tree
Showing 8 changed files with 759 additions and 4 deletions.
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"rust-analyzer.linkedProjects": [
".\\tuples\\Cargo.toml",
".\\tuples\\Cargo.toml",
".\\tuples\\Cargo.toml"
],
"rust-analyzer.showUnlinkedFileNotification": false
}
45 changes: 45 additions & 0 deletions code_gen/src/code_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn code_gen(out_dir: &Path) {
gen_cloned(&ctx, &out_dir);
gen_call(&ctx, &out_dir);
gen_apply_tuple(&ctx, &out_dir);
gen_capt(&ctx, &out_dir);
}

#[allow(dead_code)]
Expand Down Expand Up @@ -1275,6 +1276,15 @@ fn gen_apply_tuple_size(ctx: &Ctx, size: usize) -> TokenStream {
type DynFnOnce = dyn FnOnce(#(#nts),*) -> R;
type DynFnMut = dyn FnMut(#(#nts),*) -> R;
type DynFn = dyn Fn(#(#nts),*) -> R;
type FnPtr = fn(#(#nts),*) -> R;
}

impl<F: FnOnce(#(#nts),*) -> R, R, #(#nts),*> ApplyTupleMeta<(#(#nts,)*)> for F {
type Output = R;
type DynFnOnce = dyn FnOnce(#(#nts),*) -> R;
type DynFnMut = dyn FnMut(#(#nts),*) -> R;
type DynFn = dyn Fn(#(#nts),*) -> R;
type FnPtr = fn(#(#nts),*) -> R;
}

impl<F: FnOnce(#(#nts),*) -> R, R, #(#nts),*> ApplyTupleOnce<(#(#nts,)*)> for F {
Expand All @@ -1299,3 +1309,38 @@ fn gen_apply_tuple_size(ctx: &Ctx, size: usize) -> TokenStream {
};
tks
}

fn gen_capt(ctx: &Ctx, out_dir: &Path) {
let items = (1..33usize).map(|i| gen_capt_size(ctx, i));
let tks = quote! { #(#items)* };
let mut code = tks.to_string();
code.insert_str(0, "// This file is by code gen, do not modify\n\n");
let dest_path = Path::new(out_dir).join("capt.rs");
fs::write(&dest_path, code).unwrap();
}

fn gen_capt_size(ctx: &Ctx, size: usize) -> TokenStream {
let nts = &ctx.nts[0..size];
let nvs = &ctx.nvs[0..size];
let name = format_ident!("capt_{}", size);
let name_mut = format_ident!("capt_mut_{}", size);
let name_once = format_ident!("capt_once_{}", size);
let tks = quote! {
#[doc = "Manually capture the variables required by the closure"]
pub fn #name<C, #(#nts),*, R, F: Fn(&C, #(#nts),*) -> R>(c: C, f: F) -> impl Fn(#(#nts),*) -> R {
move |#(#nvs,)*| f(&c, #(#nvs,)*)
}

#[doc = "Manually capture the variables required by the closure"]
pub fn #name_mut<C, #(#nts),*, R, F: FnMut(&mut C, #(#nts),*) -> R>(mut c: C, mut f: F) -> impl FnMut(#(#nts),*) -> R {
move |#(#nvs,)*| f(&mut c, #(#nvs,)*)
}

#[doc = "Manually capture the variables required by the closure"]
pub fn #name_once<C, #(#nts),*, R, F: FnOnce(C, #(#nts),*) -> R>(c: C, f: F) -> impl FnOnce(#(#nts),*) -> R {
move |#(#nvs,)*| f(c, #(#nvs,)*)
}

};
tks
}
4 changes: 3 additions & 1 deletion tuples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
name = "tuples"
readme = "../README.md"
repository = "https://github.com/libsugar/tuplers"
version = "1.11.0"
version = "1.12.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -32,6 +32,7 @@ default = [
"cloned",
"tuple_call",
"re-exports",
"capt",
]
flatten = []
re-exports = []
Expand All @@ -48,3 +49,4 @@ tuple_call = []
tuple_iter = []
tuple_map = []
tuple_meta = []
capt = []
10 changes: 10 additions & 0 deletions tuples/src/apply_tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ pub trait TupleFnMeta<R> {
type DynFnOnce: ?Sized;
type DynFnMut: ?Sized;
type DynFn: ?Sized;
type FnPtr;
}

/// Apply tuple meta
pub trait ApplyTupleMeta<Tuple> {
type Output;
type DynFnOnce: ?Sized;
type DynFnMut: ?Sized;
type DynFn: ?Sized;
type FnPtr;
}

/// Apply tuple as args to FnOnce
Expand Down
41 changes: 38 additions & 3 deletions tuples/src/capt.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
//! Manually capture the variables required by the closure
/// Manually capture the variables required by the closure
pub fn capt0<T, R, F: Fn(&T) -> R>(v: T, f: F) -> impl Fn() -> R {
pub fn capt_0<T, R, F: Fn(&T) -> R>(v: T, f: F) -> impl Fn() -> R {
move || f(&v)
}

/// Manually capture the variables required by the closure
pub fn capt1<T, A, R, F: Fn(&T, A) -> R>(v: T, f: F) -> impl Fn(A) -> R {
move |a| f(&v, a)
pub fn capt_mut_0<T, R, F: FnMut(&mut T) -> R>(mut v: T, mut f: F) -> impl FnMut() -> R {
move || f(&mut v)
}

/// Manually capture the variables required by the closure
pub fn capt_once_0<T, R, F: FnOnce(T) -> R>(v: T, f: F) -> impl FnOnce() -> R {
move || f(v)
}

include!("./gen/capt.rs");

#[test]
fn test1() {
let a = capt_0(1, |a| *a);
let r = a();
assert_eq!(r, 1);
}

#[test]
fn test2() {
let a = capt_1(2, |a, b| *a * b);
let r = a(3);
assert_eq!(r, 6);
}

#[test]
fn test3() {
let mut a = capt_mut_1(2, |a, b| {
*a *= b;
*a
});
let r = a(3);
assert_eq!(r, 6);
let r = a(3);
assert_eq!(r, 18);
}
Loading

0 comments on commit 69a4aa5

Please sign in to comment.