Skip to content

Commit 01a4d44

Browse files
authored
Merge pull request #32 from alecmocatta/nameable
Nameable closures v0.2
2 parents 6130f4a + 83a1362 commit 01a4d44

File tree

6 files changed

+249
-37
lines changed

6 files changed

+249
-37
lines changed

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[package]
44
name = "serde_closure"
5-
version = "0.3.1"
5+
version = "0.3.2"
66
license = "MIT OR Apache-2.0"
77
authors = ["Alec Mocatta <[email protected]>"]
88
categories = ["development-tools","encoding","rust-patterns","network-programming"]
@@ -23,7 +23,7 @@ azure-devops = { project = "alecmocatta/serde_closure", pipeline = "tests", buil
2323
maintenance = { status = "actively-developed" }
2424

2525
[dependencies]
26-
serde_closure_derive = { version = "=0.3.1", path = "serde_closure_derive" }
26+
serde_closure_derive = { version = "=0.3.2", path = "serde_closure_derive" }
2727
serde = { version = "1.0", features = ["derive"] }
2828

2929
[build-dependencies]

azure-pipelines.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ jobs:
1313
parameters:
1414
endpoint: alecmocatta
1515
default:
16-
rust_toolchain: beta nightly
17-
rust_lint_toolchain: nightly-2020-07-12
16+
rust_toolchain: stable nightly
17+
rust_lint_toolchain: nightly-2020-07-27
1818
rust_flags: ''
1919
rust_features_clippy: ''
2020
rust_features: ''

serde_closure_derive/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "serde_closure_derive"
3-
version = "0.3.1"
3+
version = "0.3.2"
44
license = "MIT OR Apache-2.0"
55
authors = ["Alec Mocatta <[email protected]>"]
66
categories = ["development-tools","encoding","rust-patterns","network-programming"]
@@ -27,4 +27,4 @@ proc-macro = true
2727
[dependencies]
2828
proc-macro2 = { version = "1.0.1", default-features = false }
2929
quote = { version = "1.0.2", default-features = false }
30-
syn = { version = "1.0.5", default-features = false, features = ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"] }
30+
syn = { version = "1.0.38", default-features = false, features = ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"] }

serde_closure_derive/src/lib.rs

+57-18
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
//! See [`serde_closure`](https://docs.rs/serde_closure) for
1111
//! documentation.
1212
13-
#![doc(html_root_url = "https://docs.rs/serde_closure_derive/0.3.1")]
13+
#![doc(html_root_url = "https://docs.rs/serde_closure_derive/0.3.2")]
1414

1515
use proc_macro2::{Span, TokenStream};
1616
use quote::{quote, ToTokens};
1717
use std::{collections::HashSet, iter, iter::successors, mem::take, str};
1818
use syn::{
19-
parse2, parse_macro_input, visit_mut::{self, VisitMut}, Arm, AttributeArgs, Block, Error, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, FieldValue, Ident, Item, Lifetime, LifetimeDef, Local, Member, Pat, PatBox, PatIdent, PatReference, PatSlice, PatTuple, PatTupleStruct, PatType, Path, PathArguments, PathSegment, ReturnType, Stmt, TraitBound, Type, TypeInfer, TypeReference, TypeTuple, UnOp
19+
parse2, parse_macro_input, visit_mut::{self, VisitMut}, Arm, AttributeArgs, Block, Error, Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprField, ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, FieldValue, GenericParam, Ident, ImplItem, Item, ItemImpl, Lifetime, LifetimeDef, Local, Member, Pat, PatBox, PatIdent, PatReference, PatSlice, PatTuple, PatTupleStruct, PatType, Path, PathArguments, PathSegment, ReturnType, Stmt, TraitBound, Type, TypeInfer, TypeReference, TypeTuple, UnOp
2020
};
2121

2222
#[proc_macro]
@@ -60,14 +60,12 @@ pub fn desugar(
6060

6161
struct Desugar;
6262

63-
impl VisitMut for Desugar {
64-
fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) {
65-
let span = Span::call_site();
66-
if let PathSegment {
67-
arguments: PathArguments::Parenthesized(args),
68-
..
69-
} = i.path.segments.last().unwrap()
70-
{
63+
impl Desugar {
64+
fn desugar_path_arg(
65+
&mut self, arg: &mut PathArguments, return_output: bool,
66+
) -> (u64, Option<Type>) {
67+
if let PathArguments::Parenthesized(args) = &arg {
68+
let span = Span::call_site();
7169
let mut lifetimes = 0;
7270
let mut inputs = args.inputs.clone();
7371
for input in &mut inputs {
@@ -95,6 +93,25 @@ impl VisitMut for Desugar {
9593
elems: Default::default(),
9694
}),
9795
};
96+
*arg = PathArguments::AngleBracketed(if !return_output {
97+
syn::parse2(quote! { <(#inputs), Output = #output> }).unwrap()
98+
} else {
99+
syn::parse2(quote! { <(#inputs)> }).unwrap()
100+
});
101+
(lifetimes, if return_output { Some(output) } else { None })
102+
} else {
103+
(0, None)
104+
}
105+
}
106+
}
107+
108+
impl VisitMut for Desugar {
109+
fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) {
110+
let lifetimes = self
111+
.desugar_path_arg(&mut i.path.segments.last_mut().unwrap().arguments, false)
112+
.0;
113+
if lifetimes > 0 {
114+
let span = Span::call_site();
98115
let empty = syn::parse2(quote! {for <>}).unwrap();
99116
i.lifetimes = Some(i.lifetimes.clone().unwrap_or(empty));
100117
i.lifetimes
@@ -107,12 +124,35 @@ impl VisitMut for Desugar {
107124
span,
108125
))
109126
}));
110-
i.path.segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(
111-
syn::parse2(quote! { <(#inputs), Output = #output> }).unwrap(),
112-
);
113127
}
114128
visit_mut::visit_trait_bound_mut(self, i)
115129
}
130+
fn visit_item_impl_mut(&mut self, i: &mut ItemImpl) {
131+
if let Some((_, path, _)) = &mut i.trait_ {
132+
let (lifetimes, output) =
133+
self.desugar_path_arg(&mut path.segments.last_mut().unwrap().arguments, true);
134+
if lifetimes > 0 {
135+
let span = Span::call_site();
136+
i.generics.lt_token = Some(Default::default());
137+
i.generics.gt_token = Some(Default::default());
138+
i.generics.params.extend((0..lifetimes).map(|i| {
139+
GenericParam::Lifetime(LifetimeDef::new(Lifetime::new(
140+
&format!("'__serde_closure_{}", bijective_base(i, 26, alpha_lower)),
141+
span,
142+
)))
143+
}));
144+
}
145+
// Yuck
146+
if path.segments.last().unwrap().ident == "FnOnce" {
147+
if let Some(output) = output {
148+
i.items.push(ImplItem::Type(
149+
syn::parse2(quote! { type Output = #output; }).unwrap(),
150+
));
151+
}
152+
}
153+
}
154+
visit_mut::visit_item_impl_mut(self, i)
155+
}
116156
}
117157

118158
#[derive(Copy, Clone, PartialEq, Eq)]
@@ -257,6 +297,7 @@ fn impl_closure(mut closure: ExprClosure, kind: Kind) -> Result<TokenStream, Err
257297
F: ops::FnOnce(&#name<#(#type_params,)* ()>,I) -> O
258298
{
259299
type Output = O;
300+
260301
#[inline(always)]
261302
fn call_once(self, args: I) -> Self::Output {
262303
self.f()(&self.strip_f(), args)
@@ -287,6 +328,7 @@ fn impl_closure(mut closure: ExprClosure, kind: Kind) -> Result<TokenStream, Err
287328
F: ops::FnOnce(&mut #name<#(#type_params,)* ()>,I) -> O
288329
{
289330
type Output = O;
331+
290332
#[inline(always)]
291333
fn call_once(mut self, args: I) -> Self::Output {
292334
self.f()(&mut self.strip_f(), args)
@@ -308,6 +350,7 @@ fn impl_closure(mut closure: ExprClosure, kind: Kind) -> Result<TokenStream, Err
308350
F: ops::FnOnce(#name<#(#type_params,)* ()>,I) -> O
309351
{
310352
type Output = O;
353+
311354
#[inline(always)]
312355
fn call_once(self, args: I) -> Self::Output {
313356
self.f()(self.strip_f(), args)
@@ -787,11 +830,7 @@ impl<'a> State<'a> {
787830
{
788831
let path_segment = &path.segments.first().unwrap();
789832
let ident = &path_segment.ident;
790-
let has_path_arguments = if let PathArguments::None = path_segment.arguments {
791-
false
792-
} else {
793-
true
794-
};
833+
let has_path_arguments = !matches!(path_segment.arguments, PathArguments::None);
795834
if !self.variables.contains(ident) {
796835
// Assume it's a variable, unless:
797836
// * It starts with an upper-case letter, e.g. `Some`, OR

0 commit comments

Comments
 (0)