diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index 113c156d1..2b7a43d9a 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -290,7 +290,7 @@ impl ModuleItem for FunctionItem { #doc .into_function() .with_module(vm.ctx.new_utf8_str(#module.to_owned())) - .build(&vm.ctx) + .into_ref(&vm.ctx) ); quote! { vm.__module_set_attr(&module, #py_name, #new_func).unwrap(); diff --git a/examples/mini_repl.rs b/examples/mini_repl.rs index e3f23ed35..b24fe7fc2 100644 --- a/examples/mini_repl.rs +++ b/examples/mini_repl.rs @@ -43,7 +43,7 @@ fn run(vm: &vm::VirtualMachine) -> vm::PyResult<()> { // typing `quit()` is too long, let's make `on(False)` work instead. scope .globals - .set_item("on", vm.ctx.new_function("on", on), vm)?; + .set_item("on", vm.ctx.new_function("on", on).into(), vm)?; // let's include a fibonacci function, but let's be lazy and write it in Python add_python_function!( diff --git a/stdlib/src/pyexpat.rs b/stdlib/src/pyexpat.rs index cdb08be98..66c35e493 100644 --- a/stdlib/src/pyexpat.rs +++ b/stdlib/src/pyexpat.rs @@ -25,7 +25,7 @@ macro_rules! create_property { move |this: &PyExpatLikeXmlParser, func: PyObjectRef| *this.$element.write() = func, ); - $attributes.insert($name.to_owned(), attr); + $attributes.insert($name.to_owned(), attr.into()); }; } diff --git a/vm/src/builtins/builtinfunc.rs b/vm/src/builtins/builtinfunc.rs index bed33c19b..c422e7da4 100644 --- a/vm/src/builtins/builtinfunc.rs +++ b/vm/src/builtins/builtinfunc.rs @@ -1,9 +1,9 @@ -use super::{pytype, PyClassMethod, PyStrRef, PyTypeRef}; +use super::{pytype, PyClassMethod, PyStr, PyStrRef, PyTypeRef}; use crate::{ - function::{FuncArgs, PyNativeFunc}, + builtins::PyBoundMethod, + function::{FuncArgs, IntoPyNativeFunc, PyNativeFunc}, slots::{Callable, SlotDescriptor}, - PyClassImpl, PyContext, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, - VirtualMachine, + PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, VirtualMachine, }; use std::fmt; @@ -21,34 +21,29 @@ impl PyNativeFuncDef { doc: None, } } -} -impl PyNativeFuncDef { pub fn with_doc(mut self, doc: String, ctx: &PyContext) -> Self { - self.doc = Some(ctx.new_stringref(doc)); + self.doc = Some(PyStr::new_ref(doc, ctx)); self } pub fn into_function(self) -> PyBuiltinFunction { self.into() } - pub fn build_function(self, ctx: &PyContext) -> PyObjectRef { - self.into_function().build(ctx) + pub fn build_function(self, ctx: &PyContext) -> PyRef { + self.into_function().into_ref(ctx) } - pub fn build_method(self, ctx: &PyContext, class: PyTypeRef) -> PyObjectRef { - PyObject::new( + pub fn build_method(self, ctx: &PyContext, class: PyTypeRef) -> PyRef { + PyRef::new_ref( PyBuiltinMethod { value: self, class }, ctx.types.method_descriptor_type.clone(), None, ) } - pub fn build_classmethod(self, ctx: &PyContext, class: PyTypeRef) -> PyObjectRef { + pub fn build_classmethod(self, ctx: &PyContext, class: PyTypeRef) -> PyRef { // TODO: classmethod_descriptor - PyObject::new( - PyClassMethod::from(self.build_method(ctx, class)), - ctx.types.classmethod_type.clone(), - None, - ) + let callable = self.build_method(ctx, class).into(); + PyClassMethod::new_ref(callable, ctx) } } @@ -85,8 +80,8 @@ impl PyBuiltinFunction { self } - pub fn build(self, ctx: &PyContext) -> PyObjectRef { - PyObject::new( + pub fn into_ref(self, ctx: &PyContext) -> PyRef { + PyRef::new_ref( self, ctx.types.builtin_function_or_method_type.clone(), None, @@ -183,11 +178,12 @@ impl SlotDescriptor for PyBuiltinMethod { Ok(obj) => obj, Err(result) => return result, }; - if vm.is_none(&obj) && !Self::_cls_is(&cls, &obj.class()) { - Ok(zelf.into()) + let r = if vm.is_none(&obj) && !Self::_cls_is(&cls, &obj.class()) { + zelf.into() } else { - Ok(vm.ctx.new_bound_method(zelf.into(), obj)) - } + PyBoundMethod::new_ref(obj, zelf.into(), &vm.ctx).into() + }; + Ok(r) } } @@ -197,6 +193,20 @@ impl Callable for PyBuiltinMethod { } } +impl PyBuiltinMethod { + pub fn new_ref( + name: impl Into, + class: PyTypeRef, + f: F, + ctx: &PyContext, + ) -> PyRef + where + F: IntoPyNativeFunc, + { + ctx.make_funcdef(name, f).build_method(ctx, class) + } +} + #[pyimpl(with(SlotDescriptor, Callable), flags(METHOD_DESCR))] impl PyBuiltinMethod { #[pyproperty(magic)] diff --git a/vm/src/builtins/bytearray.rs b/vm/src/builtins/bytearray.rs index 306300924..2a34c129b 100644 --- a/vm/src/builtins/bytearray.rs +++ b/vm/src/builtins/bytearray.rs @@ -92,11 +92,6 @@ impl PyValue for PyByteArray { /// Fill bytearray class methods dictionary. pub(crate) fn init(context: &PyContext) { PyByteArray::extend_class(context, &context.types.bytearray_type); - let bytearray_type = &context.types.bytearray_type; - extend_class!(context, bytearray_type, { - "maketrans" => context.new_method("maketrans", bytearray_type.clone(), PyBytesInner::maketrans), - }); - PyByteArrayIterator::extend_class(context, &context.types.bytearray_iterator_type); } @@ -227,6 +222,11 @@ impl PyByteArray { } } + #[pymethod] + fn maketrans(from: PyBytesInner, to: PyBytesInner, vm: &VirtualMachine) -> PyResult { + PyBytesInner::maketrans(from, to, vm) + } + #[pymethod] fn pop(zelf: PyRef, index: OptionalArg, vm: &VirtualMachine) -> PyResult { let elements = &mut zelf.try_resizable(vm)?.elements; diff --git a/vm/src/builtins/bytes.rs b/vm/src/builtins/bytes.rs index 48fcb1119..694503d63 100644 --- a/vm/src/builtins/bytes.rs +++ b/vm/src/builtins/bytes.rs @@ -90,10 +90,6 @@ impl PyValue for PyBytes { pub(crate) fn init(context: &PyContext) { PyBytes::extend_class(context, &context.types.bytes_type); - let bytes_type = &context.types.bytes_type; - extend_class!(context, bytes_type, { - "maketrans" => context.new_method("maketrans", bytes_type.clone(), PyBytesInner::maketrans), - }); PyBytesIterator::extend_class(context, &context.types.bytes_iterator_type); } @@ -159,6 +155,11 @@ impl PyBytes { self.inner.contains(needle, vm) } + #[pymethod] + fn maketrans(from: PyBytesInner, to: PyBytesInner, vm: &VirtualMachine) -> PyResult { + PyBytesInner::maketrans(from, to, vm) + } + #[pymethod(magic)] fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult { self.inner.getitem("byte", needle, vm) // byte != Self::NAME diff --git a/vm/src/builtins/classmethod.rs b/vm/src/builtins/classmethod.rs index 058d9e704..58c3e37c6 100644 --- a/vm/src/builtins/classmethod.rs +++ b/vm/src/builtins/classmethod.rs @@ -1,7 +1,8 @@ use super::PyTypeRef; use crate::{ + builtins::PyBoundMethod, slots::{SlotConstructor, SlotDescriptor}, - PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol, VirtualMachine, + PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, VirtualMachine, }; /// classmethod(function) -> method @@ -51,7 +52,7 @@ impl SlotDescriptor for PyClassMethod { ) -> PyResult { let (zelf, obj) = Self::_unwrap(zelf, obj, vm)?; let cls = cls.unwrap_or_else(|| obj.clone_class().into()); - Ok(vm.ctx.new_bound_method(zelf.callable.clone(), cls)) + Ok(PyBoundMethod::new_ref(cls, zelf.callable.clone(), &vm.ctx).into()) } } @@ -63,6 +64,12 @@ impl SlotConstructor for PyClassMethod { } } +impl PyClassMethod { + pub fn new_ref(callable: PyObjectRef, ctx: &PyContext) -> PyRef { + PyRef::new_ref(Self { callable }, ctx.types.classmethod_type.clone(), None) + } +} + #[pyimpl(with(SlotDescriptor, SlotConstructor), flags(BASETYPE, HAS_DICT))] impl PyClassMethod { #[pyproperty(magic)] diff --git a/vm/src/builtins/function.rs b/vm/src/builtins/function.rs index fb282803a..a234b5782 100644 --- a/vm/src/builtins/function.rs +++ b/vm/src/builtins/function.rs @@ -408,7 +408,7 @@ impl SlotDescriptor for PyFunction { let obj = if vm.is_none(&obj) && !Self::_cls_is(&cls, &obj.class()) { zelf.into() } else { - vm.ctx.new_bound_method(zelf.into(), obj) + PyBoundMethod::new_ref(obj, zelf.into(), &vm.ctx).into() }; Ok(obj) } @@ -423,9 +423,8 @@ impl Callable for PyFunction { #[pyclass(module = false, name = "method")] #[derive(Debug)] pub struct PyBoundMethod { - // TODO: these shouldn't be public object: PyObjectRef, - pub function: PyObjectRef, + function: PyObjectRef, } impl Callable for PyBoundMethod { @@ -480,15 +479,25 @@ impl SlotConstructor for PyBoundMethod { } } +impl PyBoundMethod { + fn new(object: PyObjectRef, function: PyObjectRef) -> Self { + PyBoundMethod { object, function } + } + + pub fn new_ref(object: PyObjectRef, function: PyObjectRef, ctx: &PyContext) -> PyRef { + PyRef::new_ref( + Self::new(object, function), + ctx.types.bound_method_type.clone(), + None, + ) + } +} + #[pyimpl( with(Callable, Comparable, SlotGetattro, SlotConstructor), flags(HAS_DICT) )] impl PyBoundMethod { - pub fn new(object: PyObjectRef, function: PyObjectRef) -> Self { - PyBoundMethod { object, function } - } - #[pymethod(magic)] fn repr(&self, vm: &VirtualMachine) -> PyResult { let funcname = diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs index c56fa05e2..05651c766 100644 --- a/vm/src/builtins/pytype.rs +++ b/vm/src/builtins/pytype.rs @@ -595,12 +595,14 @@ impl PyType { if !attributes.contains_key("__dict__") { attributes.insert( "__dict__".to_owned(), - vm.ctx.new_getset( - "__dict__", - vm.ctx.types.object_type.clone(), - subtype_get_dict, - subtype_set_dict, - ), + vm.ctx + .new_getset( + "__dict__", + vm.ctx.types.object_type.clone(), + subtype_get_dict, + subtype_set_dict, + ) + .into(), ); } diff --git a/vm/src/builtins/staticmethod.rs b/vm/src/builtins/staticmethod.rs index a4c644995..db134098f 100644 --- a/vm/src/builtins/staticmethod.rs +++ b/vm/src/builtins/staticmethod.rs @@ -1,5 +1,6 @@ use super::{PyStr, PyTypeRef}; use crate::{ + builtins::builtinfunc::PyBuiltinMethod, function::IntoPyNativeFunc, slots::{SlotConstructor, SlotDescriptor}, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, VirtualMachine, @@ -53,7 +54,7 @@ impl PyStaticMethod { where F: IntoPyNativeFunc, { - let callable = ctx.new_method(name, class, f); + let callable = PyBuiltinMethod::new_ref(name, class, f, ctx).into(); PyRef::new_ref(Self { callable }, ctx.types.staticmethod_type.clone(), None) } } diff --git a/vm/src/codecs.rs b/vm/src/codecs.rs index 15c30afc4..7d1fbbfa2 100644 --- a/vm/src/codecs.rs +++ b/vm/src/codecs.rs @@ -173,7 +173,7 @@ impl CodecsRegistry { ), ]; let errors = std::array::IntoIter::new(errors) - .map(|(name, f)| (name.to_owned(), f)) + .map(|(name, f)| (name.to_owned(), f.into())) .collect(); let inner = RegistryInner { search_path: Vec::new(), diff --git a/vm/src/macros.rs b/vm/src/macros.rs index a653e960d..30d45003d 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -225,7 +225,7 @@ macro_rules! named_function { ) .into_function() .with_module(ctx.new_utf8_str(stringify!($module).to_owned())) - .build(ctx) + .into_ref(ctx) } }}; } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index ad39adf29..9233acb1a 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -6,7 +6,7 @@ use crate::common::{ pub use crate::pyobjectrc::{PyObject, PyObjectRef, PyObjectWeak, PyObjectWrap, PyRef, PyWeakRef}; use crate::{ builtins::{ - builtinfunc::PyNativeFuncDef, + builtinfunc::{PyBuiltinFunction, PyBuiltinMethod, PyNativeFuncDef}, bytearray, bytes, code::{self, PyCode}, getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetSet}, @@ -249,10 +249,6 @@ impl PyContext { create_type_with_slots(name, &self.types.type_type, base, slots) } - pub(crate) fn new_stringref(&self, s: String) -> pystr::PyStrRef { - PyRef::new_ref(pystr::PyStr::from(s), self.types.str_type.clone(), None) - } - #[inline] pub fn make_funcdef(&self, name: impl Into, f: F) -> PyNativeFuncDef where @@ -261,7 +257,8 @@ impl PyContext { PyNativeFuncDef::new(f.into_func(), PyStr::new_ref(name, self)) } - pub fn new_function(&self, name: impl Into, f: F) -> PyObjectRef + // #[deprecated] + pub fn new_function(&self, name: impl Into, f: F) -> PyRef where F: IntoPyNativeFunc, { @@ -273,23 +270,11 @@ impl PyContext { name: impl Into, class: PyTypeRef, f: F, - ) -> PyObjectRef + ) -> PyRef where F: IntoPyNativeFunc, { - self.make_funcdef(name, f).build_method(self, class) - } - - pub fn new_classmethod( - &self, - name: impl Into, - class: PyTypeRef, - f: F, - ) -> PyObjectRef - where - F: IntoPyNativeFunc, - { - self.make_funcdef(name, f).build_classmethod(self, class) + PyBuiltinMethod::new_ref(name, class, f, self) } pub fn new_readonly_getset( @@ -297,11 +282,11 @@ impl PyContext { name: impl Into, class: PyTypeRef, f: F, - ) -> PyObjectRef + ) -> PyRef where F: IntoPyGetterFunc, { - PyObject::new( + PyRef::new_ref( PyGetSet::new(name.into(), class).with_get(f), self.types.getset_type.clone(), None, @@ -314,12 +299,12 @@ impl PyContext { class: PyTypeRef, g: G, s: S, - ) -> PyObjectRef + ) -> PyRef where G: IntoPyGetterFunc, S: IntoPySetterFunc, { - PyObject::new( + PyRef::new_ref( PyGetSet::new(name.into(), class).with_get(g).with_set(s), self.types.getset_type.clone(), None, @@ -333,14 +318,6 @@ impl PyContext { PyRef::new_ref(PyCode::new(code), self.types.code_type.clone(), None) } - pub fn new_bound_method(&self, function: PyObjectRef, object: PyObjectRef) -> PyObjectRef { - PyObject::new( - PyBoundMethod::new(object, function), - self.types.bound_method_type.clone(), - None, - ) - } - pub fn new_base_object(&self, class: PyTypeRef, dict: Option) -> PyObjectRef { PyObject::new(object::PyBaseObject, class, dict) } @@ -960,7 +937,9 @@ pub trait PyClassImpl: PyClassDef { class.set_str_attr("__module__", ctx.new_utf8_str(module_name)); } if class.slots.new.load().is_some() { - let bound = ctx.new_bound_method(ctx.slot_new_wrapper.clone(), class.clone().into()); + let bound: PyObjectRef = + PyBoundMethod::new_ref(class.clone().into(), ctx.slot_new_wrapper.clone(), ctx) + .into(); class.set_str_attr("__new__", bound); } } diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index 450f46542..3f1035100 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -215,24 +215,26 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef { } } else if js_val.is_function() { let func = js_sys::Function::from(js_val); - vm.ctx.new_function( - func.name(), - move |args: FuncArgs, vm: &VirtualMachine| -> PyResult { - let this = Object::new(); - for (k, v) in args.kwargs { - Reflect::set(&this, &k.into(), &py_to_js(vm, v)) - .expect("property to be settable"); - } - let js_args = args - .args - .into_iter() - .map(|v| py_to_js(vm, v)) - .collect::(); - func.apply(&this, &js_args) - .map(|val| js_to_py(vm, val)) - .map_err(|err| js_err_to_py_err(vm, &err)) - }, - ) + vm.ctx + .new_function( + String::from(func.name()), + move |args: FuncArgs, vm: &VirtualMachine| -> PyResult { + let this = Object::new(); + for (k, v) in args.kwargs { + Reflect::set(&this, &k.into(), &py_to_js(vm, v)) + .expect("property to be settable"); + } + let js_args = args + .args + .into_iter() + .map(|v| py_to_js(vm, v)) + .collect::(); + func.apply(&this, &js_args) + .map(|val| js_to_py(vm, val)) + .map_err(|err| js_err_to_py_err(vm, &err)) + }, + ) + .into() } else if let Some(err) = js_val.dyn_ref::() { js_err_to_py_err(vm, err).into() } else if js_val.is_undefined() {