From 6c3e4819edae3bd028c88a1d023ec55c033d1d3b Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Sun, 20 Sep 2020 22:36:35 -0500 Subject: [PATCH 1/4] Rework native function creation a bit --- derive/src/pyclass.rs | 14 ++-- derive/src/pymodule.rs | 12 +++- vm/src/lib.rs | 5 ++ vm/src/macros.rs | 11 ++-- vm/src/obj/objbuiltinfunc.rs | 122 ++++++++++++++++++++++++++--------- vm/src/pyobject.rs | 43 +++++------- 6 files changed, 139 insertions(+), 68 deletions(-) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 8a1c84bc9..512dacd77 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -271,13 +271,19 @@ where let item_meta = MethodItemMeta::from_attr(ident.clone(), &item_attr)?; let py_name = item_meta.method_name()?; - let new_func = Ident::new(&format!("new_{}", &self.method_type), args.item.span()); + let build_func = Ident::new(&format!("build_{}", &self.method_type), args.item.span()); let tokens = { - let new_func = quote_spanned!( - ident.span() => .#new_func(Self::#ident) + let doc = args.attrs.doc().map_or_else( + TokenStream::new, + |doc| quote!(.with_doc(#doc.to_owned(), ctx)), ); quote! { - class.set_str_attr(#py_name, ctx#new_func); + class.set_str_attr( + #py_name, + ctx.new_function_named(Self::#ident, #py_name.to_owned()) + #doc + .#build_func(ctx), + ); } }; diff --git a/derive/src/pymodule.rs b/derive/src/pymodule.rs index 231b8b578..aa39c2b15 100644 --- a/derive/src/pymodule.rs +++ b/derive/src/pymodule.rs @@ -257,9 +257,17 @@ impl ModuleItem for FunctionItem { let py_name = item_meta.simple_name()?; let item = { + let doc = args.attrs.doc().map_or_else( + TokenStream::new, + |doc| quote!(.with_doc(#doc.to_owned(), &vm.ctx)), + ); let module = args.module_name(); - let new_func = quote_spanned!( - ident.span() => vm.ctx.new_function_named(#ident, #module.to_owned(), #py_name.to_owned()) + let new_func = quote_spanned!(ident.span()=> + vm.ctx.new_function_named(#ident, #py_name.to_owned()) + #doc + .into_function() + .with_module(vm.ctx.new_str(#module.to_owned())) + .build(&vm.ctx) ); quote! { vm.__module_set_attr(&module, #py_name, #new_func).unwrap(); diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 3354d7764..d99021e82 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -77,3 +77,8 @@ mod vm; pub use self::vm::{InitParameter, Interpreter, PySettings, VirtualMachine}; pub use rustpython_bytecode::*; pub use rustpython_common as common; + +#[doc(hidden)] +pub mod __exports { + pub use paste; +} diff --git a/vm/src/macros.rs b/vm/src/macros.rs index 37588ddb2..292dc674c 100644 --- a/vm/src/macros.rs +++ b/vm/src/macros.rs @@ -235,13 +235,16 @@ macro_rules! class_or_notimplemented { #[macro_export] macro_rules! named_function { ($ctx:expr, $module:ident, $func:ident) => {{ - paste::expr! { - $crate::pyobject::PyContext::new_function_named( - &$ctx, + #[allow(unused_variables)] // weird lint, something to do with paste probably + let ctx: &$crate::pyobject::PyContext = &$ctx; + $crate::__exports::paste::expr! { + ctx.new_function_named( [<$module _ $func>], stringify!($module).to_owned(), - stringify!($func).to_owned(), ) + .into_function() + .with_module(ctx.new_str(stringify!($func).to_owned())) + .build(ctx) } }}; } diff --git a/vm/src/obj/objbuiltinfunc.rs b/vm/src/obj/objbuiltinfunc.rs index be66d7193..238e086a7 100644 --- a/vm/src/obj/objbuiltinfunc.rs +++ b/vm/src/obj/objbuiltinfunc.rs @@ -1,17 +1,64 @@ use std::fmt; +use super::objclassmethod::PyClassMethod; use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc}; use crate::obj::objstr::PyStringRef; use crate::obj::objtype::PyClassRef; -use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol}; +use crate::pyobject::{ + PyClassImpl, PyContext, PyObject, PyObjectRef, PyResult, PyValue, TypeProtocol, +}; use crate::slots::{SlotCall, SlotDescriptor}; use crate::vm::VirtualMachine; +pub struct PyFuncDef { + pub func: PyNativeFunc, + pub name: Option, + pub doc: Option, +} + +impl From for PyFuncDef { + fn from(func: PyNativeFunc) -> Self { + Self { + func, + name: None, + doc: None, + } + } +} + +impl PyFuncDef { + pub fn with_doc(mut self, doc: String, ctx: &PyContext) -> Self { + self.doc = Some(ctx.new_stringref(doc)); + 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_method(self, ctx: &PyContext) -> PyObjectRef { + PyObject::new( + PyBuiltinMethod::from(self), + ctx.types.method_descriptor_type.clone(), + None, + ) + } + pub fn build_classmethod(self, ctx: &PyContext) -> PyObjectRef { + // TODO: classmethod_descriptor + PyObject::new( + PyClassMethod::from(self.build_method(ctx)), + ctx.types.classmethod_type.clone(), + None, + ) + } +} + #[pyclass(name = "builtin_function_or_method", module = false)] pub struct PyBuiltinFunction { - value: PyNativeFunc, - module: Option, - name: Option, + value: PyFuncDef, + module: Option, } impl PyValue for PyBuiltinFunction { @@ -28,49 +75,62 @@ impl fmt::Debug for PyBuiltinFunction { impl From for PyBuiltinFunction { fn from(value: PyNativeFunc) -> Self { + PyFuncDef::from(value).into() + } +} +impl From for PyBuiltinFunction { + fn from(value: PyFuncDef) -> Self { Self { value, module: None, - name: None, } } } impl PyBuiltinFunction { - pub fn new_with_name(value: PyNativeFunc, module: PyStringRef, name: PyStringRef) -> Self { - Self { - value, - module: Some(module), - name: Some(name), - } + pub fn with_module(mut self, module: PyObjectRef) -> Self { + self.module = Some(module); + self + } + + pub fn build(self, ctx: &PyContext) -> PyObjectRef { + PyObject::new( + self, + ctx.types.builtin_function_or_method_type.clone(), + None, + ) } pub fn as_func(&self) -> &PyNativeFunc { - &self.value + &self.value.func } } impl SlotCall for PyBuiltinFunction { fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { - (self.value)(vm, args) + (self.value.func)(vm, args) } } #[pyimpl(with(SlotCall), flags(HAS_DICT))] impl PyBuiltinFunction { #[pyproperty(magic)] - fn module(&self) -> Option { - self.module.clone() + fn module(&self, vm: &VirtualMachine) -> PyObjectRef { + vm.unwrap_or_none(self.module.clone()) } #[pyproperty(magic)] fn name(&self) -> Option { - self.name.clone() + self.value.name.clone() + } + #[pyproperty(magic)] + fn doc(&self) -> Option { + self.value.doc.clone() } } #[pyclass(module = false, name = "method_descriptor")] pub struct PyBuiltinMethod { - function: PyBuiltinFunction, + value: PyFuncDef, } impl PyValue for PyBuiltinMethod { @@ -85,23 +145,25 @@ impl fmt::Debug for PyBuiltinMethod { } } -impl From for PyBuiltinMethod { - fn from(value: PyNativeFunc) -> Self { - Self { - function: value.into(), - } +impl From for PyBuiltinMethod { + fn from(value: PyFuncDef) -> Self { + Self { value } } } impl PyBuiltinMethod { - pub fn new_with_name(value: PyNativeFunc, module: PyStringRef, name: PyStringRef) -> Self { + pub fn new_with_name(func: PyNativeFunc, name: PyStringRef) -> Self { Self { - function: PyBuiltinFunction::new_with_name(value, module, name), + value: PyFuncDef { + func, + name: Some(name), + doc: None, + }, } } pub fn as_func(&self) -> &PyNativeFunc { - &self.function.value + &self.value.func } } @@ -126,19 +188,19 @@ impl SlotDescriptor for PyBuiltinMethod { impl SlotCall for PyBuiltinMethod { fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { - (self.function.value)(vm, args) + (self.value.func)(vm, args) } } #[pyimpl(with(SlotDescriptor, SlotCall))] impl PyBuiltinMethod { #[pyproperty(magic)] - fn module(&self) -> Option { - self.function.module.clone() + fn name(&self) -> Option { + self.value.name.clone() } #[pyproperty(magic)] - fn name(&self) -> Option { - self.function.name.clone() + fn doc(&self) -> Option { + self.value.doc.clone() } } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index a304f0627..378febc1a 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -12,10 +12,9 @@ use num_traits::ToPrimitive; use crate::bytecode; use crate::exceptions::{self, PyBaseExceptionRef}; use crate::function::{IntoPyNativeFunc, PyFuncArgs}; -use crate::obj::objbuiltinfunc::{PyBuiltinFunction, PyBuiltinMethod}; +use crate::obj::objbuiltinfunc::PyFuncDef; use crate::obj::objbytearray; use crate::obj::objbytes; -use crate::obj::objclassmethod::PyClassMethod; use crate::obj::objcode; use crate::obj::objcode::PyCodeRef; use crate::obj::objcomplex::PyComplex; @@ -141,7 +140,7 @@ impl PyContext { let empty_tuple = create_object(PyTuple::from(vec![]), &types.tuple_type); let tp_new_wrapper = create_object( - PyBuiltinFunction::from(objtype::tp_new_wrapper.into_func()), + PyFuncDef::from(objtype::tp_new_wrapper.into_func()).into_function(), &types.builtin_function_or_method_type, ) .into_object(); @@ -213,9 +212,9 @@ impl PyContext { pub fn new_str(&self, s: S) -> PyObjectRef where - objstr::PyString: std::convert::From, + S: Into, { - PyObject::new(objstr::PyString::from(s), self.types.str_type.clone(), None) + PyObject::new(s.into(), self.types.str_type.clone(), None) } pub fn new_bytes(&self, data: Vec) -> PyObjectRef { @@ -284,46 +283,34 @@ impl PyContext { where F: IntoPyNativeFunc, { - PyObject::new( - PyBuiltinFunction::from(f.into_func()), - self.types.builtin_function_or_method_type.clone(), - None, - ) + PyFuncDef::from(f.into_func()).build_function(self) } - pub fn new_function_named(&self, f: F, module: String, name: String) -> PyObjectRef + pub(crate) fn new_stringref(&self, s: String) -> objstr::PyStringRef { + PyRef::new_ref(objstr::PyString::from(s), self.types.str_type.clone(), None) + } + + pub fn new_function_named(&self, f: F, name: String) -> PyFuncDef where F: IntoPyNativeFunc, { - let stringref = - |s| PyRef::new_ref(objstr::PyString::from(s), self.types.str_type.clone(), None); - PyObject::new( - PyBuiltinFunction::new_with_name(f.into_func(), stringref(module), stringref(name)), - self.types.builtin_function_or_method_type.clone(), - None, - ) + let mut f = PyFuncDef::from(f.into_func()); + f.name = Some(self.new_stringref(name)); + f } pub fn new_method(&self, f: F) -> PyObjectRef where F: IntoPyNativeFunc, { - PyObject::new( - PyBuiltinMethod::from(f.into_func()), - self.types.method_descriptor_type.clone(), - None, - ) + PyFuncDef::from(f.into_func()).build_method(self) } pub fn new_classmethod(&self, f: F) -> PyObjectRef where F: IntoPyNativeFunc, { - PyObject::new( - PyClassMethod::from(self.new_method(f)), - self.types.classmethod_type.clone(), - None, - ) + PyFuncDef::from(f.into_func()).build_classmethod(self) } pub fn new_staticmethod(&self, f: F) -> PyObjectRef where From ca5f2da9e90f5ce75b38b5f07702d2620948603a Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Mon, 21 Sep 2020 10:32:25 -0500 Subject: [PATCH 2/4] Make more builtin functions be named --- vm/src/stdlib/csv.rs | 4 +- vm/src/stdlib/hashlib.rs | 530 +++++++++++++++++------------------ vm/src/stdlib/imp.rs | 60 ++-- vm/src/stdlib/io.rs | 10 +- vm/src/stdlib/math.rs | 92 +++--- vm/src/stdlib/msvcrt.rs | 18 +- vm/src/stdlib/operator.rs | 9 +- vm/src/stdlib/thread.rs | 24 +- vm/src/stdlib/time_module.rs | 22 +- vm/src/stdlib/winreg.rs | 14 +- vm/src/sysmodule.rs | 45 +-- 11 files changed, 413 insertions(+), 415 deletions(-) diff --git a/vm/src/stdlib/csv.rs b/vm/src/stdlib/csv.rs index 81167f1bf..c15895f79 100644 --- a/vm/src/stdlib/csv.rs +++ b/vm/src/stdlib/csv.rs @@ -186,7 +186,7 @@ impl Reader { } } -fn csv_reader(fp: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { +fn _csv_reader(fp: PyObjectRef, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { if let Ok(iterable) = PyIterable::::try_from_object(vm, fp) { build_reader(iterable, args, vm) } else { @@ -206,7 +206,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { ); py_module!(vm, "_csv", { - "reader" => ctx.new_function(csv_reader), + "reader" => named_function!(ctx, _csv, reader), "Reader" => reader_type, "Error" => error, // constants diff --git a/vm/src/stdlib/hashlib.rs b/vm/src/stdlib/hashlib.rs index 49233f1e4..bb23e646d 100644 --- a/vm/src/stdlib/hashlib.rs +++ b/vm/src/stdlib/hashlib.rs @@ -1,290 +1,286 @@ -use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; -use crate::function::{OptionalArg, PyFuncArgs}; -use crate::obj::objbytes::{PyBytes, PyBytesRef}; -use crate::obj::objstr::PyStringRef; -use crate::obj::objtype::PyClassRef; -use crate::pyobject::{BorrowValue, PyClassImpl, PyObjectRef, PyResult, PyValue}; -use crate::vm::VirtualMachine; -use std::fmt; +pub(crate) use hashlib::make_module; -use blake2::{Blake2b, Blake2s}; -use digest::DynDigest; -use md5::Md5; -use sha1::Sha1; -use sha2::{Sha224, Sha256, Sha384, Sha512}; -use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; // TODO: , Shake128, Shake256}; +#[pymodule] +mod hashlib { + use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; + use crate::function::{OptionalArg, PyFuncArgs}; + use crate::obj::objbytes::{PyBytes, PyBytesRef}; + use crate::obj::objstr::PyStringRef; + use crate::obj::objtype::PyClassRef; + use crate::pyobject::{BorrowValue, PyClassImpl, PyResult, PyValue}; + use crate::vm::VirtualMachine; + use std::fmt; -#[pyclass(module = "hashlib", name = "hasher")] -struct PyHasher { - name: String, - buffer: PyRwLock, -} + use blake2::{Blake2b, Blake2s}; + use digest::DynDigest; + use md5::Md5; + use sha1::Sha1; + use sha2::{Sha224, Sha256, Sha384, Sha512}; + use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; // TODO: , Shake128, Shake256}; -impl fmt::Debug for PyHasher { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "hasher {}", self.name) + #[pyattr] + #[pyclass(module = "hashlib", name = "hasher")] + struct PyHasher { + name: String, + buffer: PyRwLock, } -} -impl PyValue for PyHasher { - fn class(vm: &VirtualMachine) -> PyClassRef { - vm.class("hashlib", "hasher") - } -} - -#[pyimpl] -impl PyHasher { - fn new(name: &str, d: HashWrapper) -> Self { - PyHasher { - name: name.to_owned(), - buffer: PyRwLock::new(d), + impl fmt::Debug for PyHasher { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "hasher {}", self.name) } } - fn borrow_value(&self) -> PyRwLockReadGuard<'_, HashWrapper> { - self.buffer.read() + impl PyValue for PyHasher { + fn class(vm: &VirtualMachine) -> PyClassRef { + vm.class("hashlib", "hasher") + } } - fn borrow_value_mut(&self) -> PyRwLockWriteGuard<'_, HashWrapper> { - self.buffer.write() - } - - #[pyslot] - fn tp_new(_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { - Ok(PyHasher::new("md5", HashWrapper::md5()) - .into_ref(vm) - .into_object()) - } - - #[pyproperty(name = "name")] - fn name(&self) -> String { - self.name.clone() - } - - #[pyproperty(name = "digest_size")] - fn digest_size(&self, vm: &VirtualMachine) -> PyResult { - Ok(vm.ctx.new_int(self.borrow_value().digest_size())) - } - - #[pymethod(name = "update")] - fn update(&self, data: PyBytesRef) { - self.borrow_value_mut().input(data.borrow_value()); - } - - #[pymethod(name = "digest")] - fn digest(&self) -> PyBytes { - self.get_digest().into() - } - - #[pymethod(name = "hexdigest")] - fn hexdigest(&self) -> String { - let result = self.get_digest(); - hex::encode(result) - } - - fn get_digest(&self) -> Vec { - self.borrow_value().get_digest() - } -} - -fn hashlib_new( - name: PyStringRef, - data: OptionalArg, - vm: &VirtualMachine, -) -> PyResult { - match name.borrow_value() { - "md5" => md5(data), - "sha1" => sha1(data), - "sha224" => sha224(data), - "sha256" => sha256(data), - "sha384" => sha384(data), - "sha512" => sha512(data), - "sha3_224" => sha3_224(data), - "sha3_256" => sha3_256(data), - "sha3_384" => sha3_384(data), - "sha3_512" => sha3_512(data), - // TODO: "shake128" => shake128(data, ), - // TODO: "shake256" => shake256(data, ), - "blake2b" => blake2b(data), - "blake2s" => blake2s(data), - other => Err(vm.new_value_error(format!("Unknown hashing algorithm: {}", other))), - } -} - -fn init(hasher: PyHasher, data: OptionalArg) -> PyResult { - if let OptionalArg::Present(data) = data { - hasher.update(data); - } - - Ok(hasher) -} - -fn md5(data: OptionalArg) -> PyResult { - init(PyHasher::new("md5", HashWrapper::md5()), data) -} - -fn sha1(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha1", HashWrapper::sha1()), data) -} - -fn sha224(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha224", HashWrapper::sha224()), data) -} - -fn sha256(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha256", HashWrapper::sha256()), data) -} - -fn sha384(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha384", HashWrapper::sha384()), data) -} - -fn sha512(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha512", HashWrapper::sha512()), data) -} - -fn sha3_224(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha3_224", HashWrapper::sha3_224()), data) -} - -fn sha3_256(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha3_256", HashWrapper::sha3_256()), data) -} - -fn sha3_384(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha3_384", HashWrapper::sha3_384()), data) -} - -fn sha3_512(data: OptionalArg) -> PyResult { - init(PyHasher::new("sha3_512", HashWrapper::sha3_512()), data) -} - -fn shake128(_data: OptionalArg, vm: &VirtualMachine) -> PyResult { - Err(vm.new_not_implemented_error("shake256".to_owned())) -} - -fn shake256(_data: OptionalArg, vm: &VirtualMachine) -> PyResult { - Err(vm.new_not_implemented_error("shake256".to_owned())) -} - -fn blake2b(data: OptionalArg) -> PyResult { - // TODO: handle parameters - init(PyHasher::new("blake2b", HashWrapper::blake2b()), data) -} - -fn blake2s(data: OptionalArg) -> PyResult { - // TODO: handle parameters - init(PyHasher::new("blake2s", HashWrapper::blake2s()), data) -} - -pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { - let ctx = &vm.ctx; - - let hasher_type = PyHasher::make_class(ctx); - - py_module!(vm, "hashlib", { - "new" => ctx.new_function(hashlib_new), - "md5" => ctx.new_function(md5), - "sha1" => ctx.new_function(sha1), - "sha224" => ctx.new_function(sha224), - "sha256" => ctx.new_function(sha256), - "sha384" => ctx.new_function(sha384), - "sha512" => ctx.new_function(sha512), - "sha3_224" => ctx.new_function(sha3_224), - "sha3_256" => ctx.new_function(sha3_256), - "sha3_384" => ctx.new_function(sha3_384), - "sha3_512" => ctx.new_function(sha3_512), - "shake128" => ctx.new_function(shake128), - "shake256" => ctx.new_function(shake256), - "blake2b" => ctx.new_function(blake2b), - "blake2s" => ctx.new_function(blake2s), - "hasher" => hasher_type, - }) -} - -trait ThreadSafeDynDigest: DynDigest + Sync + Send {} -impl ThreadSafeDynDigest for T where T: DynDigest + Sync + Send {} - -/// Generic wrapper patching around the hashing libraries. -struct HashWrapper { - inner: Box, -} - -impl HashWrapper { - fn new(d: D) -> Self - where - D: ThreadSafeDynDigest, - { - HashWrapper { inner: Box::new(d) } - } - - fn md5() -> Self { - Self::new(Md5::default()) - } - - fn sha1() -> Self { - Self::new(Sha1::default()) - } - - fn sha224() -> Self { - Self::new(Sha224::default()) - } - - fn sha256() -> Self { - Self::new(Sha256::default()) - } - - fn sha384() -> Self { - Self::new(Sha384::default()) - } - - fn sha512() -> Self { - Self::new(Sha512::default()) - } - - fn sha3_224() -> Self { - Self::new(Sha3_224::default()) - } - - fn sha3_256() -> Self { - Self::new(Sha3_256::default()) - } - - fn sha3_384() -> Self { - Self::new(Sha3_384::default()) - } - - fn sha3_512() -> Self { - Self::new(Sha3_512::default()) - } - - /* TODO: - fn shake128() -> Self { - Self::new(Shake128::default()) + #[pyimpl] + impl PyHasher { + fn new(name: &str, d: HashWrapper) -> Self { + PyHasher { + name: name.to_owned(), + buffer: PyRwLock::new(d), + } } - fn shake256() -> Self { - Self::new(Shake256::default()) + fn borrow_value(&self) -> PyRwLockReadGuard<'_, HashWrapper> { + self.buffer.read() + } + + fn borrow_value_mut(&self) -> PyRwLockWriteGuard<'_, HashWrapper> { + self.buffer.write() + } + + #[pyslot] + fn tp_new(_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult { + Ok(PyHasher::new("md5", HashWrapper::md5()) + .into_ref(vm) + .into_object()) + } + + #[pyproperty(name = "name")] + fn name(&self) -> String { + self.name.clone() + } + + #[pyproperty(name = "digest_size")] + fn digest_size(&self, vm: &VirtualMachine) -> PyResult { + Ok(vm.ctx.new_int(self.borrow_value().digest_size())) + } + + #[pymethod(name = "update")] + fn update(&self, data: PyBytesRef) { + self.borrow_value_mut().input(data.borrow_value()); + } + + #[pymethod(name = "digest")] + fn digest(&self) -> PyBytes { + self.get_digest().into() + } + + #[pymethod(name = "hexdigest")] + fn hexdigest(&self) -> String { + let result = self.get_digest(); + hex::encode(result) + } + + fn get_digest(&self) -> Vec { + self.borrow_value().get_digest() } - */ - fn blake2b() -> Self { - Self::new(Blake2b::default()) } - fn blake2s() -> Self { - Self::new(Blake2s::default()) + #[pyfunction(name = "new")] + fn hashlib_new( + name: PyStringRef, + data: OptionalArg, + vm: &VirtualMachine, + ) -> PyResult { + match name.borrow_value() { + "md5" => md5(data), + "sha1" => sha1(data), + "sha224" => sha224(data), + "sha256" => sha256(data), + "sha384" => sha384(data), + "sha512" => sha512(data), + "sha3_224" => sha3_224(data), + "sha3_256" => sha3_256(data), + "sha3_384" => sha3_384(data), + "sha3_512" => sha3_512(data), + // TODO: "shake128" => shake128(data, ), + // TODO: "shake256" => shake256(data, ), + "blake2b" => blake2b(data), + "blake2s" => blake2s(data), + other => Err(vm.new_value_error(format!("Unknown hashing algorithm: {}", other))), + } } - fn input(&mut self, data: &[u8]) { - self.inner.input(data); + fn init(hasher: PyHasher, data: OptionalArg) -> PyResult { + if let OptionalArg::Present(data) = data { + hasher.update(data); + } + + Ok(hasher) } - fn digest_size(&self) -> usize { - self.inner.output_size() + #[pyfunction] + fn md5(data: OptionalArg) -> PyResult { + init(PyHasher::new("md5", HashWrapper::md5()), data) } - fn get_digest(&self) -> Vec { - let cloned = self.inner.box_clone(); - cloned.result().to_vec() + #[pyfunction] + fn sha1(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha1", HashWrapper::sha1()), data) + } + + #[pyfunction] + fn sha224(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha224", HashWrapper::sha224()), data) + } + + #[pyfunction] + fn sha256(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha256", HashWrapper::sha256()), data) + } + + #[pyfunction] + fn sha384(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha384", HashWrapper::sha384()), data) + } + + #[pyfunction] + fn sha512(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha512", HashWrapper::sha512()), data) + } + + #[pyfunction] + fn sha3_224(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha3_224", HashWrapper::sha3_224()), data) + } + + #[pyfunction] + fn sha3_256(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha3_256", HashWrapper::sha3_256()), data) + } + + #[pyfunction] + fn sha3_384(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha3_384", HashWrapper::sha3_384()), data) + } + + #[pyfunction] + fn sha3_512(data: OptionalArg) -> PyResult { + init(PyHasher::new("sha3_512", HashWrapper::sha3_512()), data) + } + + #[pyfunction] + fn shake128(_data: OptionalArg, vm: &VirtualMachine) -> PyResult { + Err(vm.new_not_implemented_error("shake256".to_owned())) + } + + #[pyfunction] + fn shake256(_data: OptionalArg, vm: &VirtualMachine) -> PyResult { + Err(vm.new_not_implemented_error("shake256".to_owned())) + } + + #[pyfunction] + fn blake2b(data: OptionalArg) -> PyResult { + // TODO: handle parameters + init(PyHasher::new("blake2b", HashWrapper::blake2b()), data) + } + + #[pyfunction] + fn blake2s(data: OptionalArg) -> PyResult { + // TODO: handle parameters + init(PyHasher::new("blake2s", HashWrapper::blake2s()), data) + } + + trait ThreadSafeDynDigest: DynDigest + Sync + Send {} + impl ThreadSafeDynDigest for T where T: DynDigest + Sync + Send {} + + /// Generic wrapper patching around the hashing libraries. + struct HashWrapper { + inner: Box, + } + + impl HashWrapper { + fn new(d: D) -> Self + where + D: ThreadSafeDynDigest, + { + HashWrapper { inner: Box::new(d) } + } + + fn md5() -> Self { + Self::new(Md5::default()) + } + + fn sha1() -> Self { + Self::new(Sha1::default()) + } + + fn sha224() -> Self { + Self::new(Sha224::default()) + } + + fn sha256() -> Self { + Self::new(Sha256::default()) + } + + fn sha384() -> Self { + Self::new(Sha384::default()) + } + + fn sha512() -> Self { + Self::new(Sha512::default()) + } + + fn sha3_224() -> Self { + Self::new(Sha3_224::default()) + } + + fn sha3_256() -> Self { + Self::new(Sha3_256::default()) + } + + fn sha3_384() -> Self { + Self::new(Sha3_384::default()) + } + + fn sha3_512() -> Self { + Self::new(Sha3_512::default()) + } + + /* TODO: + fn shake128() -> Self { + Self::new(Shake128::default()) + } + + fn shake256() -> Self { + Self::new(Shake256::default()) + } + */ + fn blake2b() -> Self { + Self::new(Blake2b::default()) + } + + fn blake2s() -> Self { + Self::new(Blake2s::default()) + } + + fn input(&mut self, data: &[u8]) { + self.inner.input(data); + } + + fn digest_size(&self) -> usize { + self.inner.output_size() + } + + fn get_digest(&self) -> Vec { + let cloned = self.inner.box_clone(); + cloned.result().to_vec() + } } } diff --git a/vm/src/stdlib/imp.rs b/vm/src/stdlib/imp.rs index ac5fb4cdb..78fe259c1 100644 --- a/vm/src/stdlib/imp.rs +++ b/vm/src/stdlib/imp.rs @@ -15,11 +15,11 @@ mod lock { pub(super) static IMP_LOCK: RawRMutex = RawRMutex::INIT; - pub(super) fn imp_acquire_lock(_vm: &VirtualMachine) { + pub(super) fn _imp_acquire_lock(_vm: &VirtualMachine) { IMP_LOCK.lock() } - pub(super) fn imp_release_lock(vm: &VirtualMachine) -> PyResult<()> { + pub(super) fn _imp_release_lock(vm: &VirtualMachine) -> PyResult<()> { if !IMP_LOCK.is_locked() { Err(vm.new_runtime_error("Global import lock not held".to_owned())) } else { @@ -28,7 +28,7 @@ mod lock { } } - pub(super) fn imp_lock_held(_vm: &VirtualMachine) -> bool { + pub(super) fn _imp_lock_held(_vm: &VirtualMachine) -> bool { IMP_LOCK.is_locked() } } @@ -36,28 +36,28 @@ mod lock { #[cfg(not(feature = "threading"))] mod lock { use crate::vm::VirtualMachine; - pub(super) fn imp_acquire_lock(_vm: &VirtualMachine) {} - pub(super) fn imp_release_lock(_vm: &VirtualMachine) {} - pub(super) fn imp_lock_held(_vm: &VirtualMachine) -> bool { + pub(super) fn _imp_acquire_lock(_vm: &VirtualMachine) {} + pub(super) fn _imp_release_lock(_vm: &VirtualMachine) {} + pub(super) fn _imp_lock_held(_vm: &VirtualMachine) -> bool { false } } -use lock::{imp_acquire_lock, imp_lock_held, imp_release_lock}; +use lock::{_imp_acquire_lock, _imp_lock_held, _imp_release_lock}; -fn imp_extension_suffixes(vm: &VirtualMachine) -> PyResult { +fn _imp_extension_suffixes(vm: &VirtualMachine) -> PyResult { Ok(vm.ctx.new_list(vec![])) } -fn imp_is_builtin(name: PyStringRef, vm: &VirtualMachine) -> bool { +fn _imp_is_builtin(name: PyStringRef, vm: &VirtualMachine) -> bool { vm.state.stdlib_inits.contains_key(name.borrow_value()) } -fn imp_is_frozen(name: PyStringRef, vm: &VirtualMachine) -> bool { +fn _imp_is_frozen(name: PyStringRef, vm: &VirtualMachine) -> bool { vm.state.frozen.contains_key(name.borrow_value()) } -fn imp_create_builtin(spec: PyObjectRef, vm: &VirtualMachine) -> PyResult { +fn _imp_create_builtin(spec: PyObjectRef, vm: &VirtualMachine) -> PyResult { let sys_modules = vm.get_attribute(vm.sys_module.clone(), "modules").unwrap(); let spec = vm.get_attribute(spec, "name")?; let name = objstr::borrow_value(&spec); @@ -71,12 +71,12 @@ fn imp_create_builtin(spec: PyObjectRef, vm: &VirtualMachine) -> PyResult { } } -fn imp_exec_builtin(_mod: PyModuleRef) -> i32 { +fn _imp_exec_builtin(_mod: PyModuleRef) -> i32 { // TOOD: Should we do something here? 0 } -fn imp_get_frozen_object(name: PyStringRef, vm: &VirtualMachine) -> PyResult { +fn _imp_get_frozen_object(name: PyStringRef, vm: &VirtualMachine) -> PyResult { let name = name.borrow_value(); vm.state .frozen @@ -89,11 +89,11 @@ fn imp_get_frozen_object(name: PyStringRef, vm: &VirtualMachine) -> PyResult PyResult { +fn _imp_init_frozen(name: PyStringRef, vm: &VirtualMachine) -> PyResult { import::import_frozen(vm, name.borrow_value()) } -fn imp_is_frozen_package(name: PyStringRef, vm: &VirtualMachine) -> PyResult { +fn _imp_is_frozen_package(name: PyStringRef, vm: &VirtualMachine) -> PyResult { let name = name.borrow_value(); vm.state .frozen @@ -102,11 +102,11 @@ fn imp_is_frozen_package(name: PyStringRef, vm: &VirtualMachine) -> PyResult PyResult { +fn _imp_source_hash(_key: u64, _source: PyBytesRef, vm: &VirtualMachine) -> PyResult { // TODO: Ok(vm.ctx.none()) } @@ -114,18 +114,18 @@ fn imp_source_hash(_key: u64, _source: PyBytesRef, vm: &VirtualMachine) -> PyRes pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; py_module!(vm, "_imp", { - "extension_suffixes" => ctx.new_function(imp_extension_suffixes), - "acquire_lock" => ctx.new_function(imp_acquire_lock), - "release_lock" => ctx.new_function(imp_release_lock), - "lock_held" => ctx.new_function(imp_lock_held), - "is_builtin" => ctx.new_function(imp_is_builtin), - "is_frozen" => ctx.new_function(imp_is_frozen), - "create_builtin" => ctx.new_function(imp_create_builtin), - "exec_builtin" => ctx.new_function(imp_exec_builtin), - "get_frozen_object" => ctx.new_function(imp_get_frozen_object), - "init_frozen" => ctx.new_function(imp_init_frozen), - "is_frozen_package" => ctx.new_function(imp_is_frozen_package), - "_fix_co_filename" => ctx.new_function(imp_fix_co_filename), - "source_hash" => ctx.new_function(imp_source_hash) + "extension_suffixes" => named_function!(ctx, _imp, extension_suffixes), + "acquire_lock" => named_function!(ctx, _imp, acquire_lock), + "release_lock" => named_function!(ctx, _imp, release_lock), + "lock_held" => named_function!(ctx, _imp, lock_held), + "is_builtin" => named_function!(ctx, _imp, is_builtin), + "is_frozen" => named_function!(ctx, _imp, is_frozen), + "create_builtin" => named_function!(ctx, _imp, create_builtin), + "exec_builtin" => named_function!(ctx, _imp, exec_builtin), + "get_frozen_object" => named_function!(ctx, _imp, get_frozen_object), + "init_frozen" => named_function!(ctx, _imp, init_frozen), + "is_frozen_package" => named_function!(ctx, _imp, is_frozen_package), + "_fix_co_filename" => named_function!(ctx, _imp, fix_co_filename), + "source_hash" => named_function!(ctx, _imp, source_hash), }) } diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index fc34d0317..1fc368510 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -1139,7 +1139,7 @@ fn split_mode_string(mode_string: &str) -> Result<(String, String), String> { Ok((mode, typ.to_string())) } -fn io_open_wrapper( +fn _io_open( file: PyObjectRef, mode: OptionalArg, opts: OpenArgs, @@ -1152,9 +1152,9 @@ fn io_open_wrapper( vm, ) } -fn io_open_code(file: PyObjectRef, vm: &VirtualMachine) -> PyResult { +fn _io_open_code(file: PyObjectRef, vm: &VirtualMachine) -> PyResult { // TODO: lifecycle hooks or something? - io_open(file, Some("rb"), Default::default(), vm) + io_open(file, Some("rb"), OpenArgs::default(), vm) } #[derive(FromArgs)] @@ -1368,8 +1368,8 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { }); let module = py_module!(vm, "_io", { - "open" => ctx.new_function(io_open_wrapper), - "open_code" => ctx.new_function(io_open_code), + "open" => named_function!(ctx, _io, open), + "open_code" => named_function!(ctx, _io, open_code), "_IOBase" => io_base, "_RawIOBase" => raw_io_base.clone(), "_BufferedIOBase" => buffered_io_base, diff --git a/vm/src/stdlib/math.rs b/vm/src/stdlib/math.rs index 5e0fbba22..c0eb1567d 100644 --- a/vm/src/stdlib/math.rs +++ b/vm/src/stdlib/math.rs @@ -404,69 +404,69 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { py_module!(vm, "math", { // Number theory functions: - "fabs" => ctx.new_function(math_fabs), - "isfinite" => ctx.new_function(math_isfinite), - "isinf" => ctx.new_function(math_isinf), - "isnan" => ctx.new_function(math_isnan), - "isclose" => ctx.new_function(math_isclose), - "copysign" => ctx.new_function(math_copysign), + "fabs" => named_function!(ctx, math, fabs), + "isfinite" => named_function!(ctx, math, isfinite), + "isinf" => named_function!(ctx, math, isinf), + "isnan" => named_function!(ctx, math, isnan), + "isclose" => named_function!(ctx, math, isclose), + "copysign" => named_function!(ctx, math, copysign), // Power and logarithmic functions: - "exp" => ctx.new_function(math_exp), - "expm1" => ctx.new_function(math_expm1), - "log" => ctx.new_function(math_log), - "log1p" => ctx.new_function(math_log1p), - "log2" => ctx.new_function(math_log2), - "log10" => ctx.new_function(math_log10), - "pow" => ctx.new_function(math_pow), - "sqrt" => ctx.new_function(math_sqrt), + "exp" => named_function!(ctx, math, exp), + "expm1" => named_function!(ctx, math, expm1), + "log" => named_function!(ctx, math, log), + "log1p" => named_function!(ctx, math, log1p), + "log2" => named_function!(ctx, math, log2), + "log10" => named_function!(ctx, math, log10), + "pow" => named_function!(ctx, math, pow), + "sqrt" => named_function!(ctx, math, sqrt), // Trigonometric functions: - "acos" => ctx.new_function(math_acos), - "asin" => ctx.new_function(math_asin), - "atan" => ctx.new_function(math_atan), - "atan2" => ctx.new_function(math_atan2), - "cos" => ctx.new_function(math_cos), - "hypot" => ctx.new_function(math_hypot), - "sin" => ctx.new_function(math_sin), - "tan" => ctx.new_function(math_tan), + "acos" => named_function!(ctx, math, acos), + "asin" => named_function!(ctx, math, asin), + "atan" => named_function!(ctx, math, atan), + "atan2" => named_function!(ctx, math, atan2), + "cos" => named_function!(ctx, math, cos), + "hypot" => named_function!(ctx, math, hypot), + "sin" => named_function!(ctx, math, sin), + "tan" => named_function!(ctx, math, tan), - "degrees" => ctx.new_function(math_degrees), - "radians" => ctx.new_function(math_radians), + "degrees" => named_function!(ctx, math, degrees), + "radians" => named_function!(ctx, math, radians), // Hyperbolic functions: - "acosh" => ctx.new_function(math_acosh), - "asinh" => ctx.new_function(math_asinh), - "atanh" => ctx.new_function(math_atanh), - "cosh" => ctx.new_function(math_cosh), - "sinh" => ctx.new_function(math_sinh), - "tanh" => ctx.new_function(math_tanh), + "acosh" => named_function!(ctx, math, acosh), + "asinh" => named_function!(ctx, math, asinh), + "atanh" => named_function!(ctx, math, atanh), + "cosh" => named_function!(ctx, math, cosh), + "sinh" => named_function!(ctx, math, sinh), + "tanh" => named_function!(ctx, math, tanh), // Special functions: - "erf" => ctx.new_function(math_erf), - "erfc" => ctx.new_function(math_erfc), - "gamma" => ctx.new_function(math_gamma), - "lgamma" => ctx.new_function(math_lgamma), + "erf" => named_function!(ctx, math, erf), + "erfc" => named_function!(ctx, math, erfc), + "gamma" => named_function!(ctx, math, gamma), + "lgamma" => named_function!(ctx, math, lgamma), - "frexp" => ctx.new_function(math_frexp), - "ldexp" => ctx.new_function(math_ldexp), - "modf" => ctx.new_function(math_modf), - "fmod" => ctx.new_function(math_fmod), - "remainder" => ctx.new_function(math_remainder), + "frexp" => named_function!(ctx, math, frexp), + "ldexp" => named_function!(ctx, math, ldexp), + "modf" => named_function!(ctx, math, modf), + "fmod" => named_function!(ctx, math, fmod), + "remainder" => named_function!(ctx, math, remainder), // Rounding functions: - "trunc" => ctx.new_function(math_trunc), - "ceil" => ctx.new_function(math_ceil), - "floor" => ctx.new_function(math_floor), + "trunc" => named_function!(ctx, math, trunc), + "ceil" => named_function!(ctx, math, ceil), + "floor" => named_function!(ctx, math, floor), // Gcd function - "gcd" => ctx.new_function(math_gcd), - "lcm" => ctx.new_function(math_lcm), + "gcd" => named_function!(ctx, math, gcd), + "lcm" => named_function!(ctx, math, lcm), // Factorial function - "factorial" => ctx.new_function(math_factorial), + "factorial" => named_function!(ctx, math, factorial), - "nextafter" => ctx.new_function(math_nextafter), + "nextafter" => named_function!(ctx, math, nextafter), // Constants: "pi" => ctx.new_float(std::f64::consts::PI), // 3.14159... diff --git a/vm/src/stdlib/msvcrt.rs b/vm/src/stdlib/msvcrt.rs index fcd3aa064..eacfaa51c 100644 --- a/vm/src/stdlib/msvcrt.rs +++ b/vm/src/stdlib/msvcrt.rs @@ -86,15 +86,15 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; py_module!(vm, "msvcrt", { - "getch" => ctx.new_function(msvcrt_getch), - "getwch" => ctx.new_function(msvcrt_getwch), - "getche" => ctx.new_function(msvcrt_getche), - "getwche" => ctx.new_function(msvcrt_getwche), - "putch" => ctx.new_function(msvcrt_putch), - "putwch" => ctx.new_function(msvcrt_putwch), - "setmode" => ctx.new_function(msvcrt_setmode), - "open_osfhandle" => ctx.new_function(msvcrt_open_osfhandle), - "SetErrorMode" => ctx.new_function(msvcrt_seterrormode), + "getch" => named_function!(ctx, msvcrt, getch), + "getwch" => named_function!(ctx, msvcrt, getwch), + "getche" => named_function!(ctx, msvcrt, getche), + "getwche" => named_function!(ctx, msvcrt, getwche), + "putch" => named_function!(ctx, msvcrt, putch), + "putwch" => named_function!(ctx, msvcrt, putwch), + "setmode" => named_function!(ctx, msvcrt, setmode), + "open_osfhandle" => named_function!(ctx, msvcrt, open_osfhandle), + "SetErrorMode" => named_function!(ctx, msvcrt, seterrormode), "SEM_FAILCRITICALERRORS" => ctx.new_int(SEM_FAILCRITICALERRORS), "SEM_NOALIGNMENTFAULTEXCEPT" => ctx.new_int(SEM_NOALIGNMENTFAULTEXCEPT), "SEM_NOGPFAULTERRORBOX" => ctx.new_int(SEM_NOGPFAULTERRORBOX), diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 72f8cf56c..438d5d194 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -6,7 +6,7 @@ use crate::pyobject::{BorrowValue, Either, PyObjectRef, PyResult, TypeProtocol}; use crate::VirtualMachine; use volatile::Volatile; -fn operator_length_hint(obj: PyObjectRef, default: OptionalArg, vm: &VirtualMachine) -> PyResult { +fn _operator_length_hint(obj: PyObjectRef, default: OptionalArg, vm: &VirtualMachine) -> PyResult { let default = default.unwrap_or_else(|| vm.ctx.new_int(0)); if !objtype::isinstance(&default, &vm.ctx.types.int_type) { return Err(vm.new_type_error(format!( @@ -69,7 +69,7 @@ fn timing_safe_cmp(a: &[u8], b: &[u8]) -> bool { result == 0 } -fn operator_compare_digest( +fn _operator_compare_digest( a: Either, b: Either, vm: &VirtualMachine, @@ -93,8 +93,9 @@ fn operator_compare_digest( } pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { + let ctx = &vm.ctx; py_module!(vm, "_operator", { - "length_hint" => vm.ctx.new_function(operator_length_hint), - "_compare_digest" => vm.ctx.new_function(operator_compare_digest), + "length_hint" => named_function!(ctx, _operator, length_hint), + "_compare_digest" => named_function!(ctx, _operator, compare_digest), }) } diff --git a/vm/src/stdlib/thread.rs b/vm/src/stdlib/thread.rs index 2d5999e05..a3fb29567 100644 --- a/vm/src/stdlib/thread.rs +++ b/vm/src/stdlib/thread.rs @@ -201,7 +201,7 @@ impl PyRLock { } } -fn thread_get_ident() -> u64 { +fn _thread_get_ident() -> u64 { thread_to_id(&thread::current()) } @@ -211,11 +211,11 @@ fn thread_to_id(t: &thread::Thread) -> u64 { unsafe { std::mem::transmute(t.id()) } } -fn thread_allocate_lock() -> PyLock { +fn _thread_allocate_lock() -> PyLock { PyLock { mu: RawMutex::INIT } } -fn thread_start_new_thread( +fn _thread_start_new_thread( func: PyCallable, args: PyTupleRef, kwargs: OptionalArg, @@ -268,19 +268,19 @@ fn run_thread(func: PyCallable, args: PyFuncArgs, vm: &VirtualMachine) { thread_local!(static SENTINELS: RefCell> = RefCell::default()); -fn thread_set_sentinel(vm: &VirtualMachine) -> PyLockRef { +fn _thread_set_sentinel(vm: &VirtualMachine) -> PyLockRef { let lock = PyLock { mu: RawMutex::INIT }.into_ref(vm); SENTINELS.with(|sents| sents.borrow_mut().push(lock.clone())); lock } -fn thread_stack_size(size: OptionalArg, vm: &VirtualMachine) -> usize { +fn _thread_stack_size(size: OptionalArg, vm: &VirtualMachine) -> usize { let size = size.unwrap_or(0); // TODO: do validation on this to make sure it's not too small vm.state.stacksize.swap(size) } -fn thread_count(vm: &VirtualMachine) -> usize { +fn _thread_count(vm: &VirtualMachine) -> usize { vm.state.thread_count.load() } @@ -363,12 +363,12 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "RLock" => PyRLock::make_class(ctx), "LockType" => PyLock::make_class(ctx), "_local" => PyLocal::make_class(ctx), - "get_ident" => ctx.new_function(thread_get_ident), - "allocate_lock" => ctx.new_function(thread_allocate_lock), - "start_new_thread" => ctx.new_function(thread_start_new_thread), - "_set_sentinel" => ctx.new_function(thread_set_sentinel), - "stack_size" => ctx.new_function(thread_stack_size), - "_count" => ctx.new_function(thread_count), + "get_ident" => named_function!(ctx, _thread, get_ident), + "allocate_lock" => named_function!(ctx, _thread, allocate_lock), + "start_new_thread" => named_function!(ctx, _thread, start_new_thread), + "_set_sentinel" => named_function!(ctx, _thread, set_sentinel), + "stack_size" => named_function!(ctx, _thread, stack_size), + "_count" => named_function!(ctx, _thread, count), "error" => ctx.exceptions.runtime_error.clone(), "TIMEOUT_MAX" => ctx.new_float(TIMEOUT_MAX), }) diff --git a/vm/src/stdlib/time_module.rs b/vm/src/stdlib/time_module.rs index d24d6c505..eebb04913 100644 --- a/vm/src/stdlib/time_module.rs +++ b/vm/src/stdlib/time_module.rs @@ -266,17 +266,17 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let struct_time_type = PyStructTime::make_class(ctx); py_module!(vm, "time", { - "asctime" => ctx.new_function(time_asctime), - "ctime" => ctx.new_function(time_ctime), - "gmtime" => ctx.new_function(time_gmtime), - "mktime" => ctx.new_function(time_mktime), - "localtime" => ctx.new_function(time_localtime), - "monotonic" => ctx.new_function(time_monotonic), - "strftime" => ctx.new_function(time_strftime), - "strptime" => ctx.new_function(time_strptime), - "sleep" => ctx.new_function(time_sleep), + "asctime" => named_function!(ctx, time, asctime), + "ctime" => named_function!(ctx, time, ctime), + "gmtime" => named_function!(ctx, time, gmtime), + "mktime" => named_function!(ctx, time, mktime), + "localtime" => named_function!(ctx, time, localtime), + "monotonic" => named_function!(ctx, time, monotonic), + "strftime" => named_function!(ctx, time, strftime), + "strptime" => named_function!(ctx, time, strptime), + "sleep" => named_function!(ctx, time, sleep), "struct_time" => struct_time_type, - "time" => ctx.new_function(time_time), - "perf_counter" => ctx.new_function(time_time), // TODO: fix + "time" => named_function!(ctx, time, time), + "perf_counter" => named_function!(ctx, time, time), // TODO: fix }) } diff --git a/vm/src/stdlib/winreg.rs b/vm/src/stdlib/winreg.rs index 2fb46b9d2..140d90fd7 100644 --- a/vm/src/stdlib/winreg.rs +++ b/vm/src/stdlib/winreg.rs @@ -252,13 +252,13 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let hkey_type = PyHKEY::make_class(ctx); let module = py_module!(vm, "winreg", { "HKEYType" => hkey_type, - "OpenKey" => ctx.new_function(winreg_OpenKey), - "OpenKeyEx" => ctx.new_function(winreg_OpenKey), - "QueryValue" => ctx.new_function(winreg_QueryValue), - "QueryValueEx" => ctx.new_function(winreg_QueryValueEx), - "EnumKey" => ctx.new_function(winreg_EnumKey), - "EnumValue" => ctx.new_function(winreg_EnumValue), - "CloseKey" => ctx.new_function(winreg_CloseKey), + "OpenKey" => named_function!(ctx, winreg, OpenKey), + "OpenKeyEx" => named_function!(ctx, winreg, OpenKey), + "QueryValue" => named_function!(ctx, winreg, QueryValue), + "QueryValueEx" => named_function!(ctx, winreg, QueryValueEx), + "EnumKey" => named_function!(ctx, winreg, EnumKey), + "EnumValue" => named_function!(ctx, winreg, EnumValue), + "CloseKey" => named_function!(ctx, winreg, CloseKey), }); macro_rules! add_constants { diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index 6e7f13f0d..d408f29f8 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -58,7 +58,8 @@ fn _base_executable(ctx: &PyContext) -> PyObjectRef { } } -fn getframe(offset: OptionalArg, vm: &VirtualMachine) -> PyResult { +#[allow(non_snake_case)] // it's the function sys._getframe -> sys__getframe +fn sys__getframe(offset: OptionalArg, vm: &VirtualMachine) -> PyResult { let offset = offset.into_option().unwrap_or(0); if offset > vm.frames.borrow().len() - 1 { return Err(vm.new_value_error("call stack is not deep enough".to_owned())); @@ -650,24 +651,24 @@ settrace() -- set the global debug tracing function "_base_executable" => _base_executable(ctx), "executable" => executable(ctx), "flags" => flags, - "getrefcount" => ctx.new_function(sys_getrefcount), - "getrecursionlimit" => ctx.new_function(sys_getrecursionlimit), - "getsizeof" => ctx.new_function(sys_getsizeof), + "getrefcount" => named_function!(ctx, sys, getrefcount), + "getrecursionlimit" => named_function!(ctx, sys, getrecursionlimit), + "getsizeof" => named_function!(ctx, sys, getsizeof), "implementation" => implementation, - "getfilesystemencoding" => ctx.new_function(sys_getfilesystemencoding), - "getfilesystemencodeerrors" => ctx.new_function(sys_getfilesystemencodeerrors), - "getdefaultencoding" => ctx.new_function(sys_getdefaultencoding), - "getprofile" => ctx.new_function(sys_getprofile), - "gettrace" => ctx.new_function(sys_gettrace), + "getfilesystemencoding" => named_function!(ctx, sys, getfilesystemencoding), + "getfilesystemencodeerrors" => named_function!(ctx, sys, getfilesystemencodeerrors), + "getdefaultencoding" => named_function!(ctx, sys, getdefaultencoding), + "getprofile" => named_function!(ctx, sys, getprofile), + "gettrace" => named_function!(ctx, sys, gettrace), "hash_info" => hash_info, - "intern" => ctx.new_function(sys_intern), + "intern" => named_function!(ctx, sys, intern), "maxunicode" => ctx.new_int(std::char::MAX as u32), "maxsize" => ctx.new_int(std::isize::MAX), "path" => path, "ps1" => ctx.new_str(">>>>> "), "ps2" => ctx.new_str("..... "), "__doc__" => ctx.new_str(sys_doc), - "_getframe" => ctx.new_function(getframe), + "_getframe" => named_function!(ctx, sys, _getframe), "modules" => modules.clone(), "warnoptions" => ctx.new_list(vec![]), "platform" => ctx.new_str(PLATFORM.to_owned()), @@ -677,24 +678,24 @@ settrace() -- set the global debug tracing function "path_importer_cache" => ctx.new_dict(), "pycache_prefix" => vm.ctx.none(), "dont_write_bytecode" => vm.ctx.new_bool(vm.state.settings.dont_write_bytecode), - "setprofile" => ctx.new_function(sys_setprofile), - "setrecursionlimit" => ctx.new_function(sys_setrecursionlimit), - "settrace" => ctx.new_function(sys_settrace), + "setprofile" => named_function!(ctx, sys, setprofile), + "setrecursionlimit" => named_function!(ctx, sys, setrecursionlimit), + "settrace" => named_function!(ctx, sys, settrace), "version" => vm.ctx.new_str(version::get_version()), "version_info" => version_info, "_git" => sys_git_info(vm), - "exc_info" => ctx.new_function(sys_exc_info), + "exc_info" => named_function!(ctx, sys, exc_info), "prefix" => ctx.new_str(prefix), "base_prefix" => ctx.new_str(base_prefix), "exec_prefix" => ctx.new_str(exec_prefix), "base_exec_prefix" => ctx.new_str(base_exec_prefix), - "exit" => ctx.new_function(sys_exit), + "exit" => named_function!(ctx, sys, exit), "abiflags" => ctx.new_str(ABIFLAGS.to_owned()), - "audit" => ctx.new_function(sys_audit), - "displayhook" => ctx.new_function(sys_displayhook), - "__displayhook__" => ctx.new_function(sys_displayhook), - "excepthook" => ctx.new_function(sys_excepthook), - "__excepthook__" => ctx.new_function(sys_excepthook), + "audit" => named_function!(ctx, sys, audit), + "displayhook" => named_function!(ctx, sys, displayhook), + "__displayhook__" => named_function!(ctx, sys, displayhook), + "excepthook" => named_function!(ctx, sys, excepthook), + "__excepthook__" => named_function!(ctx, sys, excepthook), "hexversion" => ctx.new_int(version::VERSION_HEX), "api_version" => ctx.new_int(0x0), // what C api? "float_info" => float_info, @@ -708,7 +709,7 @@ settrace() -- set the global debug tracing function { let getwindowsversion = WindowsVersion::make_class(ctx); extend_module!(vm, module, { - "getwindowsversion" => ctx.new_function(sys_getwindowsversion), + "getwindowsversion" => named_function!(ctx, sys, getwindowsversion), "_getwindowsversion_type" => getwindowsversion, // XXX: This is not a python spec but required by current RustPython implementation }) } From 2dcfd197502528aa048ecf3d811df2e2730acc69 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Mon, 21 Sep 2020 10:41:58 -0500 Subject: [PATCH 3/4] Add signal.py from CPython 3.8.3 --- Lib/signal.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Lib/signal.py diff --git a/Lib/signal.py b/Lib/signal.py new file mode 100644 index 000000000..d4a6d6fe2 --- /dev/null +++ b/Lib/signal.py @@ -0,0 +1,85 @@ +import _signal +from _signal import * +from functools import wraps as _wraps +from enum import IntEnum as _IntEnum + +_globals = globals() + +_IntEnum._convert_( + 'Signals', __name__, + lambda name: + name.isupper() + and (name.startswith('SIG') and not name.startswith('SIG_')) + or name.startswith('CTRL_')) + +_IntEnum._convert_( + 'Handlers', __name__, + lambda name: name in ('SIG_DFL', 'SIG_IGN')) + +if 'pthread_sigmask' in _globals: + _IntEnum._convert_( + 'Sigmasks', __name__, + lambda name: name in ('SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK')) + + +def _int_to_enum(value, enum_klass): + """Convert a numeric value to an IntEnum member. + If it's not a known member, return the numeric value itself. + """ + try: + return enum_klass(value) + except ValueError: + return value + + +def _enum_to_int(value): + """Convert an IntEnum member to a numeric value. + If it's not an IntEnum member return the value itself. + """ + try: + return int(value) + except (ValueError, TypeError): + return value + + +@_wraps(_signal.signal) +def signal(signalnum, handler): + handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler)) + return _int_to_enum(handler, Handlers) + + +@_wraps(_signal.getsignal) +def getsignal(signalnum): + handler = _signal.getsignal(signalnum) + return _int_to_enum(handler, Handlers) + + +if 'pthread_sigmask' in _globals: + @_wraps(_signal.pthread_sigmask) + def pthread_sigmask(how, mask): + sigs_set = _signal.pthread_sigmask(how, mask) + return set(_int_to_enum(x, Signals) for x in sigs_set) + pthread_sigmask.__doc__ = _signal.pthread_sigmask.__doc__ + + +if 'sigpending' in _globals: + @_wraps(_signal.sigpending) + def sigpending(): + return {_int_to_enum(x, Signals) for x in _signal.sigpending()} + + +if 'sigwait' in _globals: + @_wraps(_signal.sigwait) + def sigwait(sigset): + retsig = _signal.sigwait(sigset) + return _int_to_enum(retsig, Signals) + sigwait.__doc__ = _signal.sigwait + + +if 'valid_signals' in _globals: + @_wraps(_signal.valid_signals) + def valid_signals(): + return {_int_to_enum(x, Signals) for x in _signal.valid_signals()} + + +del _globals, _wraps From abcd929280bd21193b2d485f2a8b7ecf3a893acf Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Mon, 21 Sep 2020 10:54:13 -0500 Subject: [PATCH 4/4] Make signal->_signal --- vm/src/stdlib/mod.rs | 2 +- vm/src/stdlib/signal.rs | 24 ++++++++++++++---------- vm/src/vm.rs | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index 05ef201ed..92ccd44b6 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -129,7 +129,7 @@ pub fn get_module_inits() -> HashMap { "_multiprocessing".to_owned(), Box::new(multiprocessing::make_module), ); - modules.insert("signal".to_owned(), Box::new(signal::make_module)); + modules.insert("_signal".to_owned(), Box::new(signal::make_module)); modules.insert("select".to_owned(), Box::new(select::make_module)); #[cfg(feature = "ssl")] modules.insert("_ssl".to_owned(), Box::new(ssl::make_module)); diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs index 60e4ef128..1bb9475d1 100644 --- a/vm/src/stdlib/signal.rs +++ b/vm/src/stdlib/signal.rs @@ -36,7 +36,7 @@ fn assert_in_range(signum: i32, vm: &VirtualMachine) -> PyResult<()> { } } -fn signal(signalnum: i32, handler: PyObjectRef, vm: &VirtualMachine) -> PyResult { +fn _signal_signal(signalnum: i32, handler: PyObjectRef, vm: &VirtualMachine) -> PyResult { assert_in_range(signalnum, vm)?; let signal_handlers = vm .signal_handlers @@ -78,7 +78,7 @@ fn signal(signalnum: i32, handler: PyObjectRef, vm: &VirtualMachine) -> PyResult Ok(old_handler) } -fn getsignal(signalnum: i32, vm: &VirtualMachine) -> PyResult { +fn _signal_getsignal(signalnum: i32, vm: &VirtualMachine) -> PyResult { assert_in_range(signalnum, vm)?; let signal_handlers = vm .signal_handlers @@ -88,7 +88,7 @@ fn getsignal(signalnum: i32, vm: &VirtualMachine) -> PyResult { } #[cfg(unix)] -fn alarm(time: u32) -> u32 { +fn _signal_alarm(time: u32) -> u32 { let prev_time = if time == 0 { sig_alarm::cancel() } else { @@ -119,21 +119,25 @@ pub fn check_signals(vm: &VirtualMachine) -> PyResult<()> { Ok(()) } -fn default_int_handler(_signum: PyObjectRef, _arg: PyObjectRef, vm: &VirtualMachine) -> PyResult { +fn _signal_default_int_handler( + _signum: PyObjectRef, + _arg: PyObjectRef, + vm: &VirtualMachine, +) -> PyResult { Err(vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.clone())) } pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; - let int_handler = ctx.new_function(default_int_handler); + let int_handler = named_function!(ctx, _signal, default_int_handler); let sig_dfl = ctx.new_int(SIG_DFL as u8); let sig_ign = ctx.new_int(SIG_IGN as u8); - let module = py_module!(vm, "signal", { - "signal" => ctx.new_function(signal), - "getsignal" => ctx.new_function(getsignal), + let module = py_module!(vm, "_signal", { + "signal" => named_function!(ctx, _signal, signal), + "getsignal" => named_function!(ctx, _signal, getsignal), "SIG_DFL" => sig_dfl.clone(), "SIG_IGN" => sig_ign.clone(), "SIGABRT" => ctx.new_int(libc::SIGABRT as u8), @@ -161,7 +165,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { vm.signal_handlers.as_ref().unwrap().borrow_mut()[signum] = py_handler; } - signal(libc::SIGINT, int_handler, vm).expect("Failed to set sigint handler"); + _signal_signal(libc::SIGINT, int_handler, vm).expect("Failed to set sigint handler"); module } @@ -171,7 +175,7 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) { let ctx = &vm.ctx; extend_module!(vm, module, { - "alarm" => ctx.new_function(alarm), + "alarm" => named_function!(ctx, _signal, alarm), "SIGHUP" => ctx.new_int(libc::SIGHUP as u8), "SIGQUIT" => ctx.new_int(libc::SIGQUIT as u8), "SIGTRAP" => ctx.new_int(libc::SIGTRAP as u8), diff --git a/vm/src/vm.rs b/vm/src/vm.rs index d3364bd95..970986159 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -310,7 +310,7 @@ impl VirtualMachine { let mut inner_init = || -> PyResult<()> { #[cfg(not(target_arch = "wasm32"))] - import::import_builtin(self, "signal")?; + import::import_builtin(self, "_signal")?; #[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))] {