mirror of
git://git.proxmox.com/git/perlmod.git
synced 2025-03-13 04:58:16 +03:00
fix #[export(name=...)], drop deprecated make_package
The `make_package` macro is tedious to use. We now simply depend on new-enough rustc for `package` to work. The change to #[export] allows writing: #[export(name = "DESTROY")] fn destroy(#[raw] this: Value) { ... } Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
ca00cfcc9a
commit
2991a46a31
@ -64,7 +64,9 @@ impl ModuleAttrs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FunctionAttrs {
|
||||
pub perl_name: Option<Ident>,
|
||||
pub xs_name: Option<Ident>,
|
||||
pub raw_return: bool,
|
||||
}
|
||||
@ -73,8 +75,7 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
|
||||
type Error = syn::Error;
|
||||
|
||||
fn try_from(args: AttributeArgs) -> Result<Self, Self::Error> {
|
||||
let mut xs_name = None;
|
||||
let mut raw_return = false;
|
||||
let mut attrs = FunctionAttrs::default();
|
||||
|
||||
for arg in args {
|
||||
match arg {
|
||||
@ -83,15 +84,17 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
|
||||
lit: syn::Lit::Str(litstr),
|
||||
..
|
||||
})) => {
|
||||
if path.is_ident("name") {
|
||||
xs_name = Some(Ident::new(&litstr.value(), litstr.span()));
|
||||
if path.is_ident("xs_name") {
|
||||
attrs.xs_name = Some(Ident::new(&litstr.value(), litstr.span()));
|
||||
} else if path.is_ident("name") {
|
||||
attrs.perl_name = Some(Ident::new(&litstr.value(), litstr.span()));
|
||||
} else {
|
||||
bail!(path => "unknown argument");
|
||||
}
|
||||
}
|
||||
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
|
||||
if path.is_ident("raw_return") {
|
||||
raw_return = true;
|
||||
attrs.raw_return = true;
|
||||
} else {
|
||||
bail!(path => "unknown attribute");
|
||||
}
|
||||
@ -100,9 +103,6 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
xs_name,
|
||||
raw_return,
|
||||
})
|
||||
Ok(attrs)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::attribs::FunctionAttrs;
|
||||
|
||||
pub struct XSub {
|
||||
pub rust_name: Ident,
|
||||
pub perl_name: Option<Ident>,
|
||||
pub xs_name: Ident,
|
||||
pub tokens: TokenStream,
|
||||
}
|
||||
@ -201,6 +202,7 @@ pub fn handle_function(
|
||||
#wrapper_func
|
||||
|
||||
#[inline(never)]
|
||||
#[allow(non_snake_case)]
|
||||
fn #impl_xs_name(
|
||||
_cv: &::perlmod::ffi::CV,
|
||||
) -> Result<#return_type, *mut ::perlmod::ffi::SV> {
|
||||
@ -229,6 +231,7 @@ pub fn handle_function(
|
||||
|
||||
Ok(XSub {
|
||||
rust_name: name.to_owned(),
|
||||
perl_name: attr.perl_name.clone(),
|
||||
xs_name,
|
||||
tokens,
|
||||
})
|
||||
|
@ -74,7 +74,7 @@ pub fn package(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
|
||||
}
|
||||
|
||||
/// Attribute to export a function so that it can be installed as an `xsub` in perl. See the
|
||||
/// [`make_package!`] macro for a usage example.
|
||||
/// [`package!`] macro for a usage example.
|
||||
#[proc_macro_attribute]
|
||||
pub fn export(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
|
||||
let attr = parse_macro_input!(attr as AttributeArgs);
|
||||
@ -82,68 +82,6 @@ pub fn export(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
|
||||
handle_error(item.clone(), export_impl(attr, item)).into()
|
||||
}
|
||||
|
||||
/// Proc macro to create a perl package file for rust functions.
|
||||
///
|
||||
/// This macro will write a perl package/module file into cargo's working directory. (Typically the
|
||||
/// manifest directory.)
|
||||
///
|
||||
/// This macro exists mostly for backward compatibility. When using rustc 1.42 or above, a more
|
||||
/// readable and less repetitive code will be produced with the [`package`](module@crate::package)
|
||||
/// attribute instead.
|
||||
///
|
||||
/// This macro always has to be used in conjunction with the [`export!]` macro, like this:
|
||||
///
|
||||
/// ```
|
||||
/// # mod testmod {
|
||||
/// use anyhow::{bail, Error};
|
||||
/// use perlmod::export;
|
||||
///
|
||||
/// #[export]
|
||||
/// fn sum_except_42(a: u32, b: u32) -> Result<u32, Error> {
|
||||
/// if a == 42 {
|
||||
/// // Errors 'die' in perl, so newlines at the end of error messages make a difference!
|
||||
/// bail!("dying on magic number\n");
|
||||
/// }
|
||||
///
|
||||
/// Ok(a + b)
|
||||
/// }
|
||||
///
|
||||
/// #[export(name = "xs_sub_name")]
|
||||
/// fn double(a: u32) -> Result<u32, Error> {
|
||||
/// Ok(2 * a)
|
||||
/// }
|
||||
///
|
||||
/// perlmod::make_package! {
|
||||
/// // First we need to specify the package, similar to perl's syntax:
|
||||
/// package "RSPM::DocTest1";
|
||||
///
|
||||
/// // The library name is usually derived from the crate name in Cargo.toml automatically.
|
||||
/// // So this line is optional:
|
||||
/// lib "perlmod_test";
|
||||
///
|
||||
/// // An optional output file name can be specified as follows:
|
||||
/// // (we use this here to prevent doc tests from creating files...)
|
||||
/// file "/dev/null";
|
||||
///
|
||||
/// // The list of xsubs we want to export:
|
||||
/// subs {
|
||||
/// // When only providing the name, default naming convention will be used:
|
||||
/// // This is used like: `RSPM::DocTest1::sum_except_42(4, 5);` in perl.
|
||||
/// sum_except_42,
|
||||
/// // If we used an explicit export name, we need to also explicitly export the renamed
|
||||
/// // function here:
|
||||
/// // This is used like: `RSPM::DocTest1::double_the_number(5);` in perl.
|
||||
/// xs_sub_name as double_the_number,
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn make_package(item: TokenStream_1) -> TokenStream_1 {
|
||||
let item: TokenStream = item.into();
|
||||
handle_error(item.clone(), make_package_impl(item)).into()
|
||||
}
|
||||
|
||||
fn perlmod_impl(attr: AttributeArgs, item: TokenStream) -> Result<TokenStream, Error> {
|
||||
let item: syn::Item = syn::parse2(item)?;
|
||||
|
||||
@ -161,9 +99,3 @@ fn export_impl(attr: AttributeArgs, item: TokenStream) -> Result<TokenStream, Er
|
||||
let func = function::handle_function(attr, func, None)?;
|
||||
Ok(func.tokens)
|
||||
}
|
||||
|
||||
fn make_package_impl(item: TokenStream) -> Result<TokenStream, Error> {
|
||||
let pkg: package::Package = syn::parse2(item)?;
|
||||
pkg.write()?;
|
||||
Ok(TokenStream::new())
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ pub fn handle_module(attr: AttributeArgs, mut module: syn::ItemMod) -> Result<To
|
||||
|
||||
package.export_named(
|
||||
func.rust_name,
|
||||
func.perl_name,
|
||||
func.xs_name,
|
||||
"src/FIXME.rs".to_string(),
|
||||
);
|
||||
|
@ -8,10 +8,7 @@ use anyhow::Error;
|
||||
|
||||
use proc_macro2::{Ident, Span};
|
||||
|
||||
use syn::parse::Parse;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::AttributeArgs;
|
||||
use syn::Token;
|
||||
|
||||
use toml::Value;
|
||||
|
||||
@ -56,6 +53,7 @@ const MODULE_TAIL: &str = "}\n";
|
||||
|
||||
struct Export {
|
||||
rust_name: Ident,
|
||||
perl_name: Option<Ident>,
|
||||
xs_name: Ident,
|
||||
file_name: String,
|
||||
}
|
||||
@ -73,18 +71,16 @@ impl Package {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn export_named(&mut self, rust_name: Ident, xs_name: Ident, file_name: String) {
|
||||
pub fn export_named(
|
||||
&mut self,
|
||||
rust_name: Ident,
|
||||
perl_name: Option<Ident>,
|
||||
xs_name: Ident,
|
||||
file_name: String,
|
||||
) {
|
||||
self.exported.push(Export {
|
||||
rust_name,
|
||||
xs_name,
|
||||
file_name,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn export_direct(&mut self, name: Ident, file_name: String) {
|
||||
let xs_name = Ident::new(&format!("xs_{}", name), name.span());
|
||||
self.exported.push(Export {
|
||||
rust_name: name,
|
||||
perl_name,
|
||||
xs_name,
|
||||
file_name,
|
||||
});
|
||||
@ -97,7 +93,7 @@ impl Package {
|
||||
source = format!(
|
||||
"{} newXS('{}', '{}', \"{}\");\n",
|
||||
source,
|
||||
export.rust_name,
|
||||
export.perl_name.as_ref().unwrap_or(&export.rust_name),
|
||||
export.xs_name,
|
||||
export.file_name.replace('"', "\\\""),
|
||||
);
|
||||
@ -132,88 +128,6 @@ impl Package {
|
||||
}
|
||||
}
|
||||
|
||||
mod kw {
|
||||
syn::custom_keyword!(package);
|
||||
syn::custom_keyword!(lib);
|
||||
syn::custom_keyword!(file);
|
||||
syn::custom_keyword!(subs);
|
||||
}
|
||||
|
||||
impl Parse for Package {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let mut pkg = Package {
|
||||
attrs: ModuleAttrs {
|
||||
package_name: String::new(),
|
||||
file_name: None,
|
||||
lib_name: None,
|
||||
},
|
||||
exported: Vec::new(),
|
||||
};
|
||||
|
||||
// `package "Package::Name";` comes first
|
||||
let _pkg: kw::package = input.parse()?;
|
||||
let package: syn::LitStr = input.parse()?;
|
||||
let _semicolon: Token![;] = input.parse()?;
|
||||
pkg.attrs.package_name = package.value();
|
||||
|
||||
// `lib "lib_name";` optionally comes second
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(kw::lib) {
|
||||
let _lib: kw::lib = input.parse()?;
|
||||
let lib: syn::LitStr = input.parse()?;
|
||||
pkg.attrs.lib_name = Some(lib.value());
|
||||
let _semicolon: Token![;] = input.parse()?;
|
||||
}
|
||||
drop(lookahead);
|
||||
|
||||
// `file "File/Name.pm";` optionally comes third
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(kw::file) {
|
||||
let _file: kw::file = input.parse()?;
|
||||
let file: syn::LitStr = input.parse()?;
|
||||
pkg.attrs.file_name = Some(file.value());
|
||||
let _semicolon: Token![;] = input.parse()?;
|
||||
}
|
||||
drop(lookahead);
|
||||
|
||||
// `sub { ... }` must follow:
|
||||
let _sub: kw::subs = input.parse()?;
|
||||
let content;
|
||||
let _brace_token: syn::token::Brace = syn::braced!(content in input);
|
||||
let items: Punctuated<ExportItem, Token![,]> =
|
||||
content.parse_terminated(ExportItem::parse)?;
|
||||
|
||||
for item in items {
|
||||
match item {
|
||||
ExportItem::Direct(name) => pkg.export_direct(name, "src/FIXME.rs".to_string()),
|
||||
ExportItem::Named(name, as_name) => {
|
||||
pkg.export_named(as_name, name, "src/FIXME.rs".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
enum ExportItem {
|
||||
Direct(Ident),
|
||||
Named(Ident, Ident),
|
||||
}
|
||||
|
||||
impl Parse for ExportItem {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let name: Ident = input.parse()?;
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(syn::token::As) {
|
||||
let _as: syn::token::As = input.parse()?;
|
||||
Ok(ExportItem::Named(name, input.parse()?))
|
||||
} else {
|
||||
Ok(ExportItem::Direct(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_cargo_toml(why: Span) -> Result<HashMap<String, Value>, syn::Error> {
|
||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR")
|
||||
.map_err(|err| format_err!(why, "failed to get CARGO_MANIFEST_DIR variable: {}", err))?;
|
||||
|
@ -26,8 +26,8 @@ mod export {
|
||||
println!("Called something!");
|
||||
}
|
||||
|
||||
#[export]
|
||||
fn DESTROY(#[raw] this: Value) {
|
||||
#[export(name = "DESTROY")]
|
||||
fn destroy(#[raw] this: Value) {
|
||||
match this
|
||||
.dereference()
|
||||
.ok_or_else(|| format_err!("not a reference"))
|
||||
|
@ -7,8 +7,5 @@ mod pkg142;
|
||||
/// possible on nightly with #![feature(custom_inner_attributes)]
|
||||
mod pkginline;
|
||||
|
||||
/// This is possible on stable rust with some 1.3x already.
|
||||
mod pkgstable;
|
||||
|
||||
/// A test for blessed values.
|
||||
mod bless;
|
||||
|
@ -1,26 +0,0 @@
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
#[perlmod::export]
|
||||
fn foo(a: u32, b: u32) -> Result<u32, Error> {
|
||||
if a == 42 {
|
||||
bail!("dying on magic number");
|
||||
}
|
||||
|
||||
Ok(a + b)
|
||||
}
|
||||
|
||||
#[perlmod::export(name = "xs_a")]
|
||||
fn func_b(a: u32) -> Result<u32, Error> {
|
||||
Ok(a * 2)
|
||||
}
|
||||
|
||||
perlmod::make_package! {
|
||||
package "RSPM::Foo";
|
||||
|
||||
//lib "perlmod_test";
|
||||
|
||||
subs {
|
||||
foo,
|
||||
xs_a as b, // func_b's exported xsub was renamed to xs_a, and in perl it's called b
|
||||
}
|
||||
}
|
@ -1,17 +1,13 @@
|
||||
//! Crate for creating perl packages/bindings for rust code.
|
||||
//!
|
||||
//! The main feature of this crate are the [`package`], [`export`] and [`make_package!`] macros
|
||||
//! provided by the `perlmod-macro` crate. These are documented here.
|
||||
//! The main feature of this crate is the [`package`] macro provided by the `perlmod-macro` crate
|
||||
//! and documented here.
|
||||
//!
|
||||
//! The underlying machinery for these macros is contained in this crate and provides ways to
|
||||
//! serialize and deserialize data between perl and rust.
|
||||
//!
|
||||
//! For now, see the [`make_package!`] macro for all the details, since as of the time of writing
|
||||
//! this, we're only at rust 1.40.
|
||||
//!
|
||||
//! [`package`]: attr.package.html
|
||||
//! [`export`]: attr.export.html
|
||||
//! [`make_package!`]: macro.make_package.html
|
||||
|
||||
pub(crate) mod error;
|
||||
pub use error::Error;
|
||||
@ -43,4 +39,4 @@ pub use value::Value;
|
||||
|
||||
#[cfg(feature = "exporter")]
|
||||
#[doc(inline)]
|
||||
pub use perlmod_macro::{export, make_package, package};
|
||||
pub use perlmod_macro::{export, package};
|
||||
|
@ -272,7 +272,7 @@ impl ScalarRef {
|
||||
///
|
||||
/// The user is responsible for making sure the underlying pointer is correct.
|
||||
pub unsafe fn pv_ref<T>(&self) -> Result<&T, Error> {
|
||||
self.pv_raw().map(|p| unsafe { &*p })
|
||||
self.pv_raw().map(|p| &*p)
|
||||
}
|
||||
|
||||
/// Interpret the byte string as a pointer and return it as a mutable reference for
|
||||
@ -282,7 +282,7 @@ impl ScalarRef {
|
||||
///
|
||||
/// The user is responsible for making sure the underlying pointer is correct.
|
||||
pub unsafe fn pv_mut_ref<T>(&self) -> Result<&mut T, Error> {
|
||||
self.pv_raw().map(|p| unsafe { &mut *p })
|
||||
self.pv_raw().map(|p| &mut *p)
|
||||
}
|
||||
|
||||
/// Create another owned reference to this value.
|
||||
|
Loading…
x
Reference in New Issue
Block a user