diff --git a/expand/src/bin/example1.expanded.rs b/expand/src/bin/example1.expanded.rs index 8fbd688..f93f0fa 100644 --- a/expand/src/bin/example1.expanded.rs +++ b/expand/src/bin/example1.expanded.rs @@ -1,23 +1,18 @@ #![feature(prelude_import)] -#[prelude_import] -use std::prelude::rust_2021::*; #[macro_use] extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; #[repr(transparent)] struct Iterator1 { #[doc(hidden)] - __private_inner: ::stacklover::__private_mod::ErasedStorage< - { Iterator1::__SIZE }, - { Iterator1::__ALIGN }, - >, + __private_inner: + ::stacklover::__private_mod::ErasedStorage<{ Iterator1::__SIZE }, { Iterator1::__ALIGN }>, } const _: () = { type __StackloverWrappedType<__Inner__> = __Inner__; #[inline(always)] - fn __stacklover_create( - dep1: &'static str, - dep2: i32, - ) -> impl Iterator + Clone { + fn __stacklover_create(dep1: &'static str, dep2: i32) -> impl Iterator + Clone { (1..) .map(|x| x * 3) .take_while(|x| *x < 20) @@ -38,7 +33,7 @@ const _: () = { let inner_to_struct = __stacklover_inner_to_struct_fn_unreachable; inner_to_struct(created_value) }; - fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { + const fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { ::core::panicking::panic("internal error: entered unreachable code") } __stacklover_fn_param_unreachable(__stacklover_inner_to_struct_fn_unreachable) @@ -46,7 +41,7 @@ const _: () = { impl Iterator1 { #[inline(always)] pub fn new(dep1: &'static str, dep2: i32) -> __StackloverWrappedType { - let __stacklover_inner_to_struct_fn = |inner| Self { + let __stacklover_inner_to_struct_fn = |inner| Iterator1 { __private_inner: unsafe { ::core::mem::transmute::< _, @@ -57,24 +52,30 @@ const _: () = { >(inner) }, }; + let inner_to_struct = __stacklover_inner_to_struct_fn; { let created_value = __stacklover_create(dep1, dep2); - let inner_to_struct = __stacklover_inner_to_struct_fn; inner_to_struct(created_value) } } } const _: () = { - if !(::core::mem::size_of::() == Iterator1::__SIZE) { - { - ::core::panicking::panic_fmt(format_args!("invalid size")); + { + match ::core::mem::size_of::() == Iterator1::__SIZE { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid size")); + } } - } - if !(::core::mem::align_of::() == Iterator1::__ALIGN) { - { - ::core::panicking::panic_fmt(format_args!("invalid align")); + }; + { + match ::core::mem::align_of::() == Iterator1::__ALIGN { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid align")); + } } - } + }; }; const _: fn() = || { fn assert_static(_: T) {} @@ -83,18 +84,14 @@ const _: () = { impl Iterator1 { #[doc(hidden)] const __SIZE: usize = { - const fn size_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn size_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::size_of::() } size_of_return_value(&__stacklover_inner_unreachable) }; #[doc(hidden)] const __ALIGN: usize = { - const fn align_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn align_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::align_of::() } align_of_return_value(&__stacklover_inner_unreachable) @@ -144,7 +141,8 @@ const _: () = { if true { unsafe { ::core::mem::transmute(self) } } else { - #[allow(unreachable_code)] __stacklover_inner_unreachable() + #[allow(unreachable_code)] + __stacklover_inner_unreachable() } } #[inline(always)] diff --git a/expand/src/bin/example2.expanded.rs b/expand/src/bin/example2.expanded.rs index 8e44056..849dda7 100644 --- a/expand/src/bin/example2.expanded.rs +++ b/expand/src/bin/example2.expanded.rs @@ -1,15 +1,13 @@ #![feature(prelude_import)] -#[prelude_import] -use std::prelude::rust_2021::*; #[macro_use] extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; #[repr(transparent)] struct Iterator1 { #[doc(hidden)] - __private_inner: ::stacklover::__private_mod::ErasedStorage< - { Iterator1::__SIZE }, - { Iterator1::__ALIGN }, - >, + __private_inner: + ::stacklover::__private_mod::ErasedStorage<{ Iterator1::__SIZE }, { Iterator1::__ALIGN }>, } const _: () = { type __StackloverWrappedType<__Inner__> = __Inner__; @@ -27,22 +25,19 @@ const _: () = { #[allow(unused)] #[allow(unreachable_code)] fn __stacklover_inner_unreachable() -> impl Iterator + Clone { - fn __stacklover_await_future_unreachable< - T: ::core::future::Future, - O, - >(_: T) -> O { + fn __stacklover_await_future_unreachable, O>( + _: T, + ) -> O { ::core::panicking::panic("internal error: entered unreachable code") } let __stacklover_inner_to_struct_fn_unreachable = |inner| -> Iterator1 { ::core::panicking::panic("internal error: entered unreachable code") }; let _ = { - let created_value = __stacklover_await_future_unreachable( - __stacklover_create( - ::core::panicking::panic("internal error: entered unreachable code"), - ::core::panicking::panic("internal error: entered unreachable code"), - ), - ); + let created_value = __stacklover_await_future_unreachable(__stacklover_create( + ::core::panicking::panic("internal error: entered unreachable code"), + ::core::panicking::panic("internal error: entered unreachable code"), + )); let inner_to_struct = __stacklover_inner_to_struct_fn_unreachable; inner_to_struct(created_value) }; @@ -53,10 +48,7 @@ const _: () = { } impl Iterator1 { #[inline(always)] - pub async fn new( - dep1: &'static str, - dep2: i32, - ) -> __StackloverWrappedType { + pub async fn new(dep1: &'static str, dep2: i32) -> __StackloverWrappedType { let __stacklover_inner_to_struct_fn = |inner| Self { __private_inner: unsafe { ::core::mem::transmute::< @@ -76,16 +68,22 @@ const _: () = { } } const _: () = { - if !(::core::mem::size_of::() == Iterator1::__SIZE) { - { - ::core::panicking::panic_fmt(format_args!("invalid size")); + { + match ::core::mem::size_of::() == Iterator1::__SIZE { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid size")); + } } - } - if !(::core::mem::align_of::() == Iterator1::__ALIGN) { - { - ::core::panicking::panic_fmt(format_args!("invalid align")); + }; + { + match ::core::mem::align_of::() == Iterator1::__ALIGN { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid align")); + } } - } + }; }; const _: fn() = || { fn assert_static(_: T) {} @@ -94,18 +92,14 @@ const _: () = { impl Iterator1 { #[doc(hidden)] const __SIZE: usize = { - const fn size_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn size_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::size_of::() } size_of_return_value(&__stacklover_inner_unreachable) }; #[doc(hidden)] const __ALIGN: usize = { - const fn align_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn align_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::align_of::() } align_of_return_value(&__stacklover_inner_unreachable) @@ -155,7 +149,8 @@ const _: () = { if true { unsafe { ::core::mem::transmute(self) } } else { - #[allow(unreachable_code)] __stacklover_inner_unreachable() + #[allow(unreachable_code)] + __stacklover_inner_unreachable() } } #[inline(always)] diff --git a/expand/src/bin/example3.expanded.rs b/expand/src/bin/example3.expanded.rs index 64e2e4f..b60f2c9 100644 --- a/expand/src/bin/example3.expanded.rs +++ b/expand/src/bin/example3.expanded.rs @@ -1,16 +1,14 @@ #![feature(prelude_import)] -#[prelude_import] -use std::prelude::rust_2021::*; #[macro_use] extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; use stacklover::define_struct; #[repr(transparent)] struct Iterator1 { #[doc(hidden)] - __private_inner: ::stacklover::__private_mod::ErasedStorage< - { Iterator1::__SIZE }, - { Iterator1::__ALIGN }, - >, + __private_inner: + ::stacklover::__private_mod::ErasedStorage<{ Iterator1::__SIZE }, { Iterator1::__ALIGN }>, } const _: () = { type __StackloverWrappedType<__Inner__> = Result<__Inner__, std::io::Error>; @@ -40,7 +38,7 @@ const _: () = { let inner_to_struct = __stacklover_inner_to_struct_fn_unreachable; result.map(|inner| inner_to_struct(inner)) }; - fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { + const fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { ::core::panicking::panic("internal error: entered unreachable code") } __stacklover_fn_param_unreachable(__stacklover_inner_to_struct_fn_unreachable) @@ -48,7 +46,7 @@ const _: () = { impl Iterator1 { #[inline(always)] pub fn new(dep1: &'static str, dep2: i32) -> __StackloverWrappedType { - let __stacklover_inner_to_struct_fn = |inner| Self { + let __stacklover_inner_to_struct_fn = |inner| Iterator1 { __private_inner: unsafe { ::core::mem::transmute::< _, @@ -59,24 +57,30 @@ const _: () = { >(inner) }, }; + let inner_to_struct = __stacklover_inner_to_struct_fn; { let result = __stacklover_create(dep1, dep2); - let inner_to_struct = __stacklover_inner_to_struct_fn; result.map(|inner| inner_to_struct(inner)) } } } const _: () = { - if !(::core::mem::size_of::() == Iterator1::__SIZE) { - { - ::core::panicking::panic_fmt(format_args!("invalid size")); + { + match ::core::mem::size_of::() == Iterator1::__SIZE { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid size")); + } } - } - if !(::core::mem::align_of::() == Iterator1::__ALIGN) { - { - ::core::panicking::panic_fmt(format_args!("invalid align")); + }; + { + match ::core::mem::align_of::() == Iterator1::__ALIGN { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid align")); + } } - } + }; }; const _: fn() = || { fn assert_static(_: T) {} @@ -85,18 +89,14 @@ const _: () = { impl Iterator1 { #[doc(hidden)] const __SIZE: usize = { - const fn size_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn size_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::size_of::() } size_of_return_value(&__stacklover_inner_unreachable) }; #[doc(hidden)] const __ALIGN: usize = { - const fn align_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn align_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::align_of::() } align_of_return_value(&__stacklover_inner_unreachable) @@ -146,7 +146,8 @@ const _: () = { if true { unsafe { ::core::mem::transmute(self) } } else { - #[allow(unreachable_code)] __stacklover_inner_unreachable() + #[allow(unreachable_code)] + __stacklover_inner_unreachable() } } #[inline(always)] diff --git a/expand/src/bin/example4.expanded.rs b/expand/src/bin/example4.expanded.rs index 225e7b2..a6f5374 100644 --- a/expand/src/bin/example4.expanded.rs +++ b/expand/src/bin/example4.expanded.rs @@ -1,15 +1,12 @@ #![feature(prelude_import)] -#[prelude_import] -use std::prelude::rust_2021::*; #[macro_use] extern crate std; +#[prelude_import] +use std::prelude::rust_2021::*; #[repr(transparent)] struct I32 { #[doc(hidden)] - __private_inner: ::stacklover::__private_mod::ErasedStorage< - { I32::__SIZE }, - { I32::__ALIGN }, - >, + __private_inner: ::stacklover::__private_mod::ErasedStorage<{ I32::__SIZE }, { I32::__ALIGN }>, } const _: () = { type __StackloverWrappedType<__Inner__> = __Inner__; @@ -20,17 +17,16 @@ const _: () = { #[allow(unused)] #[allow(unreachable_code)] fn __stacklover_inner_unreachable() -> i32 { - let __stacklover_inner_to_struct_fn_unreachable = |inner| -> I32 { - ::core::panicking::panic("internal error: entered unreachable code") - }; + let __stacklover_inner_to_struct_fn_unreachable = + |inner| -> I32 { ::core::panicking::panic("internal error: entered unreachable code") }; let _ = { - let created_value = __stacklover_create( - ::core::panicking::panic("internal error: entered unreachable code"), - ); + let created_value = __stacklover_create(::core::panicking::panic( + "internal error: entered unreachable code", + )); let inner_to_struct = __stacklover_inner_to_struct_fn_unreachable; inner_to_struct(created_value) }; - fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { + const fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { ::core::panicking::panic("internal error: entered unreachable code") } __stacklover_fn_param_unreachable(__stacklover_inner_to_struct_fn_unreachable) @@ -38,7 +34,7 @@ const _: () = { impl I32 { #[inline(always)] pub fn new(dep2: i32) -> __StackloverWrappedType { - let __stacklover_inner_to_struct_fn = |inner| Self { + let __stacklover_inner_to_struct_fn = |inner| I32 { __private_inner: unsafe { ::core::mem::transmute::< _, @@ -49,24 +45,30 @@ const _: () = { >(inner) }, }; + let inner_to_struct = __stacklover_inner_to_struct_fn; { let created_value = __stacklover_create(dep2); - let inner_to_struct = __stacklover_inner_to_struct_fn; inner_to_struct(created_value) } } } const _: () = { - if !(::core::mem::size_of::() == I32::__SIZE) { - { - ::core::panicking::panic_fmt(format_args!("invalid size")); + { + match ::core::mem::size_of::() == I32::__SIZE { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid size")); + } } - } - if !(::core::mem::align_of::() == I32::__ALIGN) { - { - ::core::panicking::panic_fmt(format_args!("invalid align")); + }; + { + match ::core::mem::align_of::() == I32::__ALIGN { + true => {} + _ => { + ::core::panicking::panic_fmt(format_args!("invalid align")); + } } - } + }; }; const _: fn() = || { fn assert_static(_: T) {} @@ -75,18 +77,14 @@ const _: () = { impl I32 { #[doc(hidden)] const __SIZE: usize = { - const fn size_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn size_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::size_of::() } size_of_return_value(&__stacklover_inner_unreachable) }; #[doc(hidden)] const __ALIGN: usize = { - const fn align_of_return_value( - _: &(impl ::core::ops::Fn() -> R), - ) -> usize { + const fn align_of_return_value(_: &(impl ::core::ops::Fn() -> R)) -> usize { ::core::mem::align_of::() } align_of_return_value(&__stacklover_inner_unreachable) @@ -136,13 +134,12 @@ const _: () = { if true { unsafe { ::core::mem::transmute(self) } } else { - #[allow(unreachable_code)] __stacklover_inner_unreachable() + #[allow(unreachable_code)] + __stacklover_inner_unreachable() } } #[inline(always)] - pub fn as_pin_mut( - self: ::core::pin::Pin<&mut Self>, - ) -> ::core::pin::Pin<&mut (i32)> { + pub fn as_pin_mut(self: ::core::pin::Pin<&mut Self>) -> ::core::pin::Pin<&mut (i32)> { unsafe { self.map_unchecked_mut(Self::as_mut) } } } @@ -150,16 +147,14 @@ const _: () = { fn eq(&self, other: &Self) -> bool { ::core::cmp::PartialEq::eq(I32::as_ref(self), I32::as_ref(other)) } + #[allow(clippy::partialeq_ne_impl)] fn ne(&self, other: &Self) -> bool { ::core::cmp::PartialEq::ne(I32::as_ref(self), I32::as_ref(other)) } } impl ::core::cmp::Eq for I32 {} impl ::core::cmp::PartialOrd for I32 { - fn partial_cmp( - &self, - other: &Self, - ) -> ::core::option::Option<::core::cmp::Ordering> { + fn partial_cmp(&self, other: &Self) -> ::core::option::Option<::core::cmp::Ordering> { ::core::cmp::PartialOrd::partial_cmp(I32::as_ref(self), I32::as_ref(other)) } fn lt(&self, other: &Self) -> bool { diff --git a/src/lib.rs b/src/lib.rs index dd30ca2..d36b626 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,27 +1,27 @@ #[macro_export] macro_rules! define_struct { - // not async create + // async create ( $struct_name:ident, $(#[$attrs:meta])* - fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + async fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, impls = ( $($derive_trait:ident),* $(,)? ) $(,)? ) => { $crate::define_struct!( $struct_name, $(#[$attrs])* - fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, + async fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, impls = ( $($derive_trait),* ), inner_type = $create_fn_return_type, wrapped_type = __Inner__, to_wrapped_struct = |created_value, inner_to_struct| { inner_to_struct(created_value) }, ); }; - // not async create + // async create ( $struct_name:ident, $(#[$attrs:meta])* - fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + async fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, impls = ( $($derive_trait:ident),* $(,)? ), inner_type = $inner_type:ty, // wrapped_type should include __Inner__ @@ -33,19 +33,21 @@ macro_rules! define_struct { const _: () = { type __StackloverWrappedType<__Inner__> = $wrapped_type; - // NOTE: prefix "__" is for avoiding name confliction. The function body should not use the function name because it will be accidentally a recursive function. #[inline(always)] $(#[$attrs])* - fn __stacklover_create( $($param: $param_ty ),* ) -> $create_fn_return_type { + async fn __stacklover_create( $($param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* } #[allow(unused)] #[allow(unreachable_code)] fn __stacklover_inner_unreachable() -> $inner_type { + fn __stacklover_await_future_unreachable, O>(_: T) -> O { + ::core::unreachable!() + } let __stacklover_inner_to_struct_fn_unreachable = |inner| -> $struct_name { ::core::unreachable!() }; let _ = { - let $created_value = __stacklover_create( $( $crate::__ident_to_unreachable!($param) ),* ); + let $created_value = __stacklover_await_future_unreachable(__stacklover_create( $( $crate::__ident_to_unreachable!($param) ),* )); let $inner_to_struct_fn = __stacklover_inner_to_struct_fn_unreachable; // For type inference of __stacklover_inner_to_struct_fn_unreachable $($to_wrapped_struct_body)* @@ -58,14 +60,14 @@ macro_rules! define_struct { impl $struct_name { #[inline(always)] - pub fn new( $( $param: $param_ty ),* ) -> __StackloverWrappedType { + pub async fn new( $($param: $param_ty ),* ) -> __StackloverWrappedType { let __stacklover_inner_to_struct_fn = |inner| Self { __private_inner: unsafe { ::core::mem::transmute::<_, $crate::__private_mod::ErasedStorage<{ $struct_name::__SIZE }, { $struct_name::__ALIGN }>>(inner) }, }; { - let $created_value = __stacklover_create( $($param),* ); + let $created_value = __stacklover_create( $($param),* ).await; let $inner_to_struct_fn = __stacklover_inner_to_struct_fn; $($to_wrapped_struct_body)* } @@ -76,75 +78,161 @@ macro_rules! define_struct { $crate::__impl_traits!($struct_name, $($derive_trait)*); }; }; - // async create + // const create ( $struct_name:ident, $(#[$attrs:meta])* - $async:ident fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + const fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, impls = ( $($derive_trait:ident),* $(,)? ) $(,)? ) => { - $crate::define_struct!( + $crate::__define_maybe_const_struct!( + $struct_name, + $(#[$attrs])* + [const] fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, + impls = ( $($derive_trait),* ), + inner_type = $create_fn_return_type, + wrapped_type = __Inner__, + to_wrapped_struct = |created_value, inner_to_struct| { inner_to_struct!(created_value) }, + ); + }; + // const create + ( + $struct_name:ident, + $(#[$attrs:meta])* + const fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + impls = ( $($derive_trait:ident),* $(,)? ), + inner_type = $inner_type:ty, + // wrapped_type should include __Inner__ + wrapped_type = $wrapped_type:ty, + to_wrapped_struct = |$created_value:ident, $inner_to_struct_fn:ident| { $($to_wrapped_struct_body:tt)* } $(,)? + ) => { + $crate::__define_maybe_const_struct!( + $struct_name, + $(#[$attrs])* + [const] fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, + impls = ( $($derive_trait),* ), + inner_type = $inner_type, + wrapped_type = $wrapped_type, + to_wrapped_struct = |$created_value, $inner_to_struct_fn| { $( $to_wrapped_struct_body )* }, + ); + }; + // not async, not const create + ( + $struct_name:ident, + $(#[$attrs:meta])* + fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + impls = ( $($derive_trait:ident),* $(,)? ) $(,)? + ) => { + $crate::__define_maybe_const_struct!( $struct_name, $(#[$attrs])* - $async fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, + [] fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, impls = ( $($derive_trait),* ), inner_type = $create_fn_return_type, wrapped_type = __Inner__, to_wrapped_struct = |created_value, inner_to_struct| { inner_to_struct(created_value) }, ); }; - // async create + // not async, not const create ( $struct_name:ident, $(#[$attrs:meta])* - $async:ident fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, impls = ( $($derive_trait:ident),* $(,)? ), inner_type = $inner_type:ty, // wrapped_type should include __Inner__ wrapped_type = $wrapped_type:ty, to_wrapped_struct = |$created_value:ident, $inner_to_struct_fn:ident| { $($to_wrapped_struct_body:tt)* } $(,)? + ) => { + $crate::__define_maybe_const_struct!( + $struct_name, + $(#[$attrs])* + [] fn ( $( $param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* }, + impls = ( $($derive_trait),* ), + inner_type = $inner_type, + wrapped_type = $wrapped_type, + to_wrapped_struct = |$created_value, $inner_to_struct_fn| { $( $to_wrapped_struct_body )* }, + ); + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __define_maybe_const_struct { + ( + $struct_name:ident, + $(#[$attrs:meta])* + [$($cst:ident)?] fn ( $( $param:ident: $param_ty:ty ),* ) -> $create_fn_return_type:ty { $($create_fn_body:tt)* }, + impls = ( $($derive_trait:ident),* $(,)? ), + inner_type = $inner_type:ty, + // wrapped_type should include __Inner__ + wrapped_type = $wrapped_type:ty, + to_wrapped_struct = |$created_value:ident, $inner_to_struct_fn:ident| { $($to_wrapped_struct_body:tt)* }, ) => { $crate::__define_struct!($struct_name); const _: () = { type __StackloverWrappedType<__Inner__> = $wrapped_type; + // NOTE: prefix "__" is for avoiding name confliction. The function body should not use the function name because it will be accidentally a recursive function. #[inline(always)] $(#[$attrs])* - $async fn __stacklover_create( $($param: $param_ty ),* ) -> $create_fn_return_type { + $($cst)? fn __stacklover_create( $($param: $param_ty ),* ) -> $create_fn_return_type { $($create_fn_body)* } #[allow(unused)] #[allow(unreachable_code)] fn __stacklover_inner_unreachable() -> $inner_type { - fn __stacklover_await_future_unreachable, O>(_: T) -> O { - ::core::unreachable!() - } let __stacklover_inner_to_struct_fn_unreachable = |inner| -> $struct_name { ::core::unreachable!() }; + macro_rules! $inner_to_struct_fn { ($inner:expr) => { __stacklover_inner_to_struct_fn_unreachable($inner) }; } let _ = { - let $created_value = __stacklover_await_future_unreachable(__stacklover_create( $( $crate::__ident_to_unreachable!($param) ),* )); + let $created_value = __stacklover_create( $( $crate::__ident_to_unreachable!($param) ),* ); let $inner_to_struct_fn = __stacklover_inner_to_struct_fn_unreachable; // For type inference of __stacklover_inner_to_struct_fn_unreachable $($to_wrapped_struct_body)* }; - fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { + const fn __stacklover_fn_param_unreachable(_: impl Fn(T) -> R) -> T { ::core::unreachable!() } __stacklover_fn_param_unreachable(__stacklover_inner_to_struct_fn_unreachable) } + $( $crate::__expand_ident_as!($cst, const fn unambiguate_argument(f: &impl FnOnce(T) -> R, r: &T) {}); )? impl $struct_name { #[inline(always)] - pub $async fn new( $($param: $param_ty ),* ) -> __StackloverWrappedType { - let __stacklover_inner_to_struct_fn = |inner| Self { - __private_inner: unsafe { - ::core::mem::transmute::<_, $crate::__private_mod::ErasedStorage<{ $struct_name::__SIZE }, { $struct_name::__ALIGN }>>(inner) - }, - }; + pub $($cst)? fn new( $( $param: $param_ty ),* ) -> __StackloverWrappedType { + macro_rules! __stacklover_inner_to_struct_fn { + ($inner:expr) => { + $struct_name { + __private_inner: unsafe { + ::core::mem::transmute::<_, $crate::__private_mod::ErasedStorage<{ $struct_name::__SIZE }, { $struct_name::__ALIGN }>>($inner) + }, + } + }; + } + let __stacklover_inner_to_struct_fn = |inner| __stacklover_inner_to_struct_fn!(inner); + let $inner_to_struct_fn = __stacklover_inner_to_struct_fn; + // We can not call closures in const context, hence we can't simply call $inner_to_struct_fn. + // At the same time, __stacklover_inner_unreachable (above) must NOT contain MIR code naming __SIZE, which + // would lead to a cycle between assembling __stacklover_inner_unreachable and computing __SIZE + // (the compiler is not smart enough to understand that __stacklover_inner_unreachable is never evaluated, + // it still wants to assemble it). + // Hence, we have two different wrappers here, one calling the closure (above), and one creating the value + // "by hand", and allow the caller to use the macro as an alternative in const contexts. + // Anyway, only provide this macro if we are really expanding in const context. + $($crate::__expand_ident_as!($cst, + #[allow(unused)] + macro_rules! $inner_to_struct_fn { + ($inner:expr) => {__stacklover_inner_to_struct_fn!({ + let __created_value = { $inner }; + let _ = unambiguate_argument(&__stacklover_inner_to_struct_fn, &__created_value); + __created_value + })}; + } + );)? { - let $created_value = __stacklover_create( $($param),* ).await; - let $inner_to_struct_fn = __stacklover_inner_to_struct_fn; + let $created_value = __stacklover_create( $($param),* ); $($to_wrapped_struct_body)* } } @@ -154,13 +242,21 @@ macro_rules! define_struct { $crate::__impl_traits!($struct_name, $($derive_trait)*); }; }; + } +#[doc(hidden)] +#[macro_export] +macro_rules! __expand_ident_as { + ( $x:ident, $( $toks:tt )* ) => { + $( $toks )* + } +} #[doc(hidden)] #[macro_export] macro_rules! __ident_to_unreachable { ( $x:ident ) => { - ::core::unreachable!() + $crate::__expand_ident_as!($x, ::core::unreachable!()) }; } @@ -344,6 +440,7 @@ macro_rules! __impl_traits { ::core::cmp::PartialEq::eq($struct_name::as_ref(self), $struct_name::as_ref(other)) } + #[allow(clippy::partialeq_ne_impl)] // Forwarding to the inner type still seems like the correct thing to do fn ne(&self, other: &Self) -> bool { ::core::cmp::PartialEq::ne($struct_name::as_ref(self), $struct_name::as_ref(other)) } diff --git a/tests/lib.rs b/tests/lib.rs index 4796a7a..f9230ee 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -588,3 +588,46 @@ async fn it_works_with_async_auto_enum_attribute() { const fn size_of_val(_: &T) -> usize { size_of::() } + +#[test] +fn it_works_with_const() { + #[derive(PartialEq, Eq, Debug)] + struct HiddenImpl(u64); + + stacklover::define_struct! { + ConstConstructible, + const fn (a: u64) -> impl Eq + Debug { + HiddenImpl(a) + }, + impls = (PartialEq, Eq, Debug), + } + const FOO: ConstConstructible = ConstConstructible::new(42); + assert_eq!(FOO, FOO); +} + +// TODO: This *almost* works, but the compiler is not smart enough to eliminate the drop call of the Result +// which it then is unable to perform, so const and wrapping is currently not actually possible :/ +// fn it_works_with_deriving_traits_and_const_wrap_params() { +// use std::io::Error; +// stacklover::define_struct! { +// Tuple1, +// const fn (dep1: &'static str, dep2: i32) -> Result { +// Ok(create(dep1, dep2)) +// }, +// impls = ( PartialEq, Eq, Debug ), +// inner_type = impl PartialEq + Eq + Debug, +// wrapped_type = Result<__Inner__, Error>, +// to_wrapped_struct = |result, inner_to_struct| { match result { +// Ok(ok) => Ok( inner_to_struct!(ok) ), +// Err(err) => Err(err), +// } }, +// } +// const fn create(dep1: &'static str, dep2: i32) -> impl PartialEq + Eq + Debug { +// (dep1, dep2, false) +// } +// let result: Result = Tuple1::new("hello", 100); +// let x: Tuple1 = result.unwrap(); +// let bare = create("hello", 100); +// assert_eq!(format!("{:?}", x), format!("{:?}", bare)); +// assert_eq!(x, x); +// }