Skip to content

Instantly share code, notes, and snippets.

@thomcc
Last active Jun 6, 2021
Embed
What would you like to do?
//! initial version courtesy of @danielhenrymantilla.
//!
//! extended to support fns with args/return types,
//! visibility, #[attributes], unsafe, const, async,
//! extern "abi" ...
//!
//! left as an exercise for later (cuz it sux):
//! - generics?
//! - where clauses?
//! - probably other shit im missing
//! - ...
//!
//! probably don't do stuff like this, honestly.
#[macro_export]
macro_rules! with_sections {
(
$(#[$m:meta])*
$v:vis
$(const $(@$const_:tt)?)?
$(async $(@$async_:tt)?)?
$(unsafe $(@$unsafe_:tt)?)?
$(extern $($abi:literal)?)?
fn $fname:ident ($($args:tt)*) -> $ret:ty {
$($contents:tt)*
}
) => (with_sections! {
// note: the "param" to `@__inner` is
// passed verbatim (as a `:tt`) until
// the end
@__inner (
@name $fname
@vis ($v)
@args ($($args)*)
@ret ($ret)
@attrs ($(#[$m])*)
@abi ($(extern $($abi)?)?)
@unsafety ($(unsafe $(@$unsafe_)?)?)
@constitude ($(const $(@$const_)?)?)
@asynchrony ($(async $(@$async_)?)?)
)
@out []
@in [{$($contents)*}]
});
// `fn blah(...) {}` — no explicit return type, but we
// fake it with explicit `-> ()`
(
$(#[$m:meta])*
$v:vis
$(const $(@$const_:tt)?)?
$(async $(@$async_:tt)?)?
$(unsafe $(@$unsafe_:tt)?)?
$(extern $($abi:literal)?)?
fn $fname:ident ($($args:tt)*) $contents:tt
) => (with_sections! {
$(#[$m])*
$v
$(const $(@$const_)?)?
$(async $(@$async_)?)?
$(unsafe $(@$unsafe_)?)?
$(extern $($abi)?)?
fn $fname($($args)*) -> () $contents
});
(@__inner $funcinfo:tt
@out $out:tt
@in [#[section($section:expr $(,)?)] $body:tt $($rest:tt)*]
) => (with_sections! {
@__inner $funcinfo
@out $out
@in [match Section::new($section) { _ => $body } $($rest)*]
});
(@__inner $funcinfo:tt
@out $out:tt
@in [{ $($inner:tt)* } $($rest:tt)*]
) => (with_sections! {
@__inner $funcinfo
@out [$out]
@in [$($inner)* @end_brace $($rest)*]
});
(@__inner $funcinfo:tt
@out [[$($out:tt)*] $($acc:tt)*]
@in [@end_brace $($rest:tt)*]
) => (with_sections! {
@__inner $funcinfo
@out [$($out)* { $($acc)* }]
@in [$($rest)*]
});
(@__inner $funcinfo:tt
@out [$($out:tt)*]
@in [$current:tt $($rest:tt)*]
) => (with_sections! {
@__inner $funcinfo
@out [$($out)* $current]
@in [$($rest)*]
});
(
@__inner (
@name $fname:ident
@vis ($v:vis)
@args ($($args:tt)*)
@ret ($ret:ty)
@attrs ($(#[$m:meta])*)
@abi ($(extern $($abi:literal)?)?)
@unsafety ($(unsafe $(@$unsafe_:tt)?)?)
@constitude ($(const $(@$const_:tt)?)?)
@asynchrony ($(async $(@$async_:tt)?)?)
)
@out [$($out:tt)*]
@in [/* nothing */]
) => (
$(#[$m])*
$v
$(const $(@$const_)?)?
$(async $(@$async_)?)?
$(unsafe $(@$unsafe_)?)?
$(extern $($abi)?)?
fn $fname($($args)*) -> $ret $($out)*
);
}
pub struct Section {
name: &'static str,
}
impl Section {
pub fn new(name: &'static str) -> Section {
println!("begin {}", name);
Self { name }
}
}
impl Drop for Section {
fn drop(&mut self) {
println!("end {}", self.name);
}
}
// rest of this is various kinds of test code.
// (most stuff got tested by modifying these in place)
with_sections! {
/// ```
/// playground::doit(1);
/// ```
pub fn doit(x: i32) {
println!("b4 everything {}", x);
#[section("foo")]
{
println!("inside foo before bar");
#[section("bar")]
{
println!("inside bar")
}
println!("inside foo after bar");
}
#[section("baz")]
{
println!("inside baz")
}
println!("after everything");
}
}
with_sections! {
// extern "C"
const unsafe fn no() -> i32 {
// println!("no");
4
}
}
with_sections! {
// extern "C"
async unsafe fn _ayes() {
println!("no");
// 4
}
}
fn main() {
fn type_name_of<T: 'static>(_: T) -> &'static str {
std::any::type_name::<T>()
}
doit(1);
// let _f: extern "C" fn() -> i32 = no;
unsafe { println!("{}", no()) };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment