Skip to content

Commit

Permalink
Merge pull request #32 from alecmocatta/nameable
Browse files Browse the repository at this point in the history
Nameable closures v0.2
  • Loading branch information
mergify[bot] authored Aug 5, 2020
2 parents 6130f4a + 83a1362 commit 01a4d44
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 37 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[package]
name = "serde_closure"
version = "0.3.1"
version = "0.3.2"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <alec@mocatta.net>"]
categories = ["development-tools","encoding","rust-patterns","network-programming"]
Expand All @@ -23,7 +23,7 @@ azure-devops = { project = "alecmocatta/serde_closure", pipeline = "tests", buil
maintenance = { status = "actively-developed" }

[dependencies]
serde_closure_derive = { version = "=0.3.1", path = "serde_closure_derive" }
serde_closure_derive = { version = "=0.3.2", path = "serde_closure_derive" }
serde = { version = "1.0", features = ["derive"] }

[build-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ jobs:
parameters:
endpoint: alecmocatta
default:
rust_toolchain: beta nightly
rust_lint_toolchain: nightly-2020-07-12
rust_toolchain: stable nightly
rust_lint_toolchain: nightly-2020-07-27
rust_flags: ''
rust_features_clippy: ''
rust_features: ''
Expand Down
4 changes: 2 additions & 2 deletions serde_closure_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "serde_closure_derive"
version = "0.3.1"
version = "0.3.2"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <alec@mocatta.net>"]
categories = ["development-tools","encoding","rust-patterns","network-programming"]
Expand All @@ -27,4 +27,4 @@ proc-macro = true
[dependencies]
proc-macro2 = { version = "1.0.1", default-features = false }
quote = { version = "1.0.2", default-features = false }
syn = { version = "1.0.5", default-features = false, features = ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"] }
syn = { version = "1.0.38", default-features = false, features = ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"] }
75 changes: 57 additions & 18 deletions serde_closure_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
//! See [`serde_closure`](https://docs.rs/serde_closure) for
//! documentation.

#![doc(html_root_url = "https://docs.rs/serde_closure_derive/0.3.1")]
#![doc(html_root_url = "https://docs.rs/serde_closure_derive/0.3.2")]

use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use std::{collections::HashSet, iter, iter::successors, mem::take, str};
use syn::{
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
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
};

#[proc_macro]
Expand Down Expand Up @@ -60,14 +60,12 @@ pub fn desugar(

struct Desugar;

impl VisitMut for Desugar {
fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) {
let span = Span::call_site();
if let PathSegment {
arguments: PathArguments::Parenthesized(args),
..
} = i.path.segments.last().unwrap()
{
impl Desugar {
fn desugar_path_arg(
&mut self, arg: &mut PathArguments, return_output: bool,
) -> (u64, Option<Type>) {
if let PathArguments::Parenthesized(args) = &arg {
let span = Span::call_site();
let mut lifetimes = 0;
let mut inputs = args.inputs.clone();
for input in &mut inputs {
Expand Down Expand Up @@ -95,6 +93,25 @@ impl VisitMut for Desugar {
elems: Default::default(),
}),
};
*arg = PathArguments::AngleBracketed(if !return_output {
syn::parse2(quote! { <(#inputs), Output = #output> }).unwrap()
} else {
syn::parse2(quote! { <(#inputs)> }).unwrap()
});
(lifetimes, if return_output { Some(output) } else { None })
} else {
(0, None)
}
}
}

impl VisitMut for Desugar {
fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) {
let lifetimes = self
.desugar_path_arg(&mut i.path.segments.last_mut().unwrap().arguments, false)
.0;
if lifetimes > 0 {
let span = Span::call_site();
let empty = syn::parse2(quote! {for <>}).unwrap();
i.lifetimes = Some(i.lifetimes.clone().unwrap_or(empty));
i.lifetimes
Expand All @@ -107,12 +124,35 @@ impl VisitMut for Desugar {
span,
))
}));
i.path.segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(
syn::parse2(quote! { <(#inputs), Output = #output> }).unwrap(),
);
}
visit_mut::visit_trait_bound_mut(self, i)
}
fn visit_item_impl_mut(&mut self, i: &mut ItemImpl) {
if let Some((_, path, _)) = &mut i.trait_ {
let (lifetimes, output) =
self.desugar_path_arg(&mut path.segments.last_mut().unwrap().arguments, true);
if lifetimes > 0 {
let span = Span::call_site();
i.generics.lt_token = Some(Default::default());
i.generics.gt_token = Some(Default::default());
i.generics.params.extend((0..lifetimes).map(|i| {
GenericParam::Lifetime(LifetimeDef::new(Lifetime::new(
&format!("'__serde_closure_{}", bijective_base(i, 26, alpha_lower)),
span,
)))
}));
}
// Yuck
if path.segments.last().unwrap().ident == "FnOnce" {
if let Some(output) = output {
i.items.push(ImplItem::Type(
syn::parse2(quote! { type Output = #output; }).unwrap(),
));
}
}
}
visit_mut::visit_item_impl_mut(self, i)
}
}

#[derive(Copy, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -257,6 +297,7 @@ fn impl_closure(mut closure: ExprClosure, kind: Kind) -> Result<TokenStream, Err
F: ops::FnOnce(&#name<#(#type_params,)* ()>,I) -> O
{
type Output = O;

#[inline(always)]
fn call_once(self, args: I) -> Self::Output {
self.f()(&self.strip_f(), args)
Expand Down Expand Up @@ -287,6 +328,7 @@ fn impl_closure(mut closure: ExprClosure, kind: Kind) -> Result<TokenStream, Err
F: ops::FnOnce(&mut #name<#(#type_params,)* ()>,I) -> O
{
type Output = O;

#[inline(always)]
fn call_once(mut self, args: I) -> Self::Output {
self.f()(&mut self.strip_f(), args)
Expand All @@ -308,6 +350,7 @@ fn impl_closure(mut closure: ExprClosure, kind: Kind) -> Result<TokenStream, Err
F: ops::FnOnce(#name<#(#type_params,)* ()>,I) -> O
{
type Output = O;

#[inline(always)]
fn call_once(self, args: I) -> Self::Output {
self.f()(self.strip_f(), args)
Expand Down Expand Up @@ -787,11 +830,7 @@ impl<'a> State<'a> {
{
let path_segment = &path.segments.first().unwrap();
let ident = &path_segment.ident;
let has_path_arguments = if let PathArguments::None = path_segment.arguments {
false
} else {
true
};
let has_path_arguments = !matches!(path_segment.arguments, PathArguments::None);
if !self.variables.contains(ident) {
// Assume it's a variable, unless:
// * It starts with an upper-case letter, e.g. `Some`, OR
Expand Down
Loading

0 comments on commit 01a4d44

Please sign in to comment.