Skip to content

Commit b19fe80

Browse files
committed
Version 0.1.0
1 parent 42e1b55 commit b19fe80

5 files changed

Lines changed: 219 additions & 52 deletions

File tree

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Rust
1+
name: Rust-CI
22

33
on:
44
push:

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "const_closure"
3-
version = "0.0.1"
3+
version = "0.1.0"
44
edition = "2021"
55
license = "MIT OR Apache-2.0"
66
authors = [

README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Const Closure
2+
3+
[![Rust-CI](https://github.com/chriss0612/const_closure/actions/workflows/rust.yml/badge.svg)](https://github.com/chriss0612/const_closure/actions/workflows/rust.yml)
4+
[![docs.rs](https://docs.rs/const_closure/badge.svg)](https://docs.rs/const_closure)
5+
[![crates.io](https://img.shields.io/crates/v/const_closure.svg)](https://crates.io/crates/const_closure)
6+
[![rustc](https://img.shields.io/badge/rustc-nightly-lightgrey)](https://doc.rust-lang.org/nightly/std/)
7+
8+
<!-- The rest of this section comes straight from the crate docs from the source. -->
9+
10+
This crate allows using macros to automatically create closure like types/values.
11+
12+
This works by implementing the Fn* traits for a struct containing all the values captured form the environment.
13+
14+
Because of restrictions of declarative macros the used syntax is less than ideal, but it is a lot better than manual implementations of the Fn* traits.
15+
16+
For details of the Syntax see: `const_closure`.
17+
18+
## Requirements
19+
20+
This crate requires a nightly compiler.
21+
22+
## Example
23+
```rust
24+
#![feature(unboxed_closures)]
25+
#![feature(fn_traits)]
26+
#![feature(const_trait_impl)]
27+
#![feature(const_mut_refs)]
28+
#![feature(const_refs_to_cell)]
29+
#![feature(const_ops)]
30+
use const_closure::const_closure;
31+
32+
const FROM_CLOSURE: i32 = {
33+
let base = 5;
34+
let calc = const_closure!([base: i32] (offset: i32) -> i32 {
35+
base + offset
36+
});
37+
calc(-2)
38+
};
39+
assert_eq!(FROM_CLOSURE, 3)
40+
```
41+
42+
Authors
43+
-------
44+
45+
[raldone01](https://github.com/raldone01) and [onestacked](https://github.com/chriss0612) are the primary authors and maintainers of this library.
46+
47+
License
48+
-------
49+
50+
This project is released under either:
51+
52+
- [MIT License](https://github.com/raldone01/trait_cast_rs/blob/main/LICENSE-MIT)
53+
- [Apache License (Version 2.0)](https://github.com/raldone01/trait_cast_rs/blob/main/LICENSE-APACHE)
54+
55+
at your choosing.
56+
57+
### Contribution
58+
59+
Unless you explicitly state otherwise, any contribution intentionally
60+
submitted for inclusion in the work by you, as defined in the Apache-2.0
61+
license, shall be dual licensed as above, without any additional terms or
62+
conditions.

src/lib.rs

Lines changed: 125 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,146 @@
11
#![no_std]
2+
#![warn(clippy::pedantic, clippy::nursery)]
3+
#![deny(missing_docs)]
4+
#![deny(unsafe_code)]
25
#![feature(unboxed_closures)]
36
#![feature(fn_traits)]
47
#![feature(const_trait_impl)]
58
#![feature(const_mut_refs)]
69
#![feature(const_refs_to_cell)]
10+
#![feature(const_ptr_read)]
11+
#![feature(const_option)]
712

13+
/*!
14+
# Const Closure
15+
This crate allows using macros to automatically create closure like types/values.
16+
17+
This works by implementing the Fn* traits for a struct containing all the values captured form the environment.
18+
19+
Because of restrictions of declarative macros the used syntax is less than ideal, but it is a lot better than manual implementations of the Fn* traits.
20+
21+
For details of the Syntax see: `const_closure`.
22+
23+
# Example
24+
```rust
25+
#![feature(unboxed_closures)]
26+
#![feature(fn_traits)]
27+
#![feature(const_trait_impl)]
28+
#![feature(const_mut_refs)]
29+
#![feature(const_refs_to_cell)]
30+
#![feature(const_ops)]
31+
use const_closure::const_closure;
32+
33+
const FROM_CLOSURE: i32 = {
34+
let base = 5;
35+
let calc = const_closure!([base: i32] (offset: i32) -> i32 {
36+
base + offset
37+
});
38+
calc(-2)
39+
};
40+
assert_eq!(FROM_CLOSURE, 3)
41+
```
42+
!*/
43+
44+
/// # Macro for creating const callable "closures"
45+
///
46+
/// The syntax is the following:
47+
///
48+
/// const_closure!(`fn_type` for<`generics`> [`captures`] (`args`) -> `return_type` {`closure_body`})
49+
///
50+
/// where:
51+
/// * `fn_type` is one of the Fn* traits (Fn, FnMut, FnOnce).
52+
/// * `generics` generics and bounds for them.
53+
/// * `captures` the list of arguments that the closure captures with function argument like typing.
54+
/// * `return_type` the return type of the closure.
55+
/// * `closure_body` the actual implementation of the closure.
56+
///
57+
/// if `fn_type` is omitted it defaults to Fn.
58+
///
59+
/// if no `generics` are required, the for<> can be omitted.
60+
///
61+
/// if no `captures` are required, the [] can be omitted.
62+
///
63+
/// if `return_type` is (), -> () can be omitted.
64+
///
65+
/// #Advanced example:
66+
/// ```
67+
/// #![feature(unboxed_closures)]
68+
/// #![feature(fn_traits)]
69+
/// #![feature(const_trait_impl)]
70+
/// #![feature(const_mut_refs)]
71+
/// #![feature(const_refs_to_cell)]
72+
/// use const_closure::const_closure;
73+
/// use core::ops::Add;
74+
///
75+
/// const fn add<T, G: Add<T, Output = G>>(l: G, r: T) -> G {
76+
/// let cl = const_closure!(FnOnce for<T, G: Add<T, Output = G>> [l: G, r: T] () -> G {
77+
/// l + r
78+
/// });
79+
/// cl()
80+
/// }
81+
/// assert_eq!(add(1, 5), 6);
82+
/// ```
83+
#[cfg(doc)]
84+
#[macro_export]
85+
macro_rules! const_closure {
86+
($($type:ident)? $(for<$($gen_name:ident $(: $($trait_bound:path)*)?),*>)? $this:ident $([$($cap_name:ident : $cap_ty:ty ),+ $(,)?])? ($($arg_name:ident: $arg_ty:ty),*) $(-> $ret_ty:ty)? {$($body:tt)*}) => { ... };
87+
}
88+
89+
#[cfg(not(doc))]
890
#[macro_export]
91+
#[allow(missing_docs)]
992
macro_rules! const_closure {
1093
// Syntax sugar
1194
(for $($end:tt)*) => {{
1295
const_closure!(Fn for$($end)*)
1396
}};
14-
($this:ident [$($mid:tt)*] $($end:tt)*) => {{
15-
const_closure!(Fn for<> $this [$($mid)*] $($end)*)
97+
([$($mid:tt)*] $($end:tt)*) => {{
98+
const_closure!(Fn for<> [$($mid)*] $($end)*)
1699
}};
17-
($this:ident ($($mid:tt)*) $($end:tt)*) => {{
18-
const_closure!(Fn for<> $this ($($mid)*) $($end)*)
100+
(($($mid:tt)*) $($end:tt)*) => {{
101+
const_closure!(Fn for<> ($($mid)*) $($end)*)
19102
}};
20-
($type:ident $this:ident [$($mid:tt)*] $($end:tt)*) => {{
21-
const_closure!($type for<> $this [$($mid)*] $($end)*)
103+
($type:ident [$($mid:tt)*] $($end:tt)*) => {{
104+
const_closure!($type for<> [$($mid)*] $($end)*)
22105
}};
23-
($type:ident for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> $this:ident ($($mid:tt)*) $($end:tt)*) => {{
24-
const_closure!($type for<$($gen_name $(: $($trait_bound)*)?),*> $this [] ($($mid)*) $($end)*)
106+
($type:ident for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> ($($mid:tt)*) $($end:tt)*) => {{
107+
const_closure!($type for<$($gen_name $(: $($trait_bound)*)?),*> [] ($($mid)*) $($end)*)
25108
}};
26-
($type:ident for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> $this:ident [$($cap_name:ident : $cap_ty:ty ),* $(,)?] ($($arg_name:ident: $arg_ty:ty),*) {$($body:tt)*}) => {{
27-
const_closure!($type for<$($gen_name $(: $($trait_bound)*)?),*> $this [$($cap_name : $cap_ty ),*] ($($arg_name: $arg_ty),*) -> () {$($body)*})
109+
($type:ident for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> [$($cap_name:ident : $cap_ty:ty ),* $(,)?] ($($arg_name:ident: $arg_ty:ty),*) {$($body:tt)*}) => {{
110+
const_closure!($type for<$($gen_name $(: $($trait_bound)*)?),*> [$($cap_name : $cap_ty ),*] ($($arg_name: $arg_ty),*) -> () {$($body)*})
28111
}};
29112
// Actual Implementation
30-
(FnOnce for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> $this:ident [$($cap_name:ident : $cap_ty:ty ),+ $(,)?] ($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty {$($body:tt)*}) => {{
113+
(FnOnce for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> [$($cap_name:ident : $cap_ty:ty ),+ $(,)?] ($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty {$($body:tt)*}) => {{
31114
#[allow(non_snake_case)]
32-
struct Cl<$($gen_name $(: $($trait_bound)*)?),*> {
33-
$($gen_name: ::core::marker::PhantomData<*const $gen_name>),*
115+
struct Cl<$($gen_name $(: $($trait_bound)*)?),*>{
116+
$($gen_name: ::core::marker::PhantomData<*const $gen_name>,)*
34117
$($cap_name: $cap_ty),*
35118
}
36-
impl<$($gen_name $(: $(~const $trait_bound + )+ ~const ::core::marker::Destruct)?),*> const FnOnce<($($arg_ty,)*)> for Cl<$($gen_name),*> {
119+
impl<$($gen_name $(: $(~const $trait_bound + )+ ~const ::core::marker::Destruct)?),*> const FnOnce<($($arg_ty,)*)> for Cl<$($gen_name),*>
120+
where Self: ~const ::core::marker::Destruct {
37121
type Output = $ret_ty;
38122

39123
#[allow(unused_parens)]
40124
extern "rust-call" fn call_once(self, ($($arg_name,)*): ($($arg_ty,)*)) -> Self::Output {
41-
#[allow(unused_mut)]
42-
#[allow(unused_variables)]
43-
let mut $this = self;
125+
$(
126+
#[allow(unused_mut)]
127+
#[allow(unused_variables)]
128+
let mut $cap_name = self.$cap_name;
129+
)*
44130
$($body)*
45131
}
46132
}
47133
Cl {
48-
$($gen_name: ::core::marker::PhantomData),*
49-
$($cap_name: $cap_name),*
134+
$($gen_name: ::core::marker::PhantomData,)*
135+
$($cap_name),*
50136
}
51137
}};
52-
(FnMut for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> $this:ident [$($cap_name:ident : $cap_ty:ty),* $(,)?] ($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty {$($body:tt)*}) => {{
138+
(FnMut for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> [$($cap_name:ident : $cap_ty:ty),* $(,)?] ($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty {$($body:tt)*}) => {{
53139
#[allow(non_snake_case)]
54140
struct Cl<'a, $($gen_name $(: $($trait_bound)*)?),*> {
55141
_lt: ::core::marker::PhantomData<&'a mut u8>,
56-
$($gen_name: ::core::marker::PhantomData<*const $gen_name>),*
57-
$($cap_name: &'a mut $cap_ty),*
142+
$($gen_name: ::core::marker::PhantomData<*const $gen_name>,)*
143+
$($cap_name: Option<&'a mut $cap_ty>,)*
58144
}
59145
impl<'a, $($gen_name $(: $(~const $trait_bound + )+ ~const ::core::marker::Destruct)?),*> const FnOnce<($($arg_ty,)*)> for Cl<'a, $($gen_name),*> {
60146
type Output = $ret_ty;
@@ -64,27 +150,30 @@ macro_rules! const_closure {
64150
self.call_mut(args)
65151
}
66152
}
153+
67154
impl<'a, $($gen_name $(: $(~const $trait_bound + )+ ~const ::core::marker::Destruct)?),*> const FnMut<($($arg_ty,)*)> for Cl<'a, $($gen_name),*> {
68155

69156
#[allow(unused_parens)]
70157
extern "rust-call" fn call_mut(&mut self, ($($arg_name,)*): ($($arg_ty,)*)) -> Self::Output {
71-
#[allow(unused_variables)]
72-
let $this = self;
73-
$($body)*
158+
// Hack to extract the references from Self
159+
$(let $cap_name = self.$cap_name.take().unwrap();)*
160+
let ret = { $($body)* };
161+
$(self.$cap_name = Some($cap_name);)*
162+
ret
74163
}
75164
}
76165
Cl {
77166
_lt: ::core::marker::PhantomData,
78-
$($gen_name: ::core::marker::PhantomData),*
79-
$($cap_name: &mut $cap_name),*
167+
$($gen_name: ::core::marker::PhantomData,)*
168+
$($cap_name: Some(&mut $cap_name),)*
80169
}
81170
}};
82-
(Fn for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> $this:ident [$($cap_name:ident : $cap_ty:ty ),* $(,)?] ($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty {$($body:tt)*}) => {{
171+
(Fn for<$($gen_name:ident $(: $($trait_bound:path)*)?),*> [$($cap_name:ident : $cap_ty:ty ),* $(,)?] ($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty {$($body:tt)*}) => {{
83172
#[allow(non_snake_case)]
84173
struct Cl<'a, $($gen_name $(: $($trait_bound)*)?),*> {
85174
_lt: ::core::marker::PhantomData<&'a u8>,
86-
$($gen_name: ::core::marker::PhantomData<*const $gen_name>),*
87-
$($cap_name: &'a $cap_ty),*
175+
$($gen_name: ::core::marker::PhantomData<*const $gen_name>,)*
176+
$($cap_name: &'a $cap_ty,)*
88177
}
89178
impl<'a, $($gen_name $(: $(~const $trait_bound + )+ ~const ::core::marker::Destruct)?),*> const FnOnce<($($arg_ty,)*)> for Cl<'a, $($gen_name),*> {
90179
type Output = $ret_ty;
@@ -102,15 +191,17 @@ macro_rules! const_closure {
102191

103192
#[allow(unused_parens)]
104193
extern "rust-call" fn call(&self, ($($arg_name,)*): ($($arg_ty,)*)) -> Self::Output {
105-
#[allow(unused_variables)]
106-
let $this = self;
194+
$(
195+
#[allow(unused_variables)]
196+
let $cap_name = self.$cap_name;
197+
)*
107198
$($body)*
108199
}
109200
}
110201
Cl {
111202
_lt: ::core::marker::PhantomData,
112-
$($gen_name: ::core::marker::PhantomData),*
113-
$($cap_name: &mut $cap_name),*
203+
$($gen_name: ::core::marker::PhantomData,)*
204+
$($cap_name: &$cap_name,)*
114205
}
115206
}};
116207
}

0 commit comments

Comments
 (0)