Skip to content

Commit 64e58d0

Browse files
committed
Add lightning-macros crate
Previously, we used the `bdk_macros` dependency for some simple proc macros in `lightning-transaction-sync`. However, post-1.0 BDK doesn't further maintain this crate and will at some point probably yank it together with the old `bdk` crate that was split up. Here, we create a new crate for utility proc macros and ~~steal~~ add what we currently use (slightly modified for the latest `syn` version's API though). In the future we may want to expand this crate, e.g., for some `maybe_async` macros in the context of an `async KVStore` implementation.
1 parent 66fb520 commit 64e58d0

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ members = [
1414
"lightning-rapid-gossip-sync",
1515
"lightning-custom-message",
1616
"lightning-transaction-sync",
17+
"lightning-macros",
1718
"possiblyrandom",
1819
]
1920

ci/ci-tests.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ WORKSPACE_MEMBERS=(
4646
lightning-rapid-gossip-sync
4747
lightning-custom-message
4848
lightning-transaction-sync
49+
lightning-macros
4950
possiblyrandom
5051
)
5152

lightning-macros/Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "lightning-macros"
3+
version = "0.1.0"
4+
authors = ["Elias Rohrer"]
5+
license = "MIT OR Apache-2.0"
6+
repository = "https://github.com/lightningdevkit/rust-lightning/"
7+
description = """
8+
Proc macros used by LDK
9+
"""
10+
edition = "2021"
11+
12+
[package.metadata.docs.rs]
13+
rustdoc-args = ["--cfg", "docsrs"]
14+
15+
[lib]
16+
proc-macro = true
17+
18+
[features]
19+
20+
[dependencies]
21+
syn = { version = "2.0.77", default-features = false, features = ["parsing", "printing", "proc-macro", "full"] }
22+
proc-macro2 = { version = "1.0.86", default-features = false, features = ["proc-macro"] }
23+
quote = { version = "1.0", default-features = false, features = ["proc-macro"] }
24+
25+
[lints]
26+
workspace = true

lightning-macros/src/lib.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
#![crate_name = "lightning_macros"]
11+
12+
//! Proc macros used by LDK
13+
14+
#![cfg_attr(not(test), no_std)]
15+
#![deny(missing_docs)]
16+
#![forbid(unsafe_code)]
17+
#![deny(rustdoc::broken_intra_doc_links)]
18+
#![deny(rustdoc::private_intra_doc_links)]
19+
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
20+
21+
use syn::spanned::Spanned;
22+
use syn::{parse, ImplItemFn, ItemImpl, ItemTrait, Token};
23+
use proc_macro::TokenStream;
24+
use quote::quote;
25+
26+
fn add_async_trait(mut parsed: ItemTrait) -> TokenStream {
27+
let output = quote! {
28+
#[cfg(not(feature = "async-interface"))]
29+
#parsed
30+
};
31+
32+
for mut item in &mut parsed.items {
33+
if let syn::TraitItem::Fn(f) = &mut item {
34+
f.sig.asyncness = Some(Token![async](f.span()));
35+
}
36+
}
37+
38+
let output = quote! {
39+
#output
40+
41+
#[cfg(feature = "async-interface")]
42+
#[async_trait(?Send)]
43+
#parsed
44+
};
45+
46+
output.into()
47+
}
48+
49+
fn add_async_method(mut parsed: ImplItemFn) -> TokenStream {
50+
let output = quote! {
51+
#[cfg(not(feature = "async-interface"))]
52+
#parsed
53+
};
54+
55+
parsed.sig.asyncness = Some(Token![async](parsed.span()));
56+
57+
let output = quote! {
58+
#output
59+
60+
#[cfg(feature = "async-interface")]
61+
#parsed
62+
};
63+
64+
output.into()
65+
}
66+
67+
fn add_async_impl_trait(mut parsed: ItemImpl) -> TokenStream {
68+
let output = quote! {
69+
#[cfg(not(feature = "async-interface"))]
70+
#parsed
71+
};
72+
73+
for mut item in &mut parsed.items {
74+
if let syn::ImplItem::Fn(f) = &mut item {
75+
f.sig.asyncness = Some(Token![async](f.span()));
76+
}
77+
}
78+
79+
let output = quote! {
80+
#output
81+
82+
#[cfg(feature = "async-interface")]
83+
#[async_trait(?Send)]
84+
#parsed
85+
};
86+
87+
output.into()
88+
}
89+
90+
/// Makes a method or every method of a trait `async`, if the `async-interface` feature is enabled.
91+
///
92+
/// Requires the `async-trait` crate as a dependency whenever this attribute is used on a trait
93+
/// definition or trait implementation.
94+
#[proc_macro_attribute]
95+
pub fn maybe_async(_attr: TokenStream, item: TokenStream) -> TokenStream {
96+
if let Ok(parsed) = parse(item.clone()) {
97+
add_async_trait(parsed)
98+
} else if let Ok(parsed) = parse(item.clone()) {
99+
add_async_method(parsed)
100+
} else if let Ok(parsed) = parse(item) {
101+
add_async_impl_trait(parsed)
102+
} else {
103+
(quote! {
104+
compile_error!("#[maybe_async] can only be used on methods, trait or trait impl blocks")
105+
})
106+
.into()
107+
}
108+
}
109+
110+
/// Awaits, if the `async-interface` feature is enabled.
111+
#[proc_macro]
112+
pub fn maybe_await(expr: TokenStream) -> TokenStream {
113+
let expr: proc_macro2::TokenStream = expr.into();
114+
let quoted = quote! {
115+
{
116+
#[cfg(not(feature = "async-interface"))]
117+
{
118+
#expr
119+
}
120+
121+
#[cfg(feature = "async-interface")]
122+
{
123+
#expr.await
124+
}
125+
}
126+
};
127+
128+
quoted.into()
129+
}

0 commit comments

Comments
 (0)