forked from Rust-related/RustPython
Use RPITIT where applicable
This commit is contained in:
@@ -150,20 +150,14 @@ where
|
||||
pub trait AnyStr {
|
||||
type Char: Copy;
|
||||
type Container: AnyStrContainer<Self> + Extend<Self::Char>;
|
||||
type CharIter<'a>: Iterator<Item = char> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
type ElementIter<'a>: Iterator<Item = Self::Char> + 'a
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn element_bytes_len(c: Self::Char) -> usize;
|
||||
|
||||
fn to_container(&self) -> Self::Container;
|
||||
fn as_bytes(&self) -> &[u8];
|
||||
fn as_utf8_str(&self) -> Result<&str, std::str::Utf8Error>;
|
||||
fn chars(&self) -> Self::CharIter<'_>;
|
||||
fn elements(&self) -> Self::ElementIter<'_>;
|
||||
fn chars(&self) -> impl Iterator<Item = char>;
|
||||
fn elements(&self) -> impl Iterator<Item = Self::Char>;
|
||||
fn get_bytes(&self, range: std::ops::Range<usize>) -> &Self;
|
||||
// FIXME: get_chars is expensive for str
|
||||
fn get_chars(&self, range: std::ops::Range<usize>) -> &Self;
|
||||
|
||||
@@ -49,7 +49,7 @@ impl PyNativeFunction {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn as_func(&self) -> &'static PyNativeFn {
|
||||
pub fn as_func(&self) -> &'static dyn PyNativeFn {
|
||||
self.value.func
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,13 +358,13 @@ where
|
||||
}
|
||||
|
||||
impl MutObjectSequenceOp for PyList {
|
||||
type Guard<'a> = PyMappedRwLockReadGuard<'a, [PyObjectRef]>;
|
||||
type Inner = [PyObjectRef];
|
||||
|
||||
fn do_get<'a>(index: usize, guard: &'a Self::Guard<'_>) -> Option<&'a PyObjectRef> {
|
||||
guard.get(index)
|
||||
fn do_get(index: usize, inner: &[PyObjectRef]) -> Option<&PyObjectRef> {
|
||||
inner.get(index)
|
||||
}
|
||||
|
||||
fn do_lock(&self) -> Self::Guard<'_> {
|
||||
fn do_lock(&self) -> impl std::ops::Deref<Target = [PyObjectRef]> {
|
||||
self.borrow_vec()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1692,8 +1692,6 @@ impl AnyStrContainer<str> for String {
|
||||
impl AnyStr for str {
|
||||
type Char = char;
|
||||
type Container = String;
|
||||
type CharIter<'a> = std::str::Chars<'a>;
|
||||
type ElementIter<'a> = std::str::Chars<'a>;
|
||||
|
||||
fn element_bytes_len(c: char) -> usize {
|
||||
c.len_utf8()
|
||||
@@ -1711,11 +1709,11 @@ impl AnyStr for str {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn chars(&self) -> Self::CharIter<'_> {
|
||||
fn chars(&self) -> impl Iterator<Item = char> {
|
||||
str::chars(self)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Self::ElementIter<'_> {
|
||||
fn elements(&self) -> impl Iterator<Item = char> {
|
||||
str::chars(self)
|
||||
}
|
||||
|
||||
|
||||
@@ -1024,8 +1024,6 @@ const ASCII_WHITESPACES: [u8; 6] = [0x20, 0x09, 0x0a, 0x0c, 0x0d, 0x0b];
|
||||
impl AnyStr for [u8] {
|
||||
type Char = u8;
|
||||
type Container = Vec<u8>;
|
||||
type CharIter<'a> = bstr::Chars<'a>;
|
||||
type ElementIter<'a> = std::iter::Copied<std::slice::Iter<'a, u8>>;
|
||||
|
||||
fn element_bytes_len(_: u8) -> usize {
|
||||
1
|
||||
@@ -1043,11 +1041,11 @@ impl AnyStr for [u8] {
|
||||
std::str::from_utf8(self)
|
||||
}
|
||||
|
||||
fn chars(&self) -> Self::CharIter<'_> {
|
||||
fn chars(&self) -> impl Iterator<Item = char> {
|
||||
bstr::ByteSlice::chars(self)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Self::ElementIter<'_> {
|
||||
fn elements(&self) -> impl Iterator<Item = u8> {
|
||||
self.iter().copied()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,14 @@ use std::marker::PhantomData;
|
||||
|
||||
/// A built-in Python function.
|
||||
// PyCFunction in CPython
|
||||
pub type PyNativeFn = py_dyn_fn!(dyn Fn(&VirtualMachine, FuncArgs) -> PyResult);
|
||||
pub trait PyNativeFn:
|
||||
Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static
|
||||
{
|
||||
}
|
||||
impl<F: Fn(&VirtualMachine, FuncArgs) -> PyResult + PyThreadingConstraint + 'static> PyNativeFn
|
||||
for F
|
||||
{
|
||||
}
|
||||
|
||||
/// Implemented by types that are or can generate built-in functions.
|
||||
///
|
||||
@@ -34,40 +41,44 @@ pub trait IntoPyNativeFn<Kind>: Sized + PyThreadingConstraint + 'static {
|
||||
/// `IntoPyNativeFn::into_func()` generates a PyNativeFn that performs the
|
||||
/// appropriate type and arity checking, any requested conversions, and then if
|
||||
/// successful calls the function with the extracted parameters.
|
||||
fn into_func(self) -> &'static PyNativeFn {
|
||||
let boxed = Box::new(move |vm: &VirtualMachine, args| self.call(vm, args));
|
||||
Box::leak(boxed)
|
||||
fn into_func(self) -> impl PyNativeFn {
|
||||
into_func(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent to `into_func()`, but accessible as a constant. This is only
|
||||
/// valid if this function is zero-sized, i.e. that
|
||||
/// `std::mem::size_of::<F>() == 0`. If it isn't, use of this constant will
|
||||
/// raise a compile error.
|
||||
const STATIC_FUNC: &'static PyNativeFn = {
|
||||
if std::mem::size_of::<Self>() == 0 {
|
||||
&|vm, args| {
|
||||
// SAFETY: we just confirmed that Self is zero-sized, so there
|
||||
// aren't any bytes in it that could be uninit.
|
||||
#[allow(clippy::uninit_assumed_init)]
|
||||
let f = unsafe { std::mem::MaybeUninit::<Self>::uninit().assume_init() };
|
||||
f.call(vm, args)
|
||||
const fn into_func<F: IntoPyNativeFn<Kind>, Kind>(f: F) -> impl PyNativeFn {
|
||||
move |vm: &VirtualMachine, args| f.call(vm, args)
|
||||
}
|
||||
|
||||
const fn zst_ref_out_of_thin_air<T: 'static>(x: T) -> &'static T {
|
||||
// if T is zero-sized, there's no issue forgetting it - even if it does have a Drop impl, it
|
||||
// would never get called anyway if we consider this semantically a Box::leak(Box::new(x))-type
|
||||
// operation. if T isn't zero-sized, we don't have to worry about it because we'll fail to compile.
|
||||
std::mem::forget(x);
|
||||
trait Zst: Sized + 'static {
|
||||
const THIN_AIR: &'static Self = {
|
||||
if std::mem::size_of::<Self>() == 0 {
|
||||
// SAFETY: we just confirmed that Self is zero-sized, so we can
|
||||
// pull a value of it out of thin air.
|
||||
unsafe { std::ptr::NonNull::<Self>::dangling().as_ref() }
|
||||
} else {
|
||||
panic!("can't use a non-zero-sized type here")
|
||||
}
|
||||
} else {
|
||||
panic!("function must be zero-sized to access STATIC_FUNC")
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
impl<T: 'static> Zst for T {}
|
||||
<T as Zst>::THIN_AIR
|
||||
}
|
||||
|
||||
/// Get the [`STATIC_FUNC`](IntoPyNativeFn::STATIC_FUNC) of the passed function. The same
|
||||
/// requirements of zero-sizedness apply, see that documentation for details.
|
||||
///
|
||||
/// Equivalent to [`IntoPyNativeFn::into_func()`], but usable in a const context. This is only
|
||||
/// valid if the function is zero-sized, i.e. that `std::mem::size_of::<F>() == 0`. If you call
|
||||
/// this function with a non-zero-sized function, it will raise a compile error.
|
||||
#[inline(always)]
|
||||
pub const fn static_func<Kind, F: IntoPyNativeFn<Kind>>(f: F) -> &'static PyNativeFn {
|
||||
// if f is zero-sized, there's no issue forgetting it - even if a capture of f does have a Drop
|
||||
// impl, it would never get called anyway. If you passed it to into_func, it would just get
|
||||
// Box::leak'd, and as a 'static reference it'll never be dropped. and if f isn't zero-sized,
|
||||
// we'll never reach this point anyway because we'll fail to compile.
|
||||
std::mem::forget(f);
|
||||
F::STATIC_FUNC
|
||||
pub const fn static_func<Kind, F: IntoPyNativeFn<Kind>>(f: F) -> &'static dyn PyNativeFn {
|
||||
zst_ref_out_of_thin_air(into_func(f))
|
||||
}
|
||||
|
||||
// TODO: once higher-rank trait bounds are stabilized, remove the `Kind` type
|
||||
@@ -207,16 +218,16 @@ into_py_native_fn_tuple!(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::mem::size_of_val;
|
||||
|
||||
#[test]
|
||||
fn test_into_native_fn_noalloc() {
|
||||
let check_zst = |f: &'static PyNativeFn| assert_eq!(std::mem::size_of_val(f), 0);
|
||||
fn py_func(_b: bool, _vm: &crate::VirtualMachine) -> i32 {
|
||||
1
|
||||
}
|
||||
check_zst(py_func.into_func());
|
||||
assert_eq!(size_of_val(&py_func.into_func()), 0);
|
||||
let empty_closure = || "foo".to_owned();
|
||||
check_zst(empty_closure.into_func());
|
||||
check_zst(static_func(empty_closure));
|
||||
assert_eq!(size_of_val(&empty_closure.into_func()), 0);
|
||||
assert_eq!(size_of_val(static_func(empty_closure)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ macro_rules! define_methods {
|
||||
($($name:literal => $func:ident as $flags:ident),+) => {
|
||||
vec![ $( $crate::function::PyMethodDef {
|
||||
name: $name,
|
||||
func: $crate::function::IntoPyNativeFn::into_func($func),
|
||||
func: $crate::function::static_func($func),
|
||||
flags: $crate::function::PyMethodFlags::$flags,
|
||||
doc: None,
|
||||
}),+ ]
|
||||
@@ -66,27 +66,12 @@ macro_rules! define_methods {
|
||||
#[derive(Clone)]
|
||||
pub struct PyMethodDef {
|
||||
pub name: &'static str, // TODO: interned
|
||||
pub func: &'static PyNativeFn,
|
||||
pub func: &'static dyn PyNativeFn,
|
||||
pub flags: PyMethodFlags,
|
||||
pub doc: Option<&'static str>, // TODO: interned
|
||||
}
|
||||
|
||||
impl PyMethodDef {
|
||||
#[inline]
|
||||
pub fn new<Kind>(
|
||||
name: &'static str,
|
||||
func: impl IntoPyNativeFn<Kind>,
|
||||
flags: PyMethodFlags,
|
||||
doc: Option<&'static str>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
func: func.into_func(),
|
||||
flags,
|
||||
doc,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn new_const<Kind>(
|
||||
name: &'static str,
|
||||
|
||||
@@ -3,13 +3,13 @@ use crate::{
|
||||
vm::VirtualMachine, AsObject, PyObject, PyObjectRef, PyResult,
|
||||
};
|
||||
use optional::Optioned;
|
||||
use std::ops::Range;
|
||||
use std::ops::{Deref, Range};
|
||||
|
||||
pub trait MutObjectSequenceOp {
|
||||
type Guard<'a>: 'a;
|
||||
type Inner: ?Sized;
|
||||
|
||||
fn do_get<'a>(index: usize, guard: &'a Self::Guard<'_>) -> Option<&'a PyObjectRef>;
|
||||
fn do_lock(&self) -> Self::Guard<'_>;
|
||||
fn do_get(index: usize, inner: &Self::Inner) -> Option<&PyObjectRef>;
|
||||
fn do_lock(&self) -> impl Deref<Target = Self::Inner>;
|
||||
|
||||
fn mut_count(&self, vm: &VirtualMachine, needle: &PyObject) -> PyResult<usize> {
|
||||
let mut count = 0;
|
||||
|
||||
@@ -416,13 +416,13 @@ mod _collections {
|
||||
}
|
||||
|
||||
impl MutObjectSequenceOp for PyDeque {
|
||||
type Guard<'a> = PyRwLockReadGuard<'a, VecDeque<PyObjectRef>>;
|
||||
type Inner = VecDeque<PyObjectRef>;
|
||||
|
||||
fn do_get<'a>(index: usize, guard: &'a Self::Guard<'_>) -> Option<&'a PyObjectRef> {
|
||||
guard.get(index)
|
||||
fn do_get(index: usize, inner: &Self::Inner) -> Option<&PyObjectRef> {
|
||||
inner.get(index)
|
||||
}
|
||||
|
||||
fn do_lock(&self) -> Self::Guard<'_> {
|
||||
fn do_lock(&self) -> impl std::ops::Deref<Target = Self::Inner> {
|
||||
self.borrow_deque()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,12 +291,12 @@ impl Context {
|
||||
let string_pool = StringPool::default();
|
||||
let names = unsafe { ConstName::new(&string_pool, &types.str_type.to_owned()) };
|
||||
|
||||
let slot_new_wrapper = PyMethodDef {
|
||||
name: names.__new__.as_str(),
|
||||
func: PyType::__new__.into_func(),
|
||||
flags: PyMethodFlags::METHOD,
|
||||
doc: None,
|
||||
};
|
||||
let slot_new_wrapper = PyMethodDef::new_const(
|
||||
names.__new__.as_str(),
|
||||
PyType::__new__,
|
||||
PyMethodFlags::METHOD,
|
||||
None,
|
||||
);
|
||||
|
||||
let empty_str = unsafe { string_pool.intern("", types.str_type.to_owned()) };
|
||||
let empty_bytes = create_object(PyBytes::from(Vec::new()), types.bytes_type);
|
||||
@@ -499,7 +499,7 @@ impl Context {
|
||||
{
|
||||
let def = PyMethodDef {
|
||||
name,
|
||||
func: f.into_func(),
|
||||
func: Box::leak(Box::new(f.into_func())),
|
||||
flags,
|
||||
doc,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user