diff --git a/derive-impl/src/pyclass.rs b/derive-impl/src/pyclass.rs index 38f5bad61..a2896ffee 100644 --- a/derive-impl/src/pyclass.rs +++ b/derive-impl/src/pyclass.rs @@ -752,6 +752,7 @@ where let item_meta = MethodItemMeta::from_attr(ident.clone(), &item_attr)?; let py_name = item_meta.method_name()?; + let raw = item_meta.raw()?; let sig_doc = text_signature(func.sig(), &py_name); let doc = args.attrs.doc().map(|doc| format_doc(&sig_doc, &doc)); @@ -760,6 +761,7 @@ where cfgs: args.cfgs.to_vec(), ident: ident.to_owned(), doc, + raw, attr_name: self.inner.attr_name, }); Ok(()) @@ -954,6 +956,7 @@ struct MethodNurseryItem { py_name: String, cfgs: Vec, ident: Ident, + raw: bool, doc: Option, attr_name: AttrName, } @@ -1005,9 +1008,14 @@ impl ToTokens for MethodNursery { // } else { // quote_spanned! { ident.span() => #py_name } // }; + let method_new = if item.raw { + quote!(new_raw_const) + } else { + quote!(new_const) + }; inner_tokens.extend(quote! [ #(#cfgs)* - rustpython_vm::function::PyMethodDef::new_const( + rustpython_vm::function::PyMethodDef::#method_new( #py_name, Self::#ident, #flags, @@ -1203,7 +1211,7 @@ impl ToTokens for MemberNursery { struct MethodItemMeta(ItemMetaInner); impl ItemMeta for MethodItemMeta { - const ALLOWED_NAMES: &'static [&'static str] = &["name", "magic"]; + const ALLOWED_NAMES: &'static [&'static str] = &["name", "magic", "raw"]; fn from_inner(inner: ItemMetaInner) -> Self { Self(inner) @@ -1214,6 +1222,9 @@ impl ItemMeta for MethodItemMeta { } impl MethodItemMeta { + fn raw(&self) -> Result { + self.inner()._bool("raw") + } fn method_name(&self) -> Result { let inner = self.inner(); let name = inner._optional_str("name")?; diff --git a/vm/src/function/builtin.rs b/vm/src/function/builtin.rs index e38fda03b..41e04d252 100644 --- a/vm/src/function/builtin.rs +++ b/vm/src/function/builtin.rs @@ -81,6 +81,11 @@ pub const fn static_func>(f: F) -> &'static dyn Py zst_ref_out_of_thin_air(into_func(f)) } +#[inline(always)] +pub const fn static_raw_func(f: F) -> &'static dyn PyNativeFn { + zst_ref_out_of_thin_air(f) +} + // TODO: once higher-rank trait bounds are stabilized, remove the `Kind` type // parameter and impl for F where F: for PyNativeFnInternal impl IntoPyNativeFn<(T, R, VM)> for F diff --git a/vm/src/function/method.rs b/vm/src/function/method.rs index efb0b7a5f..513cb9383 100644 --- a/vm/src/function/method.rs +++ b/vm/src/function/method.rs @@ -87,6 +87,21 @@ impl PyMethodDef { } } + #[inline] + pub const fn new_raw_const( + name: &'static str, + func: impl PyNativeFn, + flags: PyMethodFlags, + doc: Option<&'static str>, + ) -> Self { + Self { + name, + func: super::static_raw_func(func), + flags, + doc, + } + } + pub fn to_proper_method( &'static self, class: &'static Py, diff --git a/vm/src/function/mod.rs b/vm/src/function/mod.rs index a0a20c996..3bd6d0f74 100644 --- a/vm/src/function/mod.rs +++ b/vm/src/function/mod.rs @@ -15,7 +15,7 @@ pub use argument::{ }; pub use arithmetic::{PyArithmeticValue, PyComparisonValue}; pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike}; -pub use builtin::{static_func, IntoPyNativeFn, PyNativeFn}; +pub use builtin::{static_func, static_raw_func, IntoPyNativeFn, PyNativeFn}; pub use either::Either; pub use fspath::FsPath; pub use getset::PySetterValue;