From aabc6479bbd2c1d7d2ade9f0820e02e7c9cc4774 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 15 Feb 2021 15:48:17 +0100 Subject: [PATCH] "fix" the destructor macro long story short: compiler restrictions Signed-off-by: Wolfgang Bumiller --- perlmod-test/src/bless.rs | 5 ++- perlmod/src/macros.rs | 75 ++++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/perlmod-test/src/bless.rs b/perlmod-test/src/bless.rs index 6d1a6f9..f609957 100644 --- a/perlmod-test/src/bless.rs +++ b/perlmod-test/src/bless.rs @@ -29,5 +29,8 @@ mod export { Ok(()) } - perlmod::destructor! { Bless : CLASSNAME } + #[export(name = "DESTROY")] + fn destroy(#[raw] this: Value) { + perlmod::destructor!(this, Bless : CLASSNAME); + } } diff --git a/perlmod/src/macros.rs b/perlmod/src/macros.rs index a8dae33..d90fd2c 100644 --- a/perlmod/src/macros.rs +++ b/perlmod/src/macros.rs @@ -2,6 +2,10 @@ /// Create a standard destructor for a boxed type. /// +/// Due to compiler restrictions, the function itself needs to be written manually, only the +/// contents can be generated using this macro. This also means that the `this` parameter needs to +/// be passed to the macro. +/// /// For safety it is recommended to pass the package name to the macro in order for the generated /// code to also guard against values not blessed into the package. /// @@ -9,22 +13,34 @@ /// /// Usage: /// ```ignore -/// // complete: -/// destructor!(MyType : "My::RS::Package" => { -/// Err(err) => { eprintln!("DESTROY called with invalid pointer: {}", err); } -/// }); +/// #[export(name = "DESTROY")] +/// fn destroy(#[raw] this: Value) { +/// // complete: +/// destructor!(this, MyType : "My::RS::Package" => { +/// Err(err) => { eprintln!("DESTROY called with invalid pointer: {}", err); } +/// }); +/// } /// -/// // error case only -/// destructor!(MyType { -/// Err(err) => { eprintln!("DESTROY called with invalid pointer: {}", err); } -/// }); +/// #[export(name = "DESTROY")] +/// fn destroy(#[raw] this: Value) { +/// // error case only +/// destructor!(this, MyType { +/// Err(err) => { eprintln!("DESTROY called with invalid pointer: {}", err); } +/// }); +/// } /// -/// // simple case with default error case (which is the above example case) -/// // the class name can also reference a constant. -/// destructor!(MyType : CLASSNAME); +/// #[export(name = "DESTROY")] +/// fn destroy(#[raw] this: Value) { +/// // simple case with default error case (which is the above example case) +/// // the class name can also reference a constant. +/// destructor!(this, MyType : CLASSNAME); +/// } /// -/// // simple less-safe case without checking the reference type. -/// destructor!(MyType); +/// #[export(name = "DESTROY")] +/// fn destroy(#[raw] this: Value) { +/// // simple less-safe case without checking the reference type. +/// destructor!(this, MyType); +/// } /// ``` /// /// The generated code looks like this: @@ -45,9 +61,9 @@ /// ``` #[macro_export] macro_rules! destructor { - ($ty:ty : $package:expr) => { + ($this:expr, $ty:ty : $package:expr) => { $crate::destructor! { - $ty : $package => { + $this, $ty : $package => { Err(err) => { eprintln!("DESTROY called with invalid pointer: {}", err); } @@ -55,22 +71,20 @@ macro_rules! destructor { } }; - ($ty:ty : $package:expr => { + ($this:expr, $ty:ty : $package:expr => { Err($errname:ident) => $on_err:expr }) => { - #[perlmod::export(name = "DESTROY")] - fn destroy(#[raw] this: Value) { - match unsafe { this.from_blessed_box::<$ty>($package) } { - Ok(ptr) => { - let _ = unsafe { Box::<$ty>::from_raw(ptr as *const $ty as *mut $ty) }; - } - Err($errname) => $on_err, + match unsafe { $this.from_blessed_box::<$ty>($package) } { + Ok(ptr) => { + let _ = unsafe { Box::<$ty>::from_raw(ptr as *const $ty as *mut $ty) }; } + Err($errname) => $on_err, } }; - ($ty:ty) => { + ($this:expr, $ty:ty) => { $crate::destructor! { + $this, $ty { Err(err) => { eprintln!("DESTROY called with invalid pointer: {}", err); @@ -79,17 +93,14 @@ macro_rules! destructor { } }; - ($ty:ty { + ($this:expr, $ty:ty { Err($name:ident) => $on_err:expr }) => { - #[perlmod::export(name = "DESTROY")] - fn destroy(#[raw] this: Value) { - match unsafe { this.from_ref_box::<$ty>() } { - Ok(ptr) => { - let _ = unsafe { Box::::from_raw(ptr) }; - } - Err($name) => $on_err, + match unsafe { $this.from_ref_box::<$ty>() } { + Ok(ptr) => { + let _ = unsafe { Box::::from_raw(ptr) }; } + Err($name) => $on_err, } }; }