commit
3b3ba4e3ab
|
@ -94,6 +94,10 @@ jobs:
|
|||
- if: matrix.python-version != 'pypy3'
|
||||
name: Test
|
||||
run: cargo test --features "num-bigint num-complex" --target ${{ matrix.platform.rust-target }}
|
||||
# Run tests again, but in abi3 mode
|
||||
- if: matrix.python-version != 'pypy3'
|
||||
name: Test (abi3)
|
||||
run: cargo test --no-default-features --features "abi3,macros" --target ${{ matrix.platform.rust-target }}
|
||||
|
||||
- name: Test proc-macro code
|
||||
run: cargo test --manifest-path=pyo3-derive-backend/Cargo.toml --target ${{ matrix.platform.rust-target }}
|
||||
|
|
|
@ -12,11 +12,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- Drop support for Python 3.5 (as it is now end-of-life). [#1250](https://github.com/PyO3/pyo3/pull/1250)
|
||||
|
||||
### Added
|
||||
- Add support for building for CPython limited API. This required a few minor changes to runtime behaviour of of pyo3 `#[pyclass]` types. See the migration guide for full details. [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
- Add argument names to `TypeError` messages generated by pymethod wrappers. [#1212](https://github.com/PyO3/pyo3/pull/1212)
|
||||
- Add `PyEval_SetProfile` and `PyEval_SetTrace` to FFI. [#1255](https://github.com/PyO3/pyo3/pull/1255)
|
||||
- Add context.h functions (`PyContext_New`, etc) to FFI. [#1259](https://github.com/PyO3/pyo3/pull/1259)
|
||||
|
||||
### Changed
|
||||
- Change return type `PyType::name()` from `Cow<str>` to `PyResult<&str>`. [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
- `#[pyclass(subclass)]` is now required for subclassing from Rust (was previously just required for subclassing from Python). [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
- Change `PyIterator` to be consistent with other native types: it is now used as `&PyIterator` instead of `PyIterator<'a>`. [#1176](https://github.com/PyO3/pyo3/pull/1176)
|
||||
- Change formatting of `PyDowncastError` messages to be closer to Python's builtin error messages. [#1212](https://github.com/PyO3/pyo3/pull/1212)
|
||||
|
||||
|
|
|
@ -35,6 +35,10 @@ rustversion = "1.0"
|
|||
[features]
|
||||
default = ["macros"]
|
||||
macros = ["ctor", "indoc", "inventory", "paste", "pyo3cls", "unindent"]
|
||||
# Use the Python limited API. See https://www.python.org/dev/peps/pep-0384/ for
|
||||
# more.
|
||||
abi3 = []
|
||||
|
||||
# Optimizes PyObject to Vec conversion and so on.
|
||||
nightly = []
|
||||
|
||||
|
@ -43,11 +47,6 @@ nightly = []
|
|||
# so that the module can also be used with statically linked python interpreters.
|
||||
extension-module = []
|
||||
|
||||
# The stable cpython abi as defined in PEP 384. Currently broken with
|
||||
# many compilation errors. Pull Requests working towards fixing that
|
||||
# are welcome.
|
||||
# abi3 = []
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"pyo3cls",
|
||||
|
|
5
build.rs
5
build.rs
|
@ -557,6 +557,11 @@ fn run_python_script(interpreter: &Path, script: &str) -> Result<String> {
|
|||
|
||||
fn get_library_link_name(version: &PythonVersion, ld_version: &str) -> String {
|
||||
if cfg!(target_os = "windows") {
|
||||
// Mirrors the behavior in CPython's `PC/pyconfig.h`.
|
||||
if env::var_os("CARGO_FEATURE_ABI3").is_some() {
|
||||
return "python3".to_string();
|
||||
}
|
||||
|
||||
let minor_or_empty_string = match version.minor {
|
||||
Some(minor) => format!("{}", minor),
|
||||
None => String::new(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import datetime as pdt
|
||||
import platform
|
||||
import struct
|
||||
import re
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
@ -310,4 +311,5 @@ def test_tz_class_introspection():
|
|||
tzi = rdt.TzClass()
|
||||
|
||||
assert tzi.__class__ == rdt.TzClass
|
||||
assert repr(tzi).startswith("<TzClass object at")
|
||||
# PyPy generates <importlib.bootstrap.TzClass ...> for some reason.
|
||||
assert re.match(r"^<[\w\.]*TzClass object at", repr(tzi))
|
||||
|
|
|
@ -36,7 +36,27 @@ On Linux/macOS you might have to change `LD_LIBRARY_PATH` to include libpython,
|
|||
|
||||
## Distribution
|
||||
|
||||
There are two ways to distribute your module as a Python package: The old, [setuptools-rust](https://github.com/PyO3/setuptools-rust), and the new, [maturin](https://github.com/pyo3/maturin). setuptools-rust needs several configuration files (`setup.py`, `MANIFEST.in`, `build-wheels.sh`, etc.). maturin doesn't need any configuration files, however it does not support some functionality of setuptools such as package data ([pyo3/maturin#258](https://github.com/PyO3/maturin/issues/258)) and requires a rigid project structure, while setuptools-rust allows (and sometimes requires) configuration with python code.
|
||||
There are two ways to distribute your module as a Python package: The old, [setuptools-rust], and the new, [maturin]. setuptools-rust needs several configuration files (`setup.py`, `MANIFEST.in`, `build-wheels.sh`, etc.). maturin doesn't need any configuration files, however it does not support some functionality of setuptools such as package data ([pyo3/maturin#258](https://github.com/PyO3/maturin/issues/258)) and requires a rigid project structure, while setuptools-rust allows (and sometimes requires) configuration with python code.
|
||||
|
||||
## `Py_LIMITED_API`/`abi3`
|
||||
|
||||
By default, Python extension modules can only be used with the same Python version they were compiled against -- if you build an extension module with Python 3.5, you can't import it using Python 3.8. [PEP 384](https://www.python.org/dev/peps/pep-0384/) introduced the idea of the limited Python API, which would have a stable ABI enabling extension modules built with it to be used against multiple Python versions. This is also known as `abi3`.
|
||||
|
||||
Note that [maturin] >= 0.9.0 or [setuptools-rust] >= 0.12.0 is going to support `abi3` wheels.
|
||||
See the [corresponding](https://github.com/PyO3/maturin/pull/353) [PRs](https://github.com/PyO3/setuptools-rust/pull/82) for more.
|
||||
|
||||
There are three steps involved in making use of `abi3` when building Python packages as wheels:
|
||||
|
||||
1. Enable the `abi3` feature in `pyo3`. This ensures `pyo3` only calls Python C-API functions which are part of the stable API, and on Windows also ensures that the project links against the correct shared object (no special behavior is required on other platforms):
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
pyo3 = { version = "...", features = ["abi3"]}
|
||||
```
|
||||
|
||||
2. Ensure that the built shared objects are correctly marked as `abi3`. This is accomplished by telling your build system that you're using the limited API.
|
||||
|
||||
3. Ensure that the `.whl` is correctly marked as `abi3`. For projects using `setuptools`, this is accomplished by passing `--py-limited-api=cp3x` (where `x` is the minimum Python version supported by the wheel, e.g. `--py-limited-api=cp35` for Python 3.5) to `setup.py bdist_wheel`.
|
||||
|
||||
## Cross Compiling
|
||||
|
||||
|
@ -83,3 +103,8 @@ cargo build --target x86_64-pc-windows-gnu
|
|||
## Bazel
|
||||
|
||||
For an example of how to build python extensions using Bazel, see https://github.com/TheButlah/rules_pyo3
|
||||
|
||||
|
||||
[maturin]: https://github.com/PyO3/maturin
|
||||
[setuptools-rust]: https://github.com/PyO3/setuptools-rust
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ or by `self_.into_super()` as `PyRef<Self::BaseClass>`.
|
|||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(subclass)]
|
||||
struct BaseClass {
|
||||
val1: usize,
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ impl BaseClass {
|
|||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends=BaseClass)]
|
||||
#[pyclass(extends=BaseClass, subclass)]
|
||||
struct SubClass {
|
||||
val2: usize,
|
||||
}
|
||||
|
@ -266,12 +266,14 @@ impl SubSubClass {
|
|||
```
|
||||
|
||||
You can also inherit native types such as `PyDict`, if they implement
|
||||
[`PySizedLayout`](https://docs.rs/pyo3/latest/pyo3/type_object/trait.PySizedLayout.html).
|
||||
[`PySizedLayout`](https://docs.rs/pyo3/latest/pyo3/type_object/trait.PySizedLayout.html). However, this is not supported when building for the Python limited API (aka the `abi3` feature of PyO3).
|
||||
|
||||
However, because of some technical problems, we don't currently provide safe upcasting methods for types
|
||||
that inherit native types. Even in such cases, you can unsafely get a base class by raw pointer conversion.
|
||||
|
||||
```rust
|
||||
# #[cfg(Py_LIMITED_API)] fn main() {}
|
||||
# #[cfg(not(Py_LIMITED_API))] fn main() {
|
||||
# use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use pyo3::{AsPyPointer, PyNativeType};
|
||||
|
@ -300,6 +302,7 @@ impl DictWithCounter {
|
|||
# let py = gil.python();
|
||||
# let cnt = pyo3::PyCell::new(py, DictWithCounter::new()).unwrap();
|
||||
# pyo3::py_run!(py, cnt, "cnt.set('abc', 10); assert cnt['abc'] == 10")
|
||||
# }
|
||||
```
|
||||
|
||||
If `SubClass` does not provide a baseclass initialization, the compilation fails.
|
||||
|
@ -769,13 +772,23 @@ impl pyo3::class::methods::HasMethodsInventory for MyClass {
|
|||
}
|
||||
pyo3::inventory::collect!(Pyo3MethodsInventoryForMyClass);
|
||||
|
||||
impl pyo3::class::proto_methods::HasProtoRegistry for MyClass {
|
||||
fn registry() -> &'static pyo3::class::proto_methods::PyProtoRegistry {
|
||||
static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry
|
||||
= pyo3::class::proto_methods::PyProtoRegistry::new();
|
||||
®ISTRY
|
||||
|
||||
pub struct Pyo3ProtoInventoryForMyClass {
|
||||
def: pyo3::class::proto_methods::PyProtoMethodDef,
|
||||
}
|
||||
impl pyo3::class::proto_methods::PyProtoInventory for Pyo3ProtoInventoryForMyClass {
|
||||
fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self {
|
||||
Self { def }
|
||||
}
|
||||
fn get(&'static self) -> &'static pyo3::class::proto_methods::PyProtoMethodDef {
|
||||
&self.def
|
||||
}
|
||||
}
|
||||
impl pyo3::class::proto_methods::HasProtoInventory for MyClass {
|
||||
type ProtoMethods = Pyo3ProtoInventoryForMyClass;
|
||||
}
|
||||
pyo3::inventory::collect!(Pyo3ProtoInventoryForMyClass);
|
||||
|
||||
|
||||
impl pyo3::pyclass::PyClassSend for MyClass {
|
||||
type ThreadChecker = pyo3::pyclass::ThreadCheckerStub<MyClass>;
|
||||
|
|
|
@ -3,6 +3,18 @@
|
|||
This guide can help you upgrade code through breaking changes from one PyO3 version to the next.
|
||||
For a detailed list of all changes, see the [CHANGELOG](changelog.md).
|
||||
|
||||
## from 0.12.* to 0.13
|
||||
|
||||
### Runtime changes to support the CPython limited API
|
||||
|
||||
In PyO3 `0.13` support was added for compiling against the CPython limited API. This had a number of implications for _all_ PyO3 users, described here.
|
||||
|
||||
The largest of these is that all types created from PyO3 are what CPython calls "heap" types. The specific implications of this are:
|
||||
|
||||
- If you wish to subclass one of these types _from Rust_ you must mark it `#[pyclass(subclass)]`, as you would if you wished to allow subclassing it from Python code.
|
||||
- Type objects are now mutable - Python code can set attributes on them.
|
||||
- `__module__` on types without `#[pyclass(module="mymodule")]` no longer returns `builtins`, it now raises `AttributeError`.
|
||||
|
||||
## from 0.11.* to 0.12
|
||||
|
||||
### `PyErr` has been reworked
|
||||
|
|
|
@ -408,8 +408,8 @@ impl Model for UserModel {
|
|||
.call_method("get_results", (), None)
|
||||
.unwrap();
|
||||
|
||||
if py_result.get_type().name() != "list" {
|
||||
panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name());
|
||||
if py_result.get_type().name().unwrap() != "list" {
|
||||
panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name().unwrap());
|
||||
}
|
||||
py_result.extract()
|
||||
})
|
||||
|
@ -536,8 +536,8 @@ impl Model for UserModel {
|
|||
.call_method("get_results", (), None)
|
||||
.unwrap();
|
||||
|
||||
if py_result.get_type().name() != "list" {
|
||||
panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name());
|
||||
if py_result.get_type().name().unwrap() != "list" {
|
||||
panic!("Expected a list for the get_results() method signature, got {}", py_result.get_type().name().unwrap());
|
||||
}
|
||||
py_result.extract()
|
||||
})
|
||||
|
|
|
@ -6,16 +6,14 @@ use std::collections::HashSet;
|
|||
pub struct Proto {
|
||||
/// The name of this protocol. E.g., Iter.
|
||||
pub name: &'static str,
|
||||
/// The name of slot table. E.g., PyIterMethods.
|
||||
pub slot_table: &'static str,
|
||||
/// The name of the setter used to set the table to `PyProtoRegistry`.
|
||||
pub set_slot_table: &'static str,
|
||||
/// Extension trait that has `get_*` methods
|
||||
pub extension_trait: &'static str,
|
||||
/// All methods.
|
||||
pub methods: &'static [MethodProto],
|
||||
/// All methods registered as normal methods like `#[pymethods]`.
|
||||
pub py_methods: &'static [PyMethod],
|
||||
/// All methods registered to the slot table.
|
||||
slot_setters: &'static [SlotSetter],
|
||||
slot_getters: &'static [SlotGetter],
|
||||
}
|
||||
|
||||
impl Proto {
|
||||
|
@ -32,13 +30,13 @@ impl Proto {
|
|||
self.py_methods.iter().find(|m| query == m.name)
|
||||
}
|
||||
// Since the order matters, we expose only the iterator instead of the slice.
|
||||
pub(crate) fn setters(
|
||||
pub(crate) fn slot_getters(
|
||||
&self,
|
||||
mut implemented_protocols: HashSet<String>,
|
||||
) -> impl Iterator<Item = &'static str> {
|
||||
self.slot_setters.iter().filter_map(move |setter| {
|
||||
self.slot_getters.iter().filter_map(move |getter| {
|
||||
// If any required method is not implemented, we skip this setter.
|
||||
if setter
|
||||
if getter
|
||||
.proto_names
|
||||
.iter()
|
||||
.any(|name| !implemented_protocols.contains(*name))
|
||||
|
@ -47,10 +45,10 @@ impl Proto {
|
|||
}
|
||||
// To use 'paired' setter in priority, we remove used protocols.
|
||||
// For example, if set_add_radd is already used, we shouldn't use set_add and set_radd.
|
||||
for name in setter.proto_names {
|
||||
for name in getter.proto_names {
|
||||
implemented_protocols.remove(*name);
|
||||
}
|
||||
Some(setter.set_function)
|
||||
Some(getter.get_function)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -82,27 +80,26 @@ impl PyMethod {
|
|||
}
|
||||
|
||||
/// Represents a setter used to register a method to the method table.
|
||||
struct SlotSetter {
|
||||
struct SlotGetter {
|
||||
/// Protocols necessary for invoking this setter.
|
||||
/// E.g., we need `__setattr__` and `__delattr__` for invoking `set_setdelitem`.
|
||||
pub proto_names: &'static [&'static str],
|
||||
/// The name of the setter called to the method table.
|
||||
pub set_function: &'static str,
|
||||
pub get_function: &'static str,
|
||||
}
|
||||
|
||||
impl SlotSetter {
|
||||
const fn new(names: &'static [&'static str], set_function: &'static str) -> Self {
|
||||
SlotSetter {
|
||||
impl SlotGetter {
|
||||
const fn new(names: &'static [&'static str], get_function: &'static str) -> Self {
|
||||
SlotGetter {
|
||||
proto_names: names,
|
||||
set_function,
|
||||
get_function,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const OBJECT: Proto = Proto {
|
||||
name: "Object",
|
||||
slot_table: "pyo3::class::basic::PyObjectMethods",
|
||||
set_slot_table: "set_basic_methods",
|
||||
extension_trait: "pyo3::class::basic::PyBasicSlots",
|
||||
methods: &[
|
||||
MethodProto::Binary {
|
||||
name: "__getattr__",
|
||||
|
@ -156,23 +153,22 @@ pub const OBJECT: Proto = Proto {
|
|||
PyMethod::new("__bytes__", "pyo3::class::basic::BytesProtocolImpl"),
|
||||
PyMethod::new("__unicode__", "pyo3::class::basic::UnicodeProtocolImpl"),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__str__"], "set_str"),
|
||||
SlotSetter::new(&["__repr__"], "set_repr"),
|
||||
SlotSetter::new(&["__hash__"], "set_hash"),
|
||||
SlotSetter::new(&["__getattr__"], "set_getattr"),
|
||||
SlotSetter::new(&["__richcmp__"], "set_richcompare"),
|
||||
SlotSetter::new(&["__setattr__", "__delattr__"], "set_setdelattr"),
|
||||
SlotSetter::new(&["__setattr__"], "set_setattr"),
|
||||
SlotSetter::new(&["__delattr__"], "set_delattr"),
|
||||
SlotSetter::new(&["__bool__"], "set_bool"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__str__"], "get_str"),
|
||||
SlotGetter::new(&["__repr__"], "get_repr"),
|
||||
SlotGetter::new(&["__hash__"], "get_hash"),
|
||||
SlotGetter::new(&["__getattr__"], "get_getattr"),
|
||||
SlotGetter::new(&["__richcmp__"], "get_richcmp"),
|
||||
SlotGetter::new(&["__setattr__", "__delattr__"], "get_setdelattr"),
|
||||
SlotGetter::new(&["__setattr__"], "get_setattr"),
|
||||
SlotGetter::new(&["__delattr__"], "get_delattr"),
|
||||
SlotGetter::new(&["__bool__"], "get_bool"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ASYNC: Proto = Proto {
|
||||
name: "Async",
|
||||
slot_table: "pyo3::ffi::PyAsyncMethods",
|
||||
set_slot_table: "set_async_methods",
|
||||
extension_trait: "pyo3::class::pyasync::PyAsyncSlots",
|
||||
methods: &[
|
||||
MethodProto::UnaryS {
|
||||
name: "__await__",
|
||||
|
@ -211,17 +207,16 @@ pub const ASYNC: Proto = Proto {
|
|||
"pyo3::class::pyasync::PyAsyncAexitProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__await__"], "set_await"),
|
||||
SlotSetter::new(&["__aiter__"], "set_aiter"),
|
||||
SlotSetter::new(&["__anext__"], "set_anext"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__await__"], "get_await"),
|
||||
SlotGetter::new(&["__aiter__"], "get_aiter"),
|
||||
SlotGetter::new(&["__anext__"], "get_anext"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const BUFFER: Proto = Proto {
|
||||
name: "Buffer",
|
||||
slot_table: "pyo3::ffi::PyBufferProcs",
|
||||
set_slot_table: "set_buffer_methods",
|
||||
extension_trait: "pyo3::class::buffer::PyBufferSlots",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "bf_getbuffer",
|
||||
|
@ -233,16 +228,15 @@ pub const BUFFER: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["bf_getbuffer"], "set_getbuffer"),
|
||||
SlotSetter::new(&["bf_releasebuffer"], "set_releasebuffer"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["bf_getbuffer"], "get_getbuffer"),
|
||||
SlotGetter::new(&["bf_releasebuffer"], "get_releasebuffer"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const CONTEXT: Proto = Proto {
|
||||
name: "Context",
|
||||
slot_table: "",
|
||||
set_slot_table: "",
|
||||
extension_trait: "",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__enter__",
|
||||
|
@ -266,13 +260,12 @@ pub const CONTEXT: Proto = Proto {
|
|||
"pyo3::class::context::PyContextExitProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[],
|
||||
slot_getters: &[],
|
||||
};
|
||||
|
||||
pub const GC: Proto = Proto {
|
||||
name: "GC",
|
||||
slot_table: "pyo3::class::gc::PyGCMethods",
|
||||
set_slot_table: "set_gc_methods",
|
||||
extension_trait: "pyo3::class::gc::PyGCSlots",
|
||||
methods: &[
|
||||
MethodProto::Free {
|
||||
name: "__traverse__",
|
||||
|
@ -284,16 +277,15 @@ pub const GC: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__traverse__"], "set_traverse"),
|
||||
SlotSetter::new(&["__clear__"], "set_clear"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__traverse__"], "get_traverse"),
|
||||
SlotGetter::new(&["__clear__"], "get_clear"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const DESCR: Proto = Proto {
|
||||
name: "Descriptor",
|
||||
slot_table: "pyo3::class::descr::PyDescrMethods",
|
||||
set_slot_table: "set_descr_methods",
|
||||
extension_trait: "pyo3::class::descr::PyDescrSlots",
|
||||
methods: &[
|
||||
MethodProto::TernaryS {
|
||||
name: "__get__",
|
||||
|
@ -327,16 +319,15 @@ pub const DESCR: Proto = Proto {
|
|||
"pyo3::class::context::PyDescrNameProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__get__"], "set_descr_get"),
|
||||
SlotSetter::new(&["__set__"], "set_descr_set"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__get__"], "get_descr_get"),
|
||||
SlotGetter::new(&["__set__"], "get_descr_set"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ITER: Proto = Proto {
|
||||
name: "Iter",
|
||||
slot_table: "pyo3::class::iter::PyIterMethods",
|
||||
set_slot_table: "set_iter_methods",
|
||||
extension_trait: "pyo3::class::iter::PyIterSlots",
|
||||
py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::UnaryS {
|
||||
|
@ -350,16 +341,15 @@ pub const ITER: Proto = Proto {
|
|||
proto: "pyo3::class::iter::PyIterNextProtocol",
|
||||
},
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__iter__"], "set_iter"),
|
||||
SlotSetter::new(&["__next__"], "set_iternext"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__iter__"], "get_iter"),
|
||||
SlotGetter::new(&["__next__"], "get_iternext"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const MAPPING: Proto = Proto {
|
||||
name: "Mapping",
|
||||
slot_table: "pyo3::ffi::PyMappingMethods",
|
||||
set_slot_table: "set_mapping_methods",
|
||||
extension_trait: "pyo3::class::mapping::PyMappingSlots",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__len__",
|
||||
|
@ -390,19 +380,18 @@ pub const MAPPING: Proto = Proto {
|
|||
"__reversed__",
|
||||
"pyo3::class::mapping::PyMappingReversedProtocolImpl",
|
||||
)],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__len__"], "set_length"),
|
||||
SlotSetter::new(&["__getitem__"], "set_getitem"),
|
||||
SlotSetter::new(&["__setitem__", "__delitem__"], "set_setdelitem"),
|
||||
SlotSetter::new(&["__setitem__"], "set_setitem"),
|
||||
SlotSetter::new(&["__delitem__"], "set_delitem"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__len__"], "get_len"),
|
||||
SlotGetter::new(&["__getitem__"], "get_getitem"),
|
||||
SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"),
|
||||
SlotGetter::new(&["__setitem__"], "get_setitem"),
|
||||
SlotGetter::new(&["__delitem__"], "get_delitem"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const SEQ: Proto = Proto {
|
||||
name: "Sequence",
|
||||
slot_table: "pyo3::ffi::PySequenceMethods",
|
||||
set_slot_table: "set_sequence_methods",
|
||||
extension_trait: "pyo3::class::sequence::PySequenceSlots",
|
||||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__len__",
|
||||
|
@ -451,24 +440,23 @@ pub const SEQ: Proto = Proto {
|
|||
},
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__len__"], "set_len"),
|
||||
SlotSetter::new(&["__concat__"], "set_concat"),
|
||||
SlotSetter::new(&["__repeat__"], "set_repeat"),
|
||||
SlotSetter::new(&["__getitem__"], "set_getitem"),
|
||||
SlotSetter::new(&["__setitem__", "__delitem__"], "set_setdelitem"),
|
||||
SlotSetter::new(&["__setitem__"], "set_setitem"),
|
||||
SlotSetter::new(&["__delitem__"], "set_delitem"),
|
||||
SlotSetter::new(&["__contains__"], "set_contains"),
|
||||
SlotSetter::new(&["__inplace_concat__"], "set_inplace_concat"),
|
||||
SlotSetter::new(&["__inplace_repeat__"], "set_inplace_repeat"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__len__"], "get_len"),
|
||||
SlotGetter::new(&["__concat__"], "get_concat"),
|
||||
SlotGetter::new(&["__repeat__"], "get_repeat"),
|
||||
SlotGetter::new(&["__getitem__"], "get_getitem"),
|
||||
SlotGetter::new(&["__setitem__", "__delitem__"], "get_setdelitem"),
|
||||
SlotGetter::new(&["__setitem__"], "get_setitem"),
|
||||
SlotGetter::new(&["__delitem__"], "get_delitem"),
|
||||
SlotGetter::new(&["__contains__"], "get_contains"),
|
||||
SlotGetter::new(&["__inplace_concat__"], "get_inplace_concat"),
|
||||
SlotGetter::new(&["__inplace_repeat__"], "get_inplace_repeat"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const NUM: Proto = Proto {
|
||||
name: "Number",
|
||||
slot_table: "pyo3::ffi::PyNumberMethods",
|
||||
set_slot_table: "set_number_methods",
|
||||
extension_trait: "pyo3::class::number::PyNumberSlots",
|
||||
methods: &[
|
||||
MethodProto::BinaryS {
|
||||
name: "__add__",
|
||||
|
@ -771,66 +759,66 @@ pub const NUM: Proto = Proto {
|
|||
"pyo3::class::number::PyNumberRoundProtocolImpl",
|
||||
),
|
||||
],
|
||||
slot_setters: &[
|
||||
SlotSetter::new(&["__add__", "__radd__"], "set_add_radd"),
|
||||
SlotSetter::new(&["__add__"], "set_add"),
|
||||
SlotSetter::new(&["__radd__"], "set_radd"),
|
||||
SlotSetter::new(&["__sub__", "__rsub__"], "set_sub_rsub"),
|
||||
SlotSetter::new(&["__sub__"], "set_sub"),
|
||||
SlotSetter::new(&["__rsub__"], "set_rsub"),
|
||||
SlotSetter::new(&["__mul__", "__rmul__"], "set_mul_rmul"),
|
||||
SlotSetter::new(&["__mul__"], "set_mul"),
|
||||
SlotSetter::new(&["__rmul__"], "set_rmul"),
|
||||
SlotSetter::new(&["__mod__"], "set_mod"),
|
||||
SlotSetter::new(&["__divmod__", "__rdivmod__"], "set_divmod_rdivmod"),
|
||||
SlotSetter::new(&["__divmod__"], "set_divmod"),
|
||||
SlotSetter::new(&["__rdivmod__"], "set_rdivmod"),
|
||||
SlotSetter::new(&["__pow__", "__rpow__"], "set_pow_rpow"),
|
||||
SlotSetter::new(&["__pow__"], "set_pow"),
|
||||
SlotSetter::new(&["__rpow__"], "set_rpow"),
|
||||
SlotSetter::new(&["__neg__"], "set_neg"),
|
||||
SlotSetter::new(&["__pos__"], "set_pos"),
|
||||
SlotSetter::new(&["__abs__"], "set_abs"),
|
||||
SlotSetter::new(&["__invert__"], "set_invert"),
|
||||
SlotSetter::new(&["__lshift__", "__rlshift__"], "set_lshift_rlshift"),
|
||||
SlotSetter::new(&["__lshift__"], "set_lshift"),
|
||||
SlotSetter::new(&["__rlshift__"], "set_rlshift"),
|
||||
SlotSetter::new(&["__rshift__", "__rrshift__"], "set_rshift_rrshift"),
|
||||
SlotSetter::new(&["__rshift__"], "set_rshift"),
|
||||
SlotSetter::new(&["__rrshift__"], "set_rrshift"),
|
||||
SlotSetter::new(&["__and__", "__rand__"], "set_and_rand"),
|
||||
SlotSetter::new(&["__and__"], "set_and"),
|
||||
SlotSetter::new(&["__rand__"], "set_rand"),
|
||||
SlotSetter::new(&["__xor__", "__rxor__"], "set_xor_rxor"),
|
||||
SlotSetter::new(&["__xor__"], "set_xor"),
|
||||
SlotSetter::new(&["__rxor__"], "set_rxor"),
|
||||
SlotSetter::new(&["__or__", "__ror__"], "set_or_ror"),
|
||||
SlotSetter::new(&["__or__"], "set_or"),
|
||||
SlotSetter::new(&["__ror__"], "set_ror"),
|
||||
SlotSetter::new(&["__int__"], "set_int"),
|
||||
SlotSetter::new(&["__float__"], "set_float"),
|
||||
SlotSetter::new(&["__iadd__"], "set_iadd"),
|
||||
SlotSetter::new(&["__isub__"], "set_isub"),
|
||||
SlotSetter::new(&["__imul__"], "set_imul"),
|
||||
SlotSetter::new(&["__imod__"], "set_imod"),
|
||||
SlotSetter::new(&["__ipow__"], "set_ipow"),
|
||||
SlotSetter::new(&["__ilshift__"], "set_ilshift"),
|
||||
SlotSetter::new(&["__irshift__"], "set_irshift"),
|
||||
SlotSetter::new(&["__iand__"], "set_iand"),
|
||||
SlotSetter::new(&["__ixor__"], "set_ixor"),
|
||||
SlotSetter::new(&["__ior__"], "set_ior"),
|
||||
SlotSetter::new(&["__floordiv__", "__rfloordiv__"], "set_floordiv_rfloordiv"),
|
||||
SlotSetter::new(&["__floordiv__"], "set_floordiv"),
|
||||
SlotSetter::new(&["__rfloordiv__"], "set_rfloordiv"),
|
||||
SlotSetter::new(&["__truediv__", "__rtruediv__"], "set_truediv_rtruediv"),
|
||||
SlotSetter::new(&["__truediv__"], "set_truediv"),
|
||||
SlotSetter::new(&["__rtruediv__"], "set_rtruediv"),
|
||||
SlotSetter::new(&["__ifloordiv__"], "set_ifloordiv"),
|
||||
SlotSetter::new(&["__itruediv__"], "set_itruediv"),
|
||||
SlotSetter::new(&["__index__"], "set_index"),
|
||||
SlotSetter::new(&["__matmul__", "__rmatmul__"], "set_matmul_rmatmul"),
|
||||
SlotSetter::new(&["__matmul__"], "set_matmul"),
|
||||
SlotSetter::new(&["__rmatmul__"], "set_rmatmul"),
|
||||
SlotSetter::new(&["__imatmul__"], "set_imatmul"),
|
||||
slot_getters: &[
|
||||
SlotGetter::new(&["__add__", "__radd__"], "get_add_radd"),
|
||||
SlotGetter::new(&["__add__"], "get_add"),
|
||||
SlotGetter::new(&["__radd__"], "get_radd"),
|
||||
SlotGetter::new(&["__sub__", "__rsub__"], "get_sub_rsub"),
|
||||
SlotGetter::new(&["__sub__"], "get_sub"),
|
||||
SlotGetter::new(&["__rsub__"], "get_rsub"),
|
||||
SlotGetter::new(&["__mul__", "__rmul__"], "get_mul_rmul"),
|
||||
SlotGetter::new(&["__mul__"], "get_mul"),
|
||||
SlotGetter::new(&["__rmul__"], "get_rmul"),
|
||||
SlotGetter::new(&["__mod__"], "get_mod"),
|
||||
SlotGetter::new(&["__divmod__", "__rdivmod__"], "get_divmod_rdivmod"),
|
||||
SlotGetter::new(&["__divmod__"], "get_divmod"),
|
||||
SlotGetter::new(&["__rdivmod__"], "get_rdivmod"),
|
||||
SlotGetter::new(&["__pow__", "__rpow__"], "get_pow_rpow"),
|
||||
SlotGetter::new(&["__pow__"], "get_pow"),
|
||||
SlotGetter::new(&["__rpow__"], "get_rpow"),
|
||||
SlotGetter::new(&["__neg__"], "get_neg"),
|
||||
SlotGetter::new(&["__pos__"], "get_pos"),
|
||||
SlotGetter::new(&["__abs__"], "get_abs"),
|
||||
SlotGetter::new(&["__invert__"], "get_invert"),
|
||||
SlotGetter::new(&["__lshift__", "__rlshift__"], "get_lshift_rlshift"),
|
||||
SlotGetter::new(&["__lshift__"], "get_lshift"),
|
||||
SlotGetter::new(&["__rlshift__"], "get_rlshift"),
|
||||
SlotGetter::new(&["__rshift__", "__rrshift__"], "get_rshift_rrshift"),
|
||||
SlotGetter::new(&["__rshift__"], "get_rshift"),
|
||||
SlotGetter::new(&["__rrshift__"], "get_rrshift"),
|
||||
SlotGetter::new(&["__and__", "__rand__"], "get_and_rand"),
|
||||
SlotGetter::new(&["__and__"], "get_and"),
|
||||
SlotGetter::new(&["__rand__"], "get_rand"),
|
||||
SlotGetter::new(&["__xor__", "__rxor__"], "get_xor_rxor"),
|
||||
SlotGetter::new(&["__xor__"], "get_xor"),
|
||||
SlotGetter::new(&["__rxor__"], "get_rxor"),
|
||||
SlotGetter::new(&["__or__", "__ror__"], "get_or_ror"),
|
||||
SlotGetter::new(&["__or__"], "get_or"),
|
||||
SlotGetter::new(&["__ror__"], "get_ror"),
|
||||
SlotGetter::new(&["__int__"], "get_int"),
|
||||
SlotGetter::new(&["__float__"], "get_float"),
|
||||
SlotGetter::new(&["__iadd__"], "get_iadd"),
|
||||
SlotGetter::new(&["__isub__"], "get_isub"),
|
||||
SlotGetter::new(&["__imul__"], "get_imul"),
|
||||
SlotGetter::new(&["__imod__"], "get_imod"),
|
||||
SlotGetter::new(&["__ipow__"], "get_ipow"),
|
||||
SlotGetter::new(&["__ilshift__"], "get_ilshift"),
|
||||
SlotGetter::new(&["__irshift__"], "get_irshift"),
|
||||
SlotGetter::new(&["__iand__"], "get_iand"),
|
||||
SlotGetter::new(&["__ixor__"], "get_ixor"),
|
||||
SlotGetter::new(&["__ior__"], "get_ior"),
|
||||
SlotGetter::new(&["__floordiv__", "__rfloordiv__"], "get_floordiv_rfloordiv"),
|
||||
SlotGetter::new(&["__floordiv__"], "get_floordiv"),
|
||||
SlotGetter::new(&["__rfloordiv__"], "get_rfloordiv"),
|
||||
SlotGetter::new(&["__truediv__", "__rtruediv__"], "get_truediv_rtruediv"),
|
||||
SlotGetter::new(&["__truediv__"], "get_truediv"),
|
||||
SlotGetter::new(&["__rtruediv__"], "get_rtruediv"),
|
||||
SlotGetter::new(&["__ifloordiv__"], "get_ifloordiv"),
|
||||
SlotGetter::new(&["__itruediv__"], "get_itruediv"),
|
||||
SlotGetter::new(&["__index__"], "get_index"),
|
||||
SlotGetter::new(&["__matmul__", "__rmatmul__"], "get_matmul_rmatmul"),
|
||||
SlotGetter::new(&["__matmul__"], "get_matmul"),
|
||||
SlotGetter::new(&["__rmatmul__"], "get_rmatmul"),
|
||||
SlotGetter::new(&["__imatmul__"], "get_imatmul"),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -72,7 +72,7 @@ impl<'a> Enum<'a> {
|
|||
};
|
||||
quote!(
|
||||
#(#var_extracts)*
|
||||
let type_name = obj.get_type().name();
|
||||
let type_name = obj.get_type().name()?;
|
||||
let err_msg = format!("'{}' object cannot be converted to '{}'", type_name, #error_names);
|
||||
Err(::pyo3::exceptions::PyTypeError::new_err(err_msg))
|
||||
)
|
||||
|
@ -246,7 +246,7 @@ impl<'a> Container<'a> {
|
|||
let self_ty = &self.path;
|
||||
let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new();
|
||||
for i in 0..len {
|
||||
fields.push(quote!(slice[#i].extract()?));
|
||||
fields.push(quote!(s.get_item(#i).extract()?));
|
||||
}
|
||||
let msg = if self.is_enum_variant {
|
||||
quote!(format!(
|
||||
|
@ -262,7 +262,6 @@ impl<'a> Container<'a> {
|
|||
if s.len() != #len {
|
||||
return Err(::pyo3::exceptions::PyValueError::new_err(#msg))
|
||||
}
|
||||
let slice = s.as_slice();
|
||||
Ok(#self_ty(#fields))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -234,16 +234,31 @@ fn impl_methods_inventory(cls: &syn::Ident) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// Implement `HasProtoRegistry` for the class for lazy protocol initialization.
|
||||
fn impl_proto_registry(cls: &syn::Ident) -> TokenStream {
|
||||
/// Implement `HasProtoInventory` for the class for lazy protocol initialization.
|
||||
fn impl_proto_inventory(cls: &syn::Ident) -> TokenStream {
|
||||
// Try to build a unique type for better error messages
|
||||
let name = format!("Pyo3ProtoInventoryFor{}", cls);
|
||||
let inventory_cls = syn::Ident::new(&name, Span::call_site());
|
||||
|
||||
quote! {
|
||||
impl pyo3::class::proto_methods::HasProtoRegistry for #cls {
|
||||
fn registry() -> &'static pyo3::class::proto_methods::PyProtoRegistry {
|
||||
static REGISTRY: pyo3::class::proto_methods::PyProtoRegistry
|
||||
= pyo3::class::proto_methods::PyProtoRegistry::new();
|
||||
®ISTRY
|
||||
#[doc(hidden)]
|
||||
pub struct #inventory_cls {
|
||||
def: pyo3::class::proto_methods::PyProtoMethodDef,
|
||||
}
|
||||
impl pyo3::class::proto_methods::PyProtoInventory for #inventory_cls {
|
||||
fn new(def: pyo3::class::proto_methods::PyProtoMethodDef) -> Self {
|
||||
Self { def }
|
||||
}
|
||||
fn get(&'static self) -> &'static pyo3::class::proto_methods::PyProtoMethodDef {
|
||||
&self.def
|
||||
}
|
||||
}
|
||||
|
||||
impl pyo3::class::proto_methods::HasProtoInventory for #cls {
|
||||
type ProtoMethods = #inventory_cls;
|
||||
}
|
||||
|
||||
pyo3::inventory::collect!(#inventory_cls);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -351,7 +366,7 @@ fn impl_class(
|
|||
};
|
||||
|
||||
let impl_inventory = impl_methods_inventory(&cls);
|
||||
let impl_proto_registry = impl_proto_registry(&cls);
|
||||
let impl_proto_inventory = impl_proto_inventory(&cls);
|
||||
|
||||
let base = &attr.base;
|
||||
let flags = &attr.flags;
|
||||
|
@ -440,7 +455,7 @@ fn impl_class(
|
|||
|
||||
#impl_inventory
|
||||
|
||||
#impl_proto_registry
|
||||
#impl_proto_inventory
|
||||
|
||||
#extra
|
||||
|
||||
|
|
|
@ -106,16 +106,16 @@ fn impl_proto_impl(
|
|||
}
|
||||
}
|
||||
}
|
||||
let inventory_submission = inventory_submission(py_methods, ty);
|
||||
let slot_initialization = slot_initialization(method_names, ty, proto)?;
|
||||
let normal_methods = submit_normal_methods(py_methods, ty);
|
||||
let protocol_methods = submit_protocol_methods(method_names, ty, proto)?;
|
||||
Ok(quote! {
|
||||
#trait_impls
|
||||
#inventory_submission
|
||||
#slot_initialization
|
||||
#normal_methods
|
||||
#protocol_methods
|
||||
})
|
||||
}
|
||||
|
||||
fn inventory_submission(py_methods: Vec<TokenStream>, ty: &syn::Type) -> TokenStream {
|
||||
fn submit_normal_methods(py_methods: Vec<TokenStream>, ty: &syn::Type) -> TokenStream {
|
||||
if py_methods.is_empty() {
|
||||
return quote! {};
|
||||
}
|
||||
|
@ -129,42 +129,49 @@ fn inventory_submission(py_methods: Vec<TokenStream>, ty: &syn::Type) -> TokenSt
|
|||
}
|
||||
}
|
||||
|
||||
fn slot_initialization(
|
||||
fn submit_protocol_methods(
|
||||
method_names: HashSet<String>,
|
||||
ty: &syn::Type,
|
||||
proto: &defs::Proto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
// Collect initializers
|
||||
let mut initializers: Vec<TokenStream> = vec![];
|
||||
for setter in proto.setters(method_names) {
|
||||
// Add slot methods to PyProtoRegistry
|
||||
let set = syn::Ident::new(setter, Span::call_site());
|
||||
initializers.push(quote! { table.#set::<#ty>(); });
|
||||
}
|
||||
if initializers.is_empty() {
|
||||
if proto.extension_trait == "" {
|
||||
return Ok(quote! {});
|
||||
}
|
||||
let ext_trait: syn::Path = syn::parse_str(proto.extension_trait)?;
|
||||
let mut tokens = vec![];
|
||||
if proto.name == "Buffer" {
|
||||
// For buffer, we construct `PyProtoMethods` from PyBufferProcs
|
||||
tokens.push(quote! {
|
||||
let mut proto_methods = pyo3::ffi::PyBufferProcs::default();
|
||||
});
|
||||
for getter in proto.slot_getters(method_names) {
|
||||
let get = syn::Ident::new(getter, Span::call_site());
|
||||
let field = syn::Ident::new(&format!("bf_{}", &getter[4..]), Span::call_site());
|
||||
tokens.push(quote! { proto_methods.#field = Some(<#ty as #ext_trait>::#get()); });
|
||||
}
|
||||
} else {
|
||||
// For other protocols, we construct `PyProtoMethods` from Vec<ffi::PyType_Slot>
|
||||
tokens.push(quote! { let mut proto_methods = vec![]; });
|
||||
for getter in proto.slot_getters(method_names) {
|
||||
let get = syn::Ident::new(getter, Span::call_site());
|
||||
tokens.push(quote! {
|
||||
let slot = <#ty as #ext_trait>::#get();
|
||||
proto_methods.push(pyo3::ffi::PyType_Slot { slot: slot.0, pfunc: slot.1 as _ });
|
||||
});
|
||||
}
|
||||
};
|
||||
if tokens.len() <= 1 {
|
||||
return Ok(quote! {});
|
||||
}
|
||||
let table: syn::Path = syn::parse_str(proto.slot_table)?;
|
||||
let set = syn::Ident::new(proto.set_slot_table, Span::call_site());
|
||||
let ty_hash = typename_hash(ty);
|
||||
let init = syn::Ident::new(
|
||||
&format!("__init_{}_{}", proto.name, ty_hash),
|
||||
Span::call_site(),
|
||||
);
|
||||
Ok(quote! {
|
||||
#[allow(non_snake_case)]
|
||||
#[pyo3::ctor::ctor]
|
||||
fn #init() {
|
||||
let mut table = #table::default();
|
||||
#(#initializers)*
|
||||
<#ty as pyo3::class::proto_methods::HasProtoRegistry>::registry().#set(table);
|
||||
pyo3::inventory::submit! {
|
||||
#![crate = pyo3] {
|
||||
type Inventory =
|
||||
<#ty as pyo3::class::proto_methods::HasProtoInventory>::ProtoMethods;
|
||||
<Inventory as pyo3::class::proto_methods::PyProtoInventory>::new(
|
||||
{ #(#tokens)* proto_methods.into() }
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn typename_hash(ty: &syn::Type) -> u64 {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
ty.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//! Parts of the documentation are copied from the respective methods from the
|
||||
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
|
||||
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject, PyResult};
|
||||
use std::os::raw::c_int;
|
||||
|
@ -133,95 +134,43 @@ pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// All FFI functions for basic protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyObjectMethods {
|
||||
pub tp_str: Option<ffi::reprfunc>,
|
||||
pub tp_repr: Option<ffi::reprfunc>,
|
||||
pub tp_hash: Option<ffi::hashfunc>,
|
||||
pub tp_getattro: Option<ffi::getattrofunc>,
|
||||
pub tp_richcompare: Option<ffi::richcmpfunc>,
|
||||
pub tp_setattro: Option<ffi::setattrofunc>,
|
||||
pub nb_bool: Option<ffi::inquiry>,
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyObjectMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_str = self.tp_str;
|
||||
type_object.tp_repr = self.tp_repr;
|
||||
type_object.tp_hash = self.tp_hash;
|
||||
type_object.tp_getattro = self.tp_getattro;
|
||||
type_object.tp_richcompare = self.tp_richcompare;
|
||||
type_object.tp_setattro = self.tp_setattro;
|
||||
}
|
||||
// Set functions used by `#[pyproto]`.
|
||||
pub fn set_str<T>(&mut self)
|
||||
pub trait PyBasicSlots {
|
||||
fn get_str() -> TypedSlot<ffi::reprfunc>
|
||||
where
|
||||
T: for<'p> PyObjectStrProtocol<'p>,
|
||||
Self: for<'p> PyObjectStrProtocol<'p>,
|
||||
{
|
||||
self.tp_str = py_unary_func!(PyObjectStrProtocol, T::__str__);
|
||||
}
|
||||
pub fn set_repr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
self.tp_repr = py_unary_func!(PyObjectReprProtocol, T::__repr__);
|
||||
}
|
||||
pub fn set_hash<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
self.tp_hash = py_unary_func!(PyObjectHashProtocol, T::__hash__, ffi::Py_hash_t);
|
||||
}
|
||||
pub fn set_getattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_getattro = tp_getattro::<T>();
|
||||
}
|
||||
pub fn set_richcompare<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
self.tp_richcompare = tp_richcompare::<T>();
|
||||
}
|
||||
pub fn set_setattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set!(PyObjectSetAttrProtocol, T, __setattr__);
|
||||
}
|
||||
pub fn set_delattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_del!(PyObjectDelAttrProtocol, T, __delattr__);
|
||||
}
|
||||
pub fn set_setdelattr<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
self.tp_setattro = py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
T,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
TypedSlot(
|
||||
ffi::Py_tp_str,
|
||||
py_unary_func!(PyObjectStrProtocol, Self::__str__),
|
||||
)
|
||||
}
|
||||
pub fn set_bool<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
self.nb_bool = py_unary_func!(PyObjectBoolProtocol, T::__bool__, c_int);
|
||||
}
|
||||
}
|
||||
|
||||
fn tp_getattro<T>() -> Option<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
fn get_repr() -> TypedSlot<ffi::reprfunc>
|
||||
where
|
||||
Self: for<'p> PyObjectReprProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_repr,
|
||||
py_unary_func!(PyObjectReprProtocol, Self::__repr__),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_hash() -> TypedSlot<ffi::hashfunc>
|
||||
where
|
||||
Self: for<'p> PyObjectHashProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_hash,
|
||||
py_unary_func!(PyObjectHashProtocol, Self::__hash__, ffi::Py_hash_t),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_getattr() -> TypedSlot<ffi::getattrofunc>
|
||||
where
|
||||
Self: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
|
@ -245,13 +194,13 @@ where
|
|||
call_ref!(slf, __getattr__, arg).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
TypedSlot(ffi::Py_tp_getattro, wrap::<Self>)
|
||||
}
|
||||
|
||||
fn tp_richcompare<T>() -> Option<ffi::richcmpfunc>
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
fn get_richcmp() -> TypedSlot<ffi::richcmpfunc>
|
||||
where
|
||||
Self: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
fn extract_op(op: c_int) -> PyResult<CompareOp> {
|
||||
match op {
|
||||
ffi::Py_LT => Ok(CompareOp::Lt),
|
||||
|
@ -281,5 +230,54 @@ where
|
|||
slf.try_borrow()?.__richcmp__(arg, op).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
TypedSlot(ffi::Py_tp_richcompare, wrap::<Self>)
|
||||
}
|
||||
|
||||
fn get_setattr() -> TypedSlot<ffi::setattrofunc>
|
||||
where
|
||||
Self: for<'p> PyObjectSetAttrProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_setattro,
|
||||
py_func_set!(PyObjectSetAttrProtocol, Self::__setattr__),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_delattr() -> TypedSlot<ffi::setattrofunc>
|
||||
where
|
||||
Self: for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_setattro,
|
||||
py_func_del!(PyObjectDelAttrProtocol, Self::__delattr__),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_setdelattr() -> TypedSlot<ffi::setattrofunc>
|
||||
where
|
||||
Self: for<'p> PyObjectSetAttrProtocol<'p> + for<'p> PyObjectDelAttrProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_setattro,
|
||||
py_func_set_del!(
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
Self,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_bool() -> TypedSlot<ffi::inquiry>
|
||||
where
|
||||
Self: for<'p> PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_nb_bool,
|
||||
py_unary_func!(PyObjectBoolProtocol, Self::__bool__, c_int),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyBasicSlots for T where T: PyObjectProtocol<'p> {}
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
//! c-api
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{
|
||||
ffi::{self, PyBufferProcs},
|
||||
PyCell, PyClass, PyRefMut,
|
||||
};
|
||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Buffer protocol interface
|
||||
|
@ -40,27 +37,13 @@ pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
/// Set functions used by `#[pyproto]`.
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyBufferProcs {
|
||||
pub fn set_getbuffer<T>(&mut self)
|
||||
pub trait PyBufferSlots {
|
||||
fn get_getbuffer() -> ffi::getbufferproc
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
Self: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
self.bf_getbuffer = bf_getbuffer::<T>();
|
||||
}
|
||||
pub fn set_releasebuffer<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
self.bf_releasebuffer = bf_releasebuffer::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
fn bf_getbuffer<T>() -> Option<ffi::getbufferproc>
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg1: *mut ffi::Py_buffer,
|
||||
|
@ -74,13 +57,14 @@ where
|
|||
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
|
||||
fn bf_releasebuffer<T>() -> Option<ffi::releasebufferproc>
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
wrap::<Self>
|
||||
}
|
||||
|
||||
fn get_releasebuffer() -> ffi::releasebufferproc
|
||||
where
|
||||
Self: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
|
@ -90,5 +74,9 @@ where
|
|||
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
|
||||
wrap::<Self>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyBufferSlots for T where T: PyBufferProtocol<'p> {}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//! [Python information](
|
||||
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::types::PyAny;
|
||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
||||
|
@ -70,29 +71,28 @@ pub trait PyDescrSetNameProtocol<'p>: PyDescrProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
/// All FFI functions for description protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyDescrMethods {
|
||||
pub tp_descr_get: Option<ffi::descrgetfunc>,
|
||||
pub tp_descr_set: Option<ffi::descrsetfunc>,
|
||||
/// Extension trait for our proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
pub trait PyDescrSlots {
|
||||
fn get_descr_get() -> TypedSlot<ffi::descrgetfunc>
|
||||
where
|
||||
Self: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_descr_get,
|
||||
py_ternarys_func!(PyDescrGetProtocol, Self::__get__),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_descr_set() -> TypedSlot<ffi::descrsetfunc>
|
||||
where
|
||||
Self: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_descr_set,
|
||||
py_ternarys_func!(PyDescrSetProtocol, Self::__set__, c_int),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl PyDescrMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_descr_get = self.tp_descr_get;
|
||||
type_object.tp_descr_set = self.tp_descr_set;
|
||||
}
|
||||
pub fn set_descr_get<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrGetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_get = py_ternarys_func!(PyDescrGetProtocol, T::__get__);
|
||||
}
|
||||
pub fn set_descr_set<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyDescrSetProtocol<'p>,
|
||||
{
|
||||
self.tp_descr_set = py_ternarys_func!(PyDescrSetProtocol, T::__set__, c_int);
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyDescrSlots for T where T: PyDescrProtocol<'p> {}
|
||||
|
|
112
src/class/gc.rs
112
src/class/gc.rs
|
@ -3,6 +3,7 @@
|
|||
//! Python GC support
|
||||
//!
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
|
@ -18,66 +19,14 @@ pub trait PyGCProtocol<'p>: PyClass {
|
|||
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
|
||||
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
|
||||
|
||||
/// All FFI functions for gc protocols.
|
||||
#[derive(Default)]
|
||||
pub struct PyGCMethods {
|
||||
pub tp_traverse: Option<ffi::traverseproc>,
|
||||
pub tp_clear: Option<ffi::inquiry>,
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl PyGCMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_traverse = self.tp_traverse;
|
||||
type_object.tp_clear = self.tp_clear;
|
||||
}
|
||||
|
||||
pub fn set_traverse<T>(&mut self)
|
||||
pub trait PyGCSlots {
|
||||
fn get_traverse() -> TypedSlot<ffi::traverseproc>
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
Self: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
self.tp_traverse = tp_traverse::<T>();
|
||||
}
|
||||
|
||||
pub fn set_clear<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
self.tp_clear = tp_clear::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/// Object visitor for GC.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PyVisit<'p> {
|
||||
visit: ffi::visitproc,
|
||||
arg: *mut c_void,
|
||||
/// VisitProc contains a Python instance to ensure that
|
||||
/// 1) it is cannot be moved out of the traverse() call
|
||||
/// 2) it cannot be sent to other threads
|
||||
_py: Python<'p>,
|
||||
}
|
||||
|
||||
impl<'p> PyVisit<'p> {
|
||||
/// Visit `obj`.
|
||||
pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
|
||||
where
|
||||
T: AsPyPointer,
|
||||
{
|
||||
let r = unsafe { (self.visit)(obj.as_ptr(), self.arg) };
|
||||
if r == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PyTraverseError(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tp_traverse<T>() -> Option<ffi::traverseproc>
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn tp_traverse<T>(
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
visit: ffi::visitproc,
|
||||
arg: *mut c_void,
|
||||
|
@ -105,23 +54,52 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
Some(tp_traverse::<T>)
|
||||
}
|
||||
TypedSlot(ffi::Py_tp_traverse, wrap::<Self>)
|
||||
}
|
||||
|
||||
fn tp_clear<T>() -> Option<ffi::inquiry>
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn tp_clear<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
fn get_clear() -> TypedSlot<ffi::inquiry>
|
||||
where
|
||||
Self: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
let slf = pool.python().from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
slf.borrow_mut().__clear__();
|
||||
0
|
||||
}
|
||||
Some(tp_clear::<T>)
|
||||
|
||||
TypedSlot(ffi::Py_tp_clear, wrap::<Self>)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyGCSlots for T where T: PyGCProtocol<'p> {}
|
||||
|
||||
/// Object visitor for GC.
|
||||
#[derive(Clone)]
|
||||
pub struct PyVisit<'p> {
|
||||
visit: ffi::visitproc,
|
||||
arg: *mut c_void,
|
||||
/// VisitProc contains a Python instance to ensure that
|
||||
/// 1) it is cannot be moved out of the traverse() call
|
||||
/// 2) it cannot be sent to other threads
|
||||
_py: Python<'p>,
|
||||
}
|
||||
|
||||
impl<'p> PyVisit<'p> {
|
||||
/// Visit `obj`.
|
||||
pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
|
||||
where
|
||||
T: AsPyPointer,
|
||||
{
|
||||
let r = unsafe { (self.visit)(obj.as_ptr(), self.arg) };
|
||||
if r == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PyTraverseError(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
//! Python Iterator Interface.
|
||||
//! Trait and support implementation for implementing iterators
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::derive_utils::TryFromPyCell;
|
||||
use crate::err::PyResult;
|
||||
|
@ -71,31 +72,30 @@ pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyIterNextOutput>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyIterMethods {
|
||||
pub tp_iter: Option<ffi::getiterfunc>,
|
||||
pub tp_iternext: Option<ffi::iternextfunc>,
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
pub trait PyIterSlots {
|
||||
fn get_iter() -> TypedSlot<ffi::getiterfunc>
|
||||
where
|
||||
Self: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_iter,
|
||||
py_unarys_func!(PyIterIterProtocol, Self::__iter__),
|
||||
)
|
||||
}
|
||||
fn get_iternext() -> TypedSlot<ffi::iternextfunc>
|
||||
where
|
||||
Self: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_tp_iternext,
|
||||
py_unarys_func!(PyIterNextProtocol, Self::__next__),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl PyIterMethods {
|
||||
pub(crate) fn update_typeobj(&self, type_object: &mut ffi::PyTypeObject) {
|
||||
type_object.tp_iter = self.tp_iter;
|
||||
type_object.tp_iternext = self.tp_iternext;
|
||||
}
|
||||
pub fn set_iter<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterIterProtocol<'p>,
|
||||
{
|
||||
self.tp_iter = py_unarys_func!(PyIterIterProtocol, T::__iter__);
|
||||
}
|
||||
pub fn set_iternext<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PyIterNextProtocol<'p>,
|
||||
{
|
||||
self.tp_iternext = py_unarys_func!(PyIterNextProtocol, T::__next__);
|
||||
}
|
||||
}
|
||||
impl<'p, T> PyIterSlots for T where T: PyIterProtocol<'p> {}
|
||||
|
||||
/// Output of `__next__` which can either `yield` the next value in the iteration, or
|
||||
/// `return` a value to raise `StopIteration` in Python.
|
||||
|
|
|
@ -11,7 +11,7 @@ macro_rules! py_unary_func {
|
|||
$call!(slf, $f).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
// Use call_ref! by default
|
||||
($trait:ident, $class:ident :: $f:ident, $ret_type:ty) => {
|
||||
|
@ -34,10 +34,10 @@ macro_rules! py_unarys_func {
|
|||
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
$class::$f(borrow).convert(py)
|
||||
T::$f(borrow).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ macro_rules! py_binary_func {
|
|||
$call!(slf, $f, arg).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
($trait:ident, $class:ident :: $f:ident, $return:ty) => {
|
||||
py_binary_func!($trait, $class::$f, $return, call_ref)
|
||||
|
@ -82,10 +82,10 @@ macro_rules! py_binary_num_func {
|
|||
$crate::callback_body!(py, {
|
||||
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
|
||||
let rhs = extract_or_return_not_implemented!(py, rhs);
|
||||
$class::$f(lhs.extract()?, rhs).convert(py)
|
||||
T::$f(lhs.extract()?, rhs).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -102,10 +102,10 @@ macro_rules! py_binary_reversed_num_func {
|
|||
// Swap lhs <-> rhs
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(py, rhs);
|
||||
let arg = extract_or_return_not_implemented!(py, lhs);
|
||||
$class::$f(&*slf.try_borrow()?, arg).convert(py)
|
||||
T::$f(&*slf.try_borrow()?, arg).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -123,17 +123,17 @@ macro_rules! py_binary_fallback_num_func {
|
|||
let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs);
|
||||
// First, try the left hand method (e.g., __add__)
|
||||
match (lhs.extract(), rhs.extract()) {
|
||||
(Ok(l), Ok(r)) => $class::$lop(l, r).convert(py),
|
||||
(Ok(l), Ok(r)) => T::$lop(l, r).convert(py),
|
||||
_ => {
|
||||
// Next, try the right hand method (e.g., __radd__)
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(rhs);
|
||||
let arg = extract_or_return_not_implemented!(lhs);
|
||||
$class::$rop(&*slf.try_borrow()?, arg).convert(py)
|
||||
T::$rop(&*slf.try_borrow()?, arg).convert(py)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ macro_rules! py_binary_self_func {
|
|||
Ok::<_, $crate::err::PyErr>(slf)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ macro_rules! py_ssizearg_func {
|
|||
$call!(slf, $f; arg.into()).convert(py)
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -203,11 +203,11 @@ macro_rules! py_ternarys_func {
|
|||
.from_borrowed_ptr::<$crate::types::PyAny>(arg2)
|
||||
.extract()?;
|
||||
|
||||
$class::$f(slf, arg1, arg2).convert(py)
|
||||
T::$f(slf, arg1, arg2).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
Some(wrap::<T>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
($trait:ident, $class:ident :: $f:ident) => {
|
||||
py_ternarys_func!($trait, $class::$f, *mut $crate::ffi::PyObject);
|
||||
|
@ -215,8 +215,8 @@ macro_rules! py_ternarys_func {
|
|||
}
|
||||
|
||||
macro_rules! py_func_set {
|
||||
($trait_name:ident, $generic:ident, $fn_set:ident) => {{
|
||||
unsafe extern "C" fn wrap<$generic>(
|
||||
($trait_name:ident, $class:ident :: $fn_set:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
|
@ -225,12 +225,12 @@ macro_rules! py_func_set {
|
|||
T: for<'p> $trait_name<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
Err($crate::exceptions::PyNotImplementedError::new_err(format!(
|
||||
"Subscript deletion not supported by {:?}",
|
||||
stringify!($generic)
|
||||
stringify!($class)
|
||||
)))
|
||||
} else {
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
|
@ -240,23 +240,23 @@ macro_rules! py_func_set {
|
|||
})
|
||||
}
|
||||
|
||||
Some(wrap::<$generic>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! py_func_del {
|
||||
($trait_name:ident, $generic:ident, $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<U>(
|
||||
($trait_name:ident, $class:ident :: $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
) -> libc::c_int
|
||||
where
|
||||
U: for<'p> $trait_name<'p>,
|
||||
T: for<'p> $trait_name<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
if value.is_null() {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let name = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(name)
|
||||
.extract()?;
|
||||
|
@ -269,13 +269,13 @@ macro_rules! py_func_del {
|
|||
})
|
||||
}
|
||||
|
||||
Some(wrap::<$generic>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! py_func_set_del {
|
||||
($trait1:ident, $trait2:ident, $generic:ident, $fn_set:ident, $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<$generic>(
|
||||
($trait1:ident, $trait2:ident, $class:ident, $fn_set:ident, $fn_del:ident) => {{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
|
@ -284,7 +284,7 @@ macro_rules! py_func_set_del {
|
|||
T: for<'p> $trait1<'p> + for<'p> $trait2<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
|
||||
if value.is_null() {
|
||||
|
@ -295,7 +295,7 @@ macro_rules! py_func_set_del {
|
|||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<$generic>)
|
||||
wrap::<$class>
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//! Python Mapping Interface
|
||||
//! Trait and support implementation for implementing mapping support
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{exceptions, ffi, FromPyObject, PyClass, PyObject};
|
||||
|
||||
|
@ -72,42 +73,64 @@ pub trait PyMappingReversedProtocol<'p>: PyMappingProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl ffi::PyMappingMethods {
|
||||
pub fn set_length<T>(&mut self)
|
||||
pub trait PyMappingSlots {
|
||||
fn get_len() -> TypedSlot<ffi::lenfunc>
|
||||
where
|
||||
T: for<'p> PyMappingLenProtocol<'p>,
|
||||
Self: for<'p> PyMappingLenProtocol<'p>,
|
||||
{
|
||||
self.mp_length = py_len_func!(PyMappingLenProtocol, T::__len__);
|
||||
TypedSlot(
|
||||
ffi::Py_mp_length,
|
||||
py_len_func!(PyMappingLenProtocol, Self::__len__),
|
||||
)
|
||||
}
|
||||
pub fn set_getitem<T>(&mut self)
|
||||
|
||||
fn get_getitem() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyMappingGetItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingGetItemProtocol<'p>,
|
||||
{
|
||||
self.mp_subscript = py_binary_func!(PyMappingGetItemProtocol, T::__getitem__);
|
||||
TypedSlot(
|
||||
ffi::Py_mp_subscript,
|
||||
py_binary_func!(PyMappingGetItemProtocol, Self::__getitem__),
|
||||
)
|
||||
}
|
||||
pub fn set_setitem<T>(&mut self)
|
||||
|
||||
fn get_setitem() -> TypedSlot<ffi::objobjargproc>
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingSetItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_set!(PyMappingSetItemProtocol, T, __setitem__);
|
||||
TypedSlot(
|
||||
ffi::Py_mp_ass_subscript,
|
||||
py_func_set!(PyMappingSetItemProtocol, Self::__setitem__),
|
||||
)
|
||||
}
|
||||
pub fn set_delitem<T>(&mut self)
|
||||
|
||||
fn get_delitem() -> TypedSlot<ffi::objobjargproc>
|
||||
where
|
||||
T: for<'p> PyMappingDelItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_del!(PyMappingDelItemProtocol, T, __delitem__);
|
||||
TypedSlot(
|
||||
ffi::Py_mp_ass_subscript,
|
||||
py_func_del!(PyMappingDelItemProtocol, Self::__delitem__),
|
||||
)
|
||||
}
|
||||
pub fn set_setdelitem<T>(&mut self)
|
||||
|
||||
fn get_setdelitem() -> TypedSlot<ffi::objobjargproc>
|
||||
where
|
||||
T: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
Self: for<'p> PyMappingSetItemProtocol<'p> + for<'p> PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
self.mp_ass_subscript = py_func_set_del!(
|
||||
TypedSlot(
|
||||
ffi::Py_mp_ass_subscript,
|
||||
py_func_set_del!(
|
||||
PyMappingSetItemProtocol,
|
||||
PyMappingDelItemProtocol,
|
||||
T,
|
||||
Self,
|
||||
__setitem__,
|
||||
__delitem__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyMappingSlots for T where T: PyMappingProtocol<'p> {}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
//! Python Number Interface
|
||||
//! Trait and support implementation for implementing number protocol
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::err::PyErr;
|
||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
||||
|
@ -579,116 +579,164 @@ pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl ffi::PyNumberMethods {
|
||||
pub(crate) fn from_nb_bool(nb_bool: ffi::inquiry) -> *mut Self {
|
||||
let mut nm = ffi::PyNumberMethods_INIT;
|
||||
nm.nb_bool = Some(nb_bool);
|
||||
Box::into_raw(Box::new(nm))
|
||||
}
|
||||
pub fn set_add_radd<T>(&mut self)
|
||||
pub trait PyNumberSlots {
|
||||
fn get_add_radd() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>,
|
||||
Self: for<'p> PyNumberAddProtocol<'p> + for<'p> PyNumberRAddProtocol<'p>,
|
||||
{
|
||||
self.nb_add = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_add,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberAddProtocol::__add__,
|
||||
PyNumberRAddProtocol::__radd__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_add<T>(&mut self)
|
||||
|
||||
fn get_add() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberAddProtocol<'p>,
|
||||
Self: for<'p> PyNumberAddProtocol<'p>,
|
||||
{
|
||||
self.nb_add = py_binary_num_func!(PyNumberAddProtocol, T::__add__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_add,
|
||||
py_binary_num_func!(PyNumberAddProtocol, Self::__add__),
|
||||
)
|
||||
}
|
||||
pub fn set_radd<T>(&mut self)
|
||||
|
||||
fn get_radd() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRAddProtocol<'p>,
|
||||
Self: for<'p> PyNumberRAddProtocol<'p>,
|
||||
{
|
||||
self.nb_add = py_binary_reversed_num_func!(PyNumberRAddProtocol, T::__radd__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_add,
|
||||
py_binary_reversed_num_func!(PyNumberRAddProtocol, Self::__radd__),
|
||||
)
|
||||
}
|
||||
pub fn set_sub_rsub<T>(&mut self)
|
||||
|
||||
fn get_sub_rsub() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberSubProtocol<'p> + for<'p> PyNumberRSubProtocol<'p>,
|
||||
Self: for<'p> PyNumberSubProtocol<'p> + for<'p> PyNumberRSubProtocol<'p>,
|
||||
{
|
||||
self.nb_subtract = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_subtract,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberSubProtocol::__sub__,
|
||||
PyNumberRSubProtocol::__rsub__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_sub<T>(&mut self)
|
||||
|
||||
fn get_sub() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberSubProtocol<'p>,
|
||||
Self: for<'p> PyNumberSubProtocol<'p>,
|
||||
{
|
||||
self.nb_subtract = py_binary_num_func!(PyNumberSubProtocol, T::__sub__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_subtract,
|
||||
py_binary_num_func!(PyNumberSubProtocol, Self::__sub__),
|
||||
)
|
||||
}
|
||||
pub fn set_rsub<T>(&mut self)
|
||||
|
||||
fn get_rsub() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRSubProtocol<'p>,
|
||||
Self: for<'p> PyNumberRSubProtocol<'p>,
|
||||
{
|
||||
self.nb_subtract = py_binary_reversed_num_func!(PyNumberRSubProtocol, T::__rsub__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_subtract,
|
||||
py_binary_reversed_num_func!(PyNumberRSubProtocol, Self::__rsub__),
|
||||
)
|
||||
}
|
||||
pub fn set_mul_rmul<T>(&mut self)
|
||||
|
||||
fn get_mul_rmul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberMulProtocol<'p> + for<'p> PyNumberRMulProtocol<'p>,
|
||||
Self: for<'p> PyNumberMulProtocol<'p> + for<'p> PyNumberRMulProtocol<'p>,
|
||||
{
|
||||
self.nb_multiply = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_multiply,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberMulProtocol::__mul__,
|
||||
PyNumberRMulProtocol::__rmul__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_mul<T>(&mut self)
|
||||
|
||||
fn get_mul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberMulProtocol<'p>,
|
||||
Self: for<'p> PyNumberMulProtocol<'p>,
|
||||
{
|
||||
self.nb_multiply = py_binary_num_func!(PyNumberMulProtocol, T::__mul__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_multiply,
|
||||
py_binary_num_func!(PyNumberMulProtocol, Self::__mul__),
|
||||
)
|
||||
}
|
||||
pub fn set_rmul<T>(&mut self)
|
||||
|
||||
fn get_rmul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRMulProtocol<'p>,
|
||||
Self: for<'p> PyNumberRMulProtocol<'p>,
|
||||
{
|
||||
self.nb_multiply = py_binary_reversed_num_func!(PyNumberRMulProtocol, T::__rmul__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_multiply,
|
||||
py_binary_reversed_num_func!(PyNumberRMulProtocol, Self::__rmul__),
|
||||
)
|
||||
}
|
||||
pub fn set_mod<T>(&mut self)
|
||||
|
||||
fn get_mod() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberModProtocol<'p>,
|
||||
Self: for<'p> PyNumberModProtocol<'p>,
|
||||
{
|
||||
self.nb_remainder = py_binary_num_func!(PyNumberModProtocol, T::__mod__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_remainder,
|
||||
py_binary_num_func!(PyNumberModProtocol, Self::__mod__),
|
||||
)
|
||||
}
|
||||
pub fn set_divmod_rdivmod<T>(&mut self)
|
||||
|
||||
fn get_divmod_rdivmod() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberDivmodProtocol<'p> + for<'p> PyNumberRDivmodProtocol<'p>,
|
||||
Self: for<'p> PyNumberDivmodProtocol<'p> + for<'p> PyNumberRDivmodProtocol<'p>,
|
||||
{
|
||||
self.nb_divmod = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_divmod,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberDivmodProtocol::__divmod__,
|
||||
PyNumberRDivmodProtocol::__rdivmod__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_divmod<T>(&mut self)
|
||||
|
||||
fn get_divmod() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberDivmodProtocol<'p>,
|
||||
Self: for<'p> PyNumberDivmodProtocol<'p>,
|
||||
{
|
||||
self.nb_divmod = py_binary_num_func!(PyNumberDivmodProtocol, T::__divmod__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_divmod,
|
||||
py_binary_num_func!(PyNumberDivmodProtocol, Self::__divmod__),
|
||||
)
|
||||
}
|
||||
pub fn set_rdivmod<T>(&mut self)
|
||||
|
||||
fn get_rdivmod() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRDivmodProtocol<'p>,
|
||||
Self: for<'p> PyNumberRDivmodProtocol<'p>,
|
||||
{
|
||||
self.nb_divmod = py_binary_reversed_num_func!(PyNumberRDivmodProtocol, T::__rdivmod__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_divmod,
|
||||
py_binary_reversed_num_func!(PyNumberRDivmodProtocol, Self::__rdivmod__),
|
||||
)
|
||||
}
|
||||
pub fn set_pow_rpow<T>(&mut self)
|
||||
|
||||
fn get_pow_rpow() -> TypedSlot<ffi::ternaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>,
|
||||
Self: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap_pow_and_rpow<T>(
|
||||
lhs: *mut crate::ffi::PyObject,
|
||||
rhs: *mut crate::ffi::PyObject,
|
||||
modulo: *mut crate::ffi::PyObject,
|
||||
) -> *mut crate::ffi::PyObject
|
||||
lhs: *mut ffi::PyObject,
|
||||
rhs: *mut ffi::PyObject,
|
||||
modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
|
@ -709,17 +757,19 @@ impl ffi::PyNumberMethods {
|
|||
}
|
||||
})
|
||||
}
|
||||
self.nb_power = Some(wrap_pow_and_rpow::<T>);
|
||||
|
||||
TypedSlot(ffi::Py_nb_power, wrap_pow_and_rpow::<Self>)
|
||||
}
|
||||
pub fn set_pow<T>(&mut self)
|
||||
|
||||
fn get_pow() -> TypedSlot<ffi::ternaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberPowProtocol<'p>,
|
||||
Self: for<'p> PyNumberPowProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap_pow<T>(
|
||||
lhs: *mut crate::ffi::PyObject,
|
||||
rhs: *mut crate::ffi::PyObject,
|
||||
modulo: *mut crate::ffi::PyObject,
|
||||
) -> *mut crate::ffi::PyObject
|
||||
lhs: *mut ffi::PyObject,
|
||||
rhs: *mut ffi::PyObject,
|
||||
modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberPowProtocol<'p>,
|
||||
{
|
||||
|
@ -730,17 +780,19 @@ impl ffi::PyNumberMethods {
|
|||
T::__pow__(lhs, rhs, modulo).convert(py)
|
||||
})
|
||||
}
|
||||
self.nb_power = Some(wrap_pow::<T>);
|
||||
|
||||
TypedSlot(ffi::Py_nb_power, wrap_pow::<Self>)
|
||||
}
|
||||
pub fn set_rpow<T>(&mut self)
|
||||
|
||||
fn get_rpow() -> TypedSlot<ffi::ternaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRPowProtocol<'p>,
|
||||
Self: for<'p> PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap_rpow<T>(
|
||||
arg: *mut crate::ffi::PyObject,
|
||||
slf: *mut crate::ffi::PyObject,
|
||||
modulo: *mut crate::ffi::PyObject,
|
||||
) -> *mut crate::ffi::PyObject
|
||||
arg: *mut ffi::PyObject,
|
||||
slf: *mut ffi::PyObject,
|
||||
modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
|
@ -751,189 +803,291 @@ impl ffi::PyNumberMethods {
|
|||
slf.try_borrow()?.__rpow__(arg, modulo).convert(py)
|
||||
})
|
||||
}
|
||||
self.nb_power = Some(wrap_rpow::<T>);
|
||||
|
||||
TypedSlot(ffi::Py_nb_power, wrap_rpow::<Self>)
|
||||
}
|
||||
pub fn set_neg<T>(&mut self)
|
||||
|
||||
fn get_neg() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberNegProtocol<'p>,
|
||||
Self: for<'p> PyNumberNegProtocol<'p>,
|
||||
{
|
||||
self.nb_negative = py_unary_func!(PyNumberNegProtocol, T::__neg__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_negative,
|
||||
py_unary_func!(PyNumberNegProtocol, Self::__neg__),
|
||||
)
|
||||
}
|
||||
pub fn set_pos<T>(&mut self)
|
||||
|
||||
fn get_pos() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberPosProtocol<'p>,
|
||||
Self: for<'p> PyNumberPosProtocol<'p>,
|
||||
{
|
||||
self.nb_positive = py_unary_func!(PyNumberPosProtocol, T::__pos__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_positive,
|
||||
py_unary_func!(PyNumberPosProtocol, Self::__pos__),
|
||||
)
|
||||
}
|
||||
pub fn set_abs<T>(&mut self)
|
||||
|
||||
fn get_abs() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberAbsProtocol<'p>,
|
||||
Self: for<'p> PyNumberAbsProtocol<'p>,
|
||||
{
|
||||
self.nb_absolute = py_unary_func!(PyNumberAbsProtocol, T::__abs__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_absolute,
|
||||
py_unary_func!(PyNumberAbsProtocol, Self::__abs__),
|
||||
)
|
||||
}
|
||||
pub fn set_invert<T>(&mut self)
|
||||
|
||||
fn get_invert() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberInvertProtocol<'p>,
|
||||
Self: for<'p> PyNumberInvertProtocol<'p>,
|
||||
{
|
||||
self.nb_invert = py_unary_func!(PyNumberInvertProtocol, T::__invert__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_invert,
|
||||
py_unary_func!(PyNumberInvertProtocol, Self::__invert__),
|
||||
)
|
||||
}
|
||||
pub fn set_lshift_rlshift<T>(&mut self)
|
||||
|
||||
fn get_lshift_rlshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberLShiftProtocol<'p> + for<'p> PyNumberRLShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberLShiftProtocol<'p> + for<'p> PyNumberRLShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_lshift = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_lshift,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberLShiftProtocol::__lshift__,
|
||||
PyNumberRLShiftProtocol::__rlshift__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_lshift<T>(&mut self)
|
||||
|
||||
fn get_lshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberLShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberLShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_lshift = py_binary_num_func!(PyNumberLShiftProtocol, T::__lshift__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_lshift,
|
||||
py_binary_num_func!(PyNumberLShiftProtocol, Self::__lshift__),
|
||||
)
|
||||
}
|
||||
pub fn set_rlshift<T>(&mut self)
|
||||
|
||||
fn get_rlshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRLShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberRLShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_lshift = py_binary_reversed_num_func!(PyNumberRLShiftProtocol, T::__rlshift__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_lshift,
|
||||
py_binary_reversed_num_func!(PyNumberRLShiftProtocol, Self::__rlshift__),
|
||||
)
|
||||
}
|
||||
pub fn set_rshift_rrshift<T>(&mut self)
|
||||
|
||||
fn get_rshift_rrshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRShiftProtocol<'p> + for<'p> PyNumberRRShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberRShiftProtocol<'p> + for<'p> PyNumberRRShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_rshift = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_rshift,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberRShiftProtocol::__rshift__,
|
||||
PyNumberRRShiftProtocol::__rrshift__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_rshift<T>(&mut self)
|
||||
|
||||
fn get_rshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberRShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_rshift = py_binary_num_func!(PyNumberRShiftProtocol, T::__rshift__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_rshift,
|
||||
py_binary_num_func!(PyNumberRShiftProtocol, Self::__rshift__),
|
||||
)
|
||||
}
|
||||
pub fn set_rrshift<T>(&mut self)
|
||||
|
||||
fn get_rrshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRRShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberRRShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_rshift = py_binary_reversed_num_func!(PyNumberRRShiftProtocol, T::__rrshift__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_rshift,
|
||||
py_binary_reversed_num_func!(PyNumberRRShiftProtocol, Self::__rrshift__),
|
||||
)
|
||||
}
|
||||
pub fn set_and_rand<T>(&mut self)
|
||||
|
||||
fn get_and_rand() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberAndProtocol<'p> + for<'p> PyNumberRAndProtocol<'p>,
|
||||
Self: for<'p> PyNumberAndProtocol<'p> + for<'p> PyNumberRAndProtocol<'p>,
|
||||
{
|
||||
self.nb_and = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_and,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberAndProtocol::__and__,
|
||||
PyNumberRAndProtocol::__rand__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_and<T>(&mut self)
|
||||
|
||||
fn get_and() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberAndProtocol<'p>,
|
||||
Self: for<'p> PyNumberAndProtocol<'p>,
|
||||
{
|
||||
self.nb_and = py_binary_num_func!(PyNumberAndProtocol, T::__and__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_and,
|
||||
py_binary_num_func!(PyNumberAndProtocol, Self::__and__),
|
||||
)
|
||||
}
|
||||
pub fn set_rand<T>(&mut self)
|
||||
|
||||
fn get_rand() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRAndProtocol<'p>,
|
||||
Self: for<'p> PyNumberRAndProtocol<'p>,
|
||||
{
|
||||
self.nb_and = py_binary_reversed_num_func!(PyNumberRAndProtocol, T::__rand__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_and,
|
||||
py_binary_reversed_num_func!(PyNumberRAndProtocol, Self::__rand__),
|
||||
)
|
||||
}
|
||||
pub fn set_xor_rxor<T>(&mut self)
|
||||
|
||||
fn get_xor_rxor() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberXorProtocol<'p> + for<'p> PyNumberRXorProtocol<'p>,
|
||||
Self: for<'p> PyNumberXorProtocol<'p> + for<'p> PyNumberRXorProtocol<'p>,
|
||||
{
|
||||
self.nb_xor = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_xor,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberXorProtocol::__xor__,
|
||||
PyNumberRXorProtocol::__rxor__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_xor<T>(&mut self)
|
||||
|
||||
fn get_xor() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberXorProtocol<'p>,
|
||||
Self: for<'p> PyNumberXorProtocol<'p>,
|
||||
{
|
||||
self.nb_xor = py_binary_num_func!(PyNumberXorProtocol, T::__xor__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_xor,
|
||||
py_binary_num_func!(PyNumberXorProtocol, Self::__xor__),
|
||||
)
|
||||
}
|
||||
pub fn set_rxor<T>(&mut self)
|
||||
|
||||
fn get_rxor() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRXorProtocol<'p>,
|
||||
Self: for<'p> PyNumberRXorProtocol<'p>,
|
||||
{
|
||||
self.nb_xor = py_binary_reversed_num_func!(PyNumberRXorProtocol, T::__rxor__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_xor,
|
||||
py_binary_reversed_num_func!(PyNumberRXorProtocol, Self::__rxor__),
|
||||
)
|
||||
}
|
||||
pub fn set_or_ror<T>(&mut self)
|
||||
|
||||
fn get_or_ror() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberOrProtocol<'p> + for<'p> PyNumberROrProtocol<'p>,
|
||||
Self: for<'p> PyNumberOrProtocol<'p> + for<'p> PyNumberROrProtocol<'p>,
|
||||
{
|
||||
self.nb_or = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_or,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberOrProtocol::__or__,
|
||||
PyNumberROrProtocol::__ror__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_or<T>(&mut self)
|
||||
|
||||
fn get_or() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberOrProtocol<'p>,
|
||||
Self: for<'p> PyNumberOrProtocol<'p>,
|
||||
{
|
||||
self.nb_or = py_binary_num_func!(PyNumberOrProtocol, T::__or__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_or,
|
||||
py_binary_num_func!(PyNumberOrProtocol, Self::__or__),
|
||||
)
|
||||
}
|
||||
pub fn set_ror<T>(&mut self)
|
||||
|
||||
fn get_ror() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberROrProtocol<'p>,
|
||||
Self: for<'p> PyNumberROrProtocol<'p>,
|
||||
{
|
||||
self.nb_or = py_binary_reversed_num_func!(PyNumberROrProtocol, T::__ror__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_or,
|
||||
py_binary_reversed_num_func!(PyNumberROrProtocol, Self::__ror__),
|
||||
)
|
||||
}
|
||||
pub fn set_int<T>(&mut self)
|
||||
|
||||
fn get_int() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIntProtocol<'p>,
|
||||
Self: for<'p> PyNumberIntProtocol<'p>,
|
||||
{
|
||||
self.nb_int = py_unary_func!(PyNumberIntProtocol, T::__int__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_int,
|
||||
py_unary_func!(PyNumberIntProtocol, Self::__int__),
|
||||
)
|
||||
}
|
||||
pub fn set_float<T>(&mut self)
|
||||
|
||||
fn get_float() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberFloatProtocol<'p>,
|
||||
Self: for<'p> PyNumberFloatProtocol<'p>,
|
||||
{
|
||||
self.nb_float = py_unary_func!(PyNumberFloatProtocol, T::__float__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_float,
|
||||
py_unary_func!(PyNumberFloatProtocol, Self::__float__),
|
||||
)
|
||||
}
|
||||
pub fn set_iadd<T>(&mut self)
|
||||
|
||||
fn get_iadd() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIAddProtocol<'p>,
|
||||
Self: for<'p> PyNumberIAddProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_add = py_binary_self_func!(PyNumberIAddProtocol, T::__iadd__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_add,
|
||||
py_binary_self_func!(PyNumberIAddProtocol, Self::__iadd__),
|
||||
)
|
||||
}
|
||||
pub fn set_isub<T>(&mut self)
|
||||
|
||||
fn get_isub() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberISubProtocol<'p>,
|
||||
Self: for<'p> PyNumberISubProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_subtract = py_binary_self_func!(PyNumberISubProtocol, T::__isub__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_subtract,
|
||||
py_binary_self_func!(PyNumberISubProtocol, Self::__isub__),
|
||||
)
|
||||
}
|
||||
pub fn set_imul<T>(&mut self)
|
||||
|
||||
fn get_imul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIMulProtocol<'p>,
|
||||
Self: for<'p> PyNumberIMulProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_multiply = py_binary_self_func!(PyNumberIMulProtocol, T::__imul__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_multiply,
|
||||
py_binary_self_func!(PyNumberIMulProtocol, Self::__imul__),
|
||||
)
|
||||
}
|
||||
pub fn set_imod<T>(&mut self)
|
||||
|
||||
fn get_imod() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIModProtocol<'p>,
|
||||
Self: for<'p> PyNumberIModProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_remainder = py_binary_self_func!(PyNumberIModProtocol, T::__imod__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_remainder,
|
||||
py_binary_self_func!(PyNumberIModProtocol, Self::__imod__),
|
||||
)
|
||||
}
|
||||
pub fn set_ipow<T>(&mut self)
|
||||
|
||||
fn get_ipow() -> TypedSlot<ffi::ternaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIPowProtocol<'p>,
|
||||
Self: for<'p> PyNumberIPowProtocol<'p>,
|
||||
{
|
||||
// NOTE: Somehow __ipow__ causes SIGSEGV in Python < 3.8 when we extract,
|
||||
// so we ignore it. It's the same as what CPython does.
|
||||
unsafe extern "C" fn wrap_ipow<T>(
|
||||
slf: *mut crate::ffi::PyObject,
|
||||
other: *mut crate::ffi::PyObject,
|
||||
_modulo: *mut crate::ffi::PyObject,
|
||||
) -> *mut crate::ffi::PyObject
|
||||
slf: *mut ffi::PyObject,
|
||||
other: *mut ffi::PyObject,
|
||||
_modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberIPowProtocol<'p>,
|
||||
{
|
||||
|
@ -945,132 +1099,201 @@ impl ffi::PyNumberMethods {
|
|||
Ok::<_, PyErr>(slf)
|
||||
})
|
||||
}
|
||||
self.nb_inplace_power = Some(wrap_ipow::<T>);
|
||||
|
||||
TypedSlot(ffi::Py_nb_inplace_power, wrap_ipow::<Self>)
|
||||
}
|
||||
pub fn set_ilshift<T>(&mut self)
|
||||
|
||||
fn get_ilshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberILShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberILShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_lshift = py_binary_self_func!(PyNumberILShiftProtocol, T::__ilshift__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_lshift,
|
||||
py_binary_self_func!(PyNumberILShiftProtocol, Self::__ilshift__),
|
||||
)
|
||||
}
|
||||
pub fn set_irshift<T>(&mut self)
|
||||
|
||||
fn get_irshift() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIRShiftProtocol<'p>,
|
||||
Self: for<'p> PyNumberIRShiftProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_rshift = py_binary_self_func!(PyNumberIRShiftProtocol, T::__irshift__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_rshift,
|
||||
py_binary_self_func!(PyNumberIRShiftProtocol, Self::__irshift__),
|
||||
)
|
||||
}
|
||||
pub fn set_iand<T>(&mut self)
|
||||
|
||||
fn get_iand() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIAndProtocol<'p>,
|
||||
Self: for<'p> PyNumberIAndProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_and = py_binary_self_func!(PyNumberIAndProtocol, T::__iand__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_and,
|
||||
py_binary_self_func!(PyNumberIAndProtocol, Self::__iand__),
|
||||
)
|
||||
}
|
||||
pub fn set_ixor<T>(&mut self)
|
||||
|
||||
fn get_ixor() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIXorProtocol<'p>,
|
||||
Self: for<'p> PyNumberIXorProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_xor = py_binary_self_func!(PyNumberIXorProtocol, T::__ixor__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_xor,
|
||||
py_binary_self_func!(PyNumberIXorProtocol, Self::__ixor__),
|
||||
)
|
||||
}
|
||||
pub fn set_ior<T>(&mut self)
|
||||
|
||||
fn get_ior() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIOrProtocol<'p>,
|
||||
Self: for<'p> PyNumberIOrProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_or = py_binary_self_func!(PyNumberIOrProtocol, T::__ior__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_or,
|
||||
py_binary_self_func!(PyNumberIOrProtocol, Self::__ior__),
|
||||
)
|
||||
}
|
||||
pub fn set_floordiv_rfloordiv<T>(&mut self)
|
||||
|
||||
fn get_floordiv_rfloordiv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberFloordivProtocol<'p> + for<'p> PyNumberRFloordivProtocol<'p>,
|
||||
Self: for<'p> PyNumberFloordivProtocol<'p> + for<'p> PyNumberRFloordivProtocol<'p>,
|
||||
{
|
||||
self.nb_floor_divide = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_floor_divide,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberFloordivProtocol::__floordiv__,
|
||||
PyNumberRFloordivProtocol::__rfloordiv__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_floordiv<T>(&mut self)
|
||||
|
||||
fn get_floordiv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberFloordivProtocol<'p>,
|
||||
Self: for<'p> PyNumberFloordivProtocol<'p>,
|
||||
{
|
||||
self.nb_floor_divide = py_binary_num_func!(PyNumberFloordivProtocol, T::__floordiv__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_floor_divide,
|
||||
py_binary_num_func!(PyNumberFloordivProtocol, Self::__floordiv__),
|
||||
)
|
||||
}
|
||||
pub fn set_rfloordiv<T>(&mut self)
|
||||
|
||||
fn get_rfloordiv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRFloordivProtocol<'p>,
|
||||
Self: for<'p> PyNumberRFloordivProtocol<'p>,
|
||||
{
|
||||
self.nb_floor_divide =
|
||||
py_binary_reversed_num_func!(PyNumberRFloordivProtocol, T::__rfloordiv__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_floor_divide,
|
||||
py_binary_reversed_num_func!(PyNumberRFloordivProtocol, Self::__rfloordiv__),
|
||||
)
|
||||
}
|
||||
pub fn set_truediv_rtruediv<T>(&mut self)
|
||||
|
||||
fn get_truediv_rtruediv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberTruedivProtocol<'p> + for<'p> PyNumberRTruedivProtocol<'p>,
|
||||
Self: for<'p> PyNumberTruedivProtocol<'p> + for<'p> PyNumberRTruedivProtocol<'p>,
|
||||
{
|
||||
self.nb_true_divide = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_true_divide,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberTruedivProtocol::__truediv__,
|
||||
PyNumberRTruedivProtocol::__rtruediv__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_truediv<T>(&mut self)
|
||||
|
||||
fn get_truediv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberTruedivProtocol<'p>,
|
||||
Self: for<'p> PyNumberTruedivProtocol<'p>,
|
||||
{
|
||||
self.nb_true_divide = py_binary_num_func!(PyNumberTruedivProtocol, T::__truediv__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_true_divide,
|
||||
py_binary_num_func!(PyNumberTruedivProtocol, Self::__truediv__),
|
||||
)
|
||||
}
|
||||
pub fn set_rtruediv<T>(&mut self)
|
||||
|
||||
fn get_rtruediv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRTruedivProtocol<'p>,
|
||||
Self: for<'p> PyNumberRTruedivProtocol<'p>,
|
||||
{
|
||||
self.nb_true_divide =
|
||||
py_binary_reversed_num_func!(PyNumberRTruedivProtocol, T::__rtruediv__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_true_divide,
|
||||
py_binary_reversed_num_func!(PyNumberRTruedivProtocol, Self::__rtruediv__),
|
||||
)
|
||||
}
|
||||
pub fn set_ifloordiv<T>(&mut self)
|
||||
|
||||
fn get_ifloordiv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIFloordivProtocol<'p>,
|
||||
Self: for<'p> PyNumberIFloordivProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_floor_divide =
|
||||
py_binary_self_func!(PyNumberIFloordivProtocol, T::__ifloordiv__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_floor_divide,
|
||||
py_binary_self_func!(PyNumberIFloordivProtocol, Self::__ifloordiv__),
|
||||
)
|
||||
}
|
||||
pub fn set_itruediv<T>(&mut self)
|
||||
|
||||
fn get_itruediv() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberITruedivProtocol<'p>,
|
||||
Self: for<'p> PyNumberITruedivProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_true_divide =
|
||||
py_binary_self_func!(PyNumberITruedivProtocol, T::__itruediv__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_true_divide,
|
||||
py_binary_self_func!(PyNumberITruedivProtocol, Self::__itruediv__),
|
||||
)
|
||||
}
|
||||
pub fn set_index<T>(&mut self)
|
||||
|
||||
fn get_index() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIndexProtocol<'p>,
|
||||
Self: for<'p> PyNumberIndexProtocol<'p>,
|
||||
{
|
||||
self.nb_index = py_unary_func!(PyNumberIndexProtocol, T::__index__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_index,
|
||||
py_unary_func!(PyNumberIndexProtocol, Self::__index__),
|
||||
)
|
||||
}
|
||||
pub fn set_matmul_rmatmul<T>(&mut self)
|
||||
|
||||
fn get_matmul_rmatmul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberMatmulProtocol<'p> + for<'p> PyNumberRMatmulProtocol<'p>,
|
||||
Self: for<'p> PyNumberMatmulProtocol<'p> + for<'p> PyNumberRMatmulProtocol<'p>,
|
||||
{
|
||||
self.nb_matrix_multiply = py_binary_fallback_num_func!(
|
||||
T,
|
||||
TypedSlot(
|
||||
ffi::Py_nb_matrix_multiply,
|
||||
py_binary_fallback_num_func!(
|
||||
Self,
|
||||
PyNumberMatmulProtocol::__matmul__,
|
||||
PyNumberRMatmulProtocol::__rmatmul__
|
||||
);
|
||||
),
|
||||
)
|
||||
}
|
||||
pub fn set_matmul<T>(&mut self)
|
||||
|
||||
fn get_matmul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberMatmulProtocol<'p>,
|
||||
Self: for<'p> PyNumberMatmulProtocol<'p>,
|
||||
{
|
||||
self.nb_matrix_multiply = py_binary_num_func!(PyNumberMatmulProtocol, T::__matmul__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_matrix_multiply,
|
||||
py_binary_num_func!(PyNumberMatmulProtocol, Self::__matmul__),
|
||||
)
|
||||
}
|
||||
pub fn set_rmatmul<T>(&mut self)
|
||||
|
||||
fn get_rmatmul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberRMatmulProtocol<'p>,
|
||||
Self: for<'p> PyNumberRMatmulProtocol<'p>,
|
||||
{
|
||||
self.nb_matrix_multiply =
|
||||
py_binary_reversed_num_func!(PyNumberRMatmulProtocol, T::__rmatmul__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_matrix_multiply,
|
||||
py_binary_reversed_num_func!(PyNumberRMatmulProtocol, Self::__rmatmul__),
|
||||
)
|
||||
}
|
||||
pub fn set_imatmul<T>(&mut self)
|
||||
|
||||
fn get_imatmul() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PyNumberIMatmulProtocol<'p>,
|
||||
Self: for<'p> PyNumberIMatmulProtocol<'p>,
|
||||
{
|
||||
self.nb_inplace_matrix_multiply =
|
||||
py_binary_self_func!(PyNumberIMatmulProtocol, T::__imatmul__);
|
||||
TypedSlot(
|
||||
ffi::Py_nb_inplace_matrix_multiply,
|
||||
py_binary_self_func!(PyNumberIMatmulProtocol, Self::__imatmul__),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyNumberSlots for T where T: PyNumberProtocol<'p> {}
|
||||
|
|
|
@ -1,154 +1,78 @@
|
|||
use crate::class::{
|
||||
basic::PyObjectMethods, descr::PyDescrMethods, gc::PyGCMethods, iter::PyIterMethods,
|
||||
};
|
||||
use crate::ffi::{
|
||||
PyAsyncMethods, PyBufferProcs, PyMappingMethods, PyNumberMethods, PySequenceMethods,
|
||||
};
|
||||
use std::{
|
||||
ptr::{self, NonNull},
|
||||
sync::atomic::{AtomicPtr, Ordering},
|
||||
};
|
||||
use crate::ffi;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::ffi::PyBufferProcs;
|
||||
|
||||
/// ABI3 doesn't have buffer APIs, so here we define the empty one.
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
#[doc(hidden)]
|
||||
#[derive(Clone)]
|
||||
pub struct PyBufferProcs;
|
||||
|
||||
/// Defines all method tables we need for object protocols.
|
||||
// Note(kngwyu): default implementations are for rust-numpy. Please don't remove them.
|
||||
pub trait PyProtoMethods {
|
||||
fn async_methods() -> Option<NonNull<PyAsyncMethods>> {
|
||||
None
|
||||
fn get_type_slots() -> Vec<ffi::PyType_Slot> {
|
||||
vec![]
|
||||
}
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
None
|
||||
}
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
None
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
None
|
||||
}
|
||||
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
|
||||
None
|
||||
}
|
||||
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
|
||||
None
|
||||
}
|
||||
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
|
||||
None
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
None
|
||||
}
|
||||
fn sequence_methods() -> Option<NonNull<PySequenceMethods>> {
|
||||
fn get_buffer() -> Option<PyBufferProcs> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates that a type has a protocol registry. Implemented by `#[pyclass]`.
|
||||
/// Typed version of `ffi::PyType_Slot`
|
||||
#[doc(hidden)]
|
||||
pub trait HasProtoRegistry: Sized + 'static {
|
||||
fn registry() -> &'static PyProtoRegistry;
|
||||
}
|
||||
pub struct TypedSlot<T: Sized>(pub std::os::raw::c_int, pub T);
|
||||
|
||||
impl<T: HasProtoRegistry> PyProtoMethods for T {
|
||||
fn async_methods() -> Option<NonNull<PyAsyncMethods>> {
|
||||
NonNull::new(Self::registry().async_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn basic_methods() -> Option<NonNull<PyObjectMethods>> {
|
||||
NonNull::new(Self::registry().basic_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn buffer_methods() -> Option<NonNull<PyBufferProcs>> {
|
||||
NonNull::new(Self::registry().buffer_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn descr_methods() -> Option<NonNull<PyDescrMethods>> {
|
||||
NonNull::new(Self::registry().descr_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn gc_methods() -> Option<NonNull<PyGCMethods>> {
|
||||
NonNull::new(Self::registry().gc_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn mapping_methods() -> Option<NonNull<PyMappingMethods>> {
|
||||
NonNull::new(Self::registry().mapping_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn number_methods() -> Option<NonNull<PyNumberMethods>> {
|
||||
NonNull::new(Self::registry().number_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn iter_methods() -> Option<NonNull<PyIterMethods>> {
|
||||
NonNull::new(Self::registry().iter_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
fn sequence_methods() -> Option<NonNull<PySequenceMethods>> {
|
||||
NonNull::new(Self::registry().sequence_methods.load(Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores all method protocols.
|
||||
/// Used in the proc-macro code as a static variable.
|
||||
#[doc(hidden)]
|
||||
pub struct PyProtoRegistry {
|
||||
/// Async protocols.
|
||||
async_methods: AtomicPtr<PyAsyncMethods>,
|
||||
/// Basic protocols.
|
||||
basic_methods: AtomicPtr<PyObjectMethods>,
|
||||
/// Buffer protocols.
|
||||
buffer_methods: AtomicPtr<PyBufferProcs>,
|
||||
/// Descr pProtocols.
|
||||
descr_methods: AtomicPtr<PyDescrMethods>,
|
||||
/// GC protocols.
|
||||
gc_methods: AtomicPtr<PyGCMethods>,
|
||||
/// Mapping protocols.
|
||||
mapping_methods: AtomicPtr<PyMappingMethods>,
|
||||
/// Number protocols.
|
||||
number_methods: AtomicPtr<PyNumberMethods>,
|
||||
/// Iterator protocols.
|
||||
iter_methods: AtomicPtr<PyIterMethods>,
|
||||
/// Sequence protocols.
|
||||
sequence_methods: AtomicPtr<PySequenceMethods>,
|
||||
pub enum PyProtoMethodDef {
|
||||
Slots(Vec<ffi::PyType_Slot>),
|
||||
Buffer(PyBufferProcs),
|
||||
}
|
||||
|
||||
impl PyProtoRegistry {
|
||||
pub const fn new() -> Self {
|
||||
PyProtoRegistry {
|
||||
async_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
basic_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
buffer_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
descr_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
gc_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
mapping_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
number_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
iter_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
sequence_methods: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
pub fn set_async_methods(&self, methods: PyAsyncMethods) {
|
||||
self.async_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_basic_methods(&self, methods: PyObjectMethods) {
|
||||
self.basic_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_buffer_methods(&self, methods: PyBufferProcs) {
|
||||
self.buffer_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_descr_methods(&self, methods: PyDescrMethods) {
|
||||
self.descr_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_gc_methods(&self, methods: PyGCMethods) {
|
||||
self.gc_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_mapping_methods(&self, methods: PyMappingMethods) {
|
||||
self.mapping_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_number_methods(&self, methods: PyNumberMethods) {
|
||||
self.number_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_iter_methods(&self, methods: PyIterMethods) {
|
||||
self.iter_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
}
|
||||
pub fn set_sequence_methods(&self, methods: PySequenceMethods) {
|
||||
self.sequence_methods
|
||||
.store(Box::into_raw(Box::new(methods)), Ordering::Relaxed)
|
||||
impl From<Vec<ffi::PyType_Slot>> for PyProtoMethodDef {
|
||||
fn from(slots: Vec<ffi::PyType_Slot>) -> Self {
|
||||
PyProtoMethodDef::Slots(slots)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PyBufferProcs> for PyProtoMethodDef {
|
||||
fn from(buffer_procs: PyBufferProcs) -> Self {
|
||||
PyProtoMethodDef::Buffer(buffer_procs)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macros")]
|
||||
pub trait PyProtoInventory: inventory::Collect {
|
||||
fn new(methods: PyProtoMethodDef) -> Self;
|
||||
fn get(&'static self) -> &'static PyProtoMethodDef;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "macros")]
|
||||
pub trait HasProtoInventory {
|
||||
type ProtoMethods: PyProtoInventory;
|
||||
}
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
impl<T: HasProtoInventory> PyProtoMethods for T {
|
||||
fn get_type_slots() -> Vec<ffi::PyType_Slot> {
|
||||
inventory::iter::<T::ProtoMethods>
|
||||
.into_iter()
|
||||
.filter_map(|def| match def.get() {
|
||||
PyProtoMethodDef::Slots(slots) => Some(slots),
|
||||
PyProtoMethodDef::Buffer(_) => None,
|
||||
})
|
||||
.flatten()
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_buffer() -> Option<PyBufferProcs> {
|
||||
inventory::iter::<T::ProtoMethods>
|
||||
.into_iter()
|
||||
.find_map(|def| match def.get() {
|
||||
PyProtoMethodDef::Slots(_) => None,
|
||||
PyProtoMethodDef::Buffer(buf) => Some(buf.clone()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
|
||||
//!
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::derive_utils::TryFromPyCell;
|
||||
use crate::err::PyResult;
|
||||
|
@ -85,28 +86,43 @@ pub trait PyAsyncAexitProtocol<'p>: PyAsyncProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl ffi::PyAsyncMethods {
|
||||
pub fn set_await<T>(&mut self)
|
||||
pub trait PyAsyncSlots {
|
||||
fn get_await() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyAsyncAwaitProtocol<'p>,
|
||||
Self: for<'p> PyAsyncAwaitProtocol<'p>,
|
||||
{
|
||||
self.am_await = py_unarys_func!(PyAsyncAwaitProtocol, T::__await__);
|
||||
TypedSlot(
|
||||
ffi::Py_am_await,
|
||||
py_unarys_func!(PyAsyncAwaitProtocol, Self::__await__),
|
||||
)
|
||||
}
|
||||
pub fn set_aiter<T>(&mut self)
|
||||
|
||||
fn get_aiter() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyAsyncAiterProtocol<'p>,
|
||||
Self: for<'p> PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
self.am_aiter = py_unarys_func!(PyAsyncAiterProtocol, T::__aiter__);
|
||||
TypedSlot(
|
||||
ffi::Py_am_aiter,
|
||||
py_unarys_func!(PyAsyncAiterProtocol, Self::__aiter__),
|
||||
)
|
||||
}
|
||||
pub fn set_anext<T>(&mut self)
|
||||
|
||||
fn get_anext() -> TypedSlot<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
Self: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
self.am_anext = am_anext::<T>();
|
||||
TypedSlot(
|
||||
ffi::Py_am_anext,
|
||||
py_unarys_func!(PyAsyncAnextProtocol, Self::__anext__),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PyAsyncSlots for T where T: PyAsyncProtocol<'p> {}
|
||||
|
||||
/// Output of `__anext__`.
|
||||
pub enum IterANextOutput<T, U> {
|
||||
Yield(T),
|
||||
Return(U),
|
||||
|
@ -149,11 +165,3 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn am_anext<T>() -> Option<ffi::unaryfunc>
|
||||
where
|
||||
T: for<'p> PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
py_unarys_func!(PyAsyncAnextProtocol, T::__anext__)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//! Python Sequence Interface
|
||||
//! Trait and support implementation for implementing sequence
|
||||
|
||||
use super::proto_methods::TypedSlot;
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::conversion::{FromPyObject, IntoPy};
|
||||
use crate::err::PyErr;
|
||||
|
@ -128,88 +129,52 @@ pub trait PySequenceInplaceRepeatProtocol<'p>:
|
|||
type Result: IntoPyCallbackOutput<Self>;
|
||||
}
|
||||
|
||||
/// Extension trait for proc-macro backend.
|
||||
#[doc(hidden)]
|
||||
impl ffi::PySequenceMethods {
|
||||
pub fn set_len<T>(&mut self)
|
||||
pub trait PySequenceSlots {
|
||||
fn get_len() -> TypedSlot<ffi::lenfunc>
|
||||
where
|
||||
T: for<'p> PySequenceLenProtocol<'p>,
|
||||
Self: for<'p> PySequenceLenProtocol<'p>,
|
||||
{
|
||||
self.sq_length = py_len_func!(PySequenceLenProtocol, T::__len__);
|
||||
}
|
||||
pub fn set_concat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_concat = py_binary_func!(PySequenceConcatProtocol, T::__concat__);
|
||||
}
|
||||
pub fn set_repeat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceRepeatProtocol<'p>,
|
||||
{
|
||||
self.sq_repeat = py_ssizearg_func!(PySequenceRepeatProtocol, T::__repeat__);
|
||||
}
|
||||
pub fn set_getitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceGetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_item = py_ssizearg_func!(PySequenceGetItemProtocol, T::__getitem__);
|
||||
}
|
||||
pub fn set_setitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::set_item::<T>();
|
||||
}
|
||||
pub fn set_delitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::del_item::<T>();
|
||||
}
|
||||
pub fn set_setdelitem<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
self.sq_ass_item = sq_ass_item_impl::set_del_item::<T>();
|
||||
}
|
||||
pub fn set_contains<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceContainsProtocol<'p>,
|
||||
{
|
||||
self.sq_contains = py_binary_func!(PySequenceContainsProtocol, T::__contains__, c_int);
|
||||
}
|
||||
pub fn set_inplace_concat<T>(&mut self)
|
||||
where
|
||||
T: for<'p> PySequenceInplaceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_inplace_concat = py_binary_func!(
|
||||
PySequenceInplaceConcatProtocol,
|
||||
T::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
TypedSlot(
|
||||
ffi::Py_sq_length,
|
||||
py_len_func!(PySequenceLenProtocol, Self::__len__),
|
||||
)
|
||||
}
|
||||
pub fn set_inplace_repeat<T>(&mut self)
|
||||
|
||||
fn get_concat() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
T: for<'p> PySequenceInplaceRepeatProtocol<'p>,
|
||||
Self: for<'p> PySequenceConcatProtocol<'p>,
|
||||
{
|
||||
self.sq_inplace_repeat = py_ssizearg_func!(
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
T::__inplace_repeat__,
|
||||
call_mut
|
||||
TypedSlot(
|
||||
ffi::Py_sq_concat,
|
||||
py_binary_func!(PySequenceConcatProtocol, Self::__concat__),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// It can be possible to delete and set items (PySequenceSetItemProtocol and
|
||||
/// PySequenceDelItemProtocol implemented), only to delete (PySequenceDelItemProtocol implemented)
|
||||
/// or no deleting or setting is possible
|
||||
mod sq_ass_item_impl {
|
||||
use super::*;
|
||||
|
||||
pub(super) fn set_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
fn get_repeat() -> TypedSlot<ffi::ssizeargfunc>
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceRepeatProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_sq_repeat,
|
||||
py_ssizearg_func!(PySequenceRepeatProtocol, Self::__repeat__),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_getitem() -> TypedSlot<ffi::ssizeargfunc>
|
||||
where
|
||||
Self: for<'p> PySequenceGetItemProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_sq_item,
|
||||
py_ssizearg_func!(PySequenceGetItemProtocol, Self::__getitem__),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_setitem() -> TypedSlot<ffi::ssizeobjargproc>
|
||||
where
|
||||
Self: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
|
@ -235,12 +200,13 @@ mod sq_ass_item_impl {
|
|||
crate::callback::convert(py, slf.__setitem__(key.into(), value))
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
|
||||
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>)
|
||||
}
|
||||
|
||||
pub(super) fn del_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
fn get_delitem() -> TypedSlot<ffi::ssizeobjargproc>
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
|
@ -263,12 +229,13 @@ mod sq_ass_item_impl {
|
|||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
|
||||
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>)
|
||||
}
|
||||
|
||||
pub(super) fn set_del_item<T>() -> Option<ffi::ssizeobjargproc>
|
||||
fn get_setdelitem() -> TypedSlot<ffi::ssizeobjargproc>
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
|
||||
Self: for<'p> PySequenceDelItemProtocol<'p> + for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
unsafe extern "C" fn wrap<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
|
@ -291,6 +258,48 @@ mod sq_ass_item_impl {
|
|||
}
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
|
||||
TypedSlot(ffi::Py_sq_ass_item, wrap::<Self>)
|
||||
}
|
||||
|
||||
fn get_contains() -> TypedSlot<ffi::objobjproc>
|
||||
where
|
||||
Self: for<'p> PySequenceContainsProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_sq_contains,
|
||||
py_binary_func!(PySequenceContainsProtocol, Self::__contains__, c_int),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_inplace_concat() -> TypedSlot<ffi::binaryfunc>
|
||||
where
|
||||
Self: for<'p> PySequenceInplaceConcatProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_sq_inplace_concat,
|
||||
py_binary_func!(
|
||||
PySequenceInplaceConcatProtocol,
|
||||
Self::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_inplace_repeat() -> TypedSlot<ffi::ssizeargfunc>
|
||||
where
|
||||
Self: for<'p> PySequenceInplaceRepeatProtocol<'p>,
|
||||
{
|
||||
TypedSlot(
|
||||
ffi::Py_sq_inplace_repeat,
|
||||
py_ssizearg_func!(
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
Self::__inplace_repeat__,
|
||||
call_mut
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> PySequenceSlots for T where T: PySequenceProtocol<'p> {}
|
||||
|
|
|
@ -491,7 +491,7 @@ impl<'a> std::fmt::Display for PyDowncastError<'a> {
|
|||
write!(
|
||||
f,
|
||||
"'{}' object cannot be converted to '{}'",
|
||||
self.from.get_type().name(),
|
||||
self.from.get_type().name().map_err(|_| std::fmt::Error)?,
|
||||
self.to
|
||||
)
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ macro_rules! impl_exception_boilerplate {
|
|||
|
||||
impl std::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let type_name = self.get_type().name();
|
||||
f.debug_struct(&*type_name)
|
||||
let type_name = self.get_type().name().map_err(|_| std::fmt::Error)?;
|
||||
f.debug_struct(type_name)
|
||||
// TODO: print out actual fields!
|
||||
.finish()
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ macro_rules! impl_exception_boilerplate {
|
|||
|
||||
impl std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let type_name = self.get_type().name();
|
||||
let type_name = self.get_type().name().map_err(|_| std::fmt::Error)?;
|
||||
write!(f, "{}", type_name)?;
|
||||
if let Ok(s) = self.str() {
|
||||
write!(f, ": {}", &s.to_string_lossy())
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::ffi::code::FreeFunc;
|
||||
use crate::ffi::object::PyObject;
|
||||
use crate::ffi::pystate::{PyThreadState, Py_tracefunc};
|
||||
|
@ -61,6 +62,7 @@ extern "C" {
|
|||
arg1: *mut crate::ffi::PyFrameObject,
|
||||
exc: c_int,
|
||||
) -> *mut PyObject;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn _PyEval_RequestCodeExtraIndex(func: FreeFunc) -> c_int;
|
||||
pub fn PyEval_EvalFrameEx(f: *mut crate::ffi::PyFrameObject, exc: c_int) -> *mut PyObject;
|
||||
#[cfg_attr(PyPy, link_name = "PyPyEval_SaveThread")]
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use crate::ffi::methodobject::PyMethodDef;
|
||||
use crate::ffi::object::{PyObject, PyTypeObject};
|
||||
#[cfg(not(PyPy))]
|
||||
#[cfg(all(not(PyPy), not(Py_LIMITED_API)))]
|
||||
use crate::ffi::object::{PyObject_GenericGetDict, PyObject_GenericSetDict};
|
||||
use crate::ffi::structmember::PyMemberDef;
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
use std::ptr;
|
||||
|
||||
pub type getter = unsafe extern "C" fn(slf: *mut PyObject, closure: *mut c_void) -> *mut PyObject;
|
||||
|
||||
pub type setter =
|
||||
unsafe extern "C" fn(slf: *mut PyObject, value: *mut PyObject, closure: *mut c_void) -> c_int;
|
||||
|
||||
|
@ -29,11 +28,12 @@ pub const PyGetSetDef_INIT: PyGetSetDef = PyGetSetDef {
|
|||
closure: ptr::null_mut(),
|
||||
};
|
||||
|
||||
#[cfg(PyPy)]
|
||||
#[cfg(any(PyPy, Py_LIMITED_API))]
|
||||
pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef_INIT;
|
||||
|
||||
// PyPy doesn't export neither PyObject_GenericGetDict/PyObject_GenericSetDict
|
||||
#[cfg(not(PyPy))]
|
||||
// Py_LIMITED_API exposes PyObject_GenericSetDict but not Get.
|
||||
#[cfg(all(not(PyPy), not(Py_LIMITED_API)))]
|
||||
pub const PyGetSetDef_DICT: PyGetSetDef = PyGetSetDef {
|
||||
name: "__dict__\0".as_ptr() as *mut c_char,
|
||||
get: Some(PyObject_GenericGetDict),
|
||||
|
|
|
@ -4,10 +4,12 @@ use crate::ffi::object::{PyObject, PyTypeObject, Py_TYPE};
|
|||
|
||||
#[cfg_attr(windows, link(name = "pythonXY"))]
|
||||
extern "C" {
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[cfg_attr(PyPy, link_name = "PyPyFunction_Type")]
|
||||
pub static mut PyFunction_Type: PyTypeObject;
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[inline]
|
||||
pub unsafe fn PyFunction_Check(op: *mut PyObject) -> c_int {
|
||||
(Py_TYPE(op) == &mut PyFunction_Type) as c_int
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::PyObject;
|
||||
use std::os::raw::{c_char, c_int};
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
extern "C" {
|
||||
#[cfg_attr(PyPy, link_name = "PyPyMarshal_WriteObjectToString")]
|
||||
pub fn PyMarshal_WriteObjectToString(object: *mut PyObject, version: c_int) -> *mut PyObject;
|
||||
|
|
|
@ -314,69 +314,14 @@ mod typeobject {
|
|||
pub nb_inplace_matrix_multiply: Option<object::binaryfunc>,
|
||||
}
|
||||
|
||||
impl Default for PyNumberMethods {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
PyNumberMethods_INIT
|
||||
}
|
||||
}
|
||||
macro_rules! as_expr {
|
||||
($e:expr) => {
|
||||
$e
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_number_methods_init {
|
||||
($($tail:tt)*) => {
|
||||
as_expr! {
|
||||
PyNumberMethods {
|
||||
nb_add: None,
|
||||
nb_subtract: None,
|
||||
nb_multiply: None,
|
||||
nb_remainder: None,
|
||||
nb_divmod: None,
|
||||
nb_power: None,
|
||||
nb_negative: None,
|
||||
nb_positive: None,
|
||||
nb_absolute: None,
|
||||
nb_bool: None,
|
||||
nb_invert: None,
|
||||
nb_lshift: None,
|
||||
nb_rshift: None,
|
||||
nb_and: None,
|
||||
nb_xor: None,
|
||||
nb_or: None,
|
||||
nb_int: None,
|
||||
nb_reserved: ::std::ptr::null_mut(),
|
||||
nb_float: None,
|
||||
nb_inplace_add: None,
|
||||
nb_inplace_subtract: None,
|
||||
nb_inplace_multiply: None,
|
||||
nb_inplace_remainder: None,
|
||||
nb_inplace_power: None,
|
||||
nb_inplace_lshift: None,
|
||||
nb_inplace_rshift: None,
|
||||
nb_inplace_and: None,
|
||||
nb_inplace_xor: None,
|
||||
nb_inplace_or: None,
|
||||
nb_floor_divide: None,
|
||||
nb_true_divide: None,
|
||||
nb_inplace_floor_divide: None,
|
||||
nb_inplace_true_divide: None,
|
||||
nb_index: None,
|
||||
$($tail)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyNumberMethods_INIT: PyNumberMethods = py_number_methods_init! {
|
||||
nb_matrix_multiply: None,
|
||||
nb_inplace_matrix_multiply: None,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct PySequenceMethods {
|
||||
pub sq_length: Option<object::lenfunc>,
|
||||
pub sq_concat: Option<object::binaryfunc>,
|
||||
|
@ -390,83 +335,29 @@ mod typeobject {
|
|||
pub sq_inplace_repeat: Option<object::ssizeargfunc>,
|
||||
}
|
||||
|
||||
impl Default for PySequenceMethods {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
}
|
||||
}
|
||||
pub const PySequenceMethods_INIT: PySequenceMethods = PySequenceMethods {
|
||||
sq_length: None,
|
||||
sq_concat: None,
|
||||
sq_repeat: None,
|
||||
sq_item: None,
|
||||
was_sq_slice: ptr::null_mut(),
|
||||
sq_ass_item: None,
|
||||
was_sq_ass_slice: ptr::null_mut(),
|
||||
sq_contains: None,
|
||||
sq_inplace_concat: None,
|
||||
sq_inplace_repeat: None,
|
||||
};
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PyMappingMethods {
|
||||
pub mp_length: Option<object::lenfunc>,
|
||||
pub mp_subscript: Option<object::binaryfunc>,
|
||||
pub mp_ass_subscript: Option<object::objobjargproc>,
|
||||
}
|
||||
|
||||
impl Default for PyMappingMethods {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
unsafe { mem::zeroed() }
|
||||
}
|
||||
}
|
||||
pub const PyMappingMethods_INIT: PyMappingMethods = PyMappingMethods {
|
||||
mp_length: None,
|
||||
mp_subscript: None,
|
||||
mp_ass_subscript: None,
|
||||
};
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PyAsyncMethods {
|
||||
pub am_await: Option<object::unaryfunc>,
|
||||
pub am_aiter: Option<object::unaryfunc>,
|
||||
pub am_anext: Option<object::unaryfunc>,
|
||||
}
|
||||
|
||||
impl Default for PyAsyncMethods {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
PyAsyncMethods_INIT
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyAsyncMethods_INIT: PyAsyncMethods = PyAsyncMethods {
|
||||
am_await: None,
|
||||
am_aiter: None,
|
||||
am_anext: None,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PyBufferProcs {
|
||||
pub bf_getbuffer: Option<object::getbufferproc>,
|
||||
pub bf_releasebuffer: Option<object::releasebufferproc>,
|
||||
}
|
||||
|
||||
impl Default for PyBufferProcs {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
PyBufferProcs_INIT
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyBufferProcs_INIT: PyBufferProcs = PyBufferProcs {
|
||||
bf_getbuffer: None,
|
||||
bf_releasebuffer: None,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PyTypeObject {
|
||||
|
@ -650,7 +541,7 @@ mod typeobject {
|
|||
pub const PyTypeObject_INIT: PyTypeObject = type_object_init!();
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct PyHeapTypeObject {
|
||||
pub ht_type: PyTypeObject,
|
||||
pub as_async: PyAsyncMethods,
|
||||
|
@ -825,6 +716,7 @@ extern "C" {
|
|||
arg2: *mut PyObject,
|
||||
arg3: *mut PyObject,
|
||||
) -> c_int;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn PyObject_GenericGetDict(arg1: *mut PyObject, arg2: *mut c_void) -> *mut PyObject;
|
||||
pub fn PyObject_GenericSetDict(
|
||||
arg1: *mut PyObject,
|
||||
|
|
|
@ -143,6 +143,11 @@ pub unsafe fn PyIter_Check(o: *mut PyObject) -> c_int {
|
|||
}) as c_int
|
||||
}
|
||||
|
||||
#[cfg(all(Py_LIMITED_API, Py_3_8))]
|
||||
extern "C" {
|
||||
pub fn PyIter_Check(obj: *mut PyObject) -> c_int;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg_attr(PyPy, link_name = "PyPyIter_Next")]
|
||||
pub fn PyIter_Next(arg1: *mut PyObject) -> *mut PyObject;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
//! Free allocation list
|
||||
|
||||
use crate::pyclass::{tp_free_fallback, PyClassAlloc};
|
||||
use crate::pyclass::{get_type_free, tp_free_fallback, PyClassAlloc};
|
||||
use crate::type_object::{PyLayout, PyTypeInfo};
|
||||
use crate::{ffi, AsPyPointer, FromPyPointer, PyAny, Python};
|
||||
use std::mem;
|
||||
|
@ -85,15 +85,14 @@ where
|
|||
unsafe fn dealloc(py: Python, self_: *mut Self::Layout) {
|
||||
(*self_).py_drop(py);
|
||||
let obj = PyAny::from_borrowed_ptr_or_panic(py, self_ as _);
|
||||
if Self::is_exact_instance(obj) && ffi::PyObject_CallFinalizerFromDealloc(obj.as_ptr()) < 0
|
||||
{
|
||||
// tp_finalize resurrected.
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(obj) = <Self as PyClassWithFreeList>::get_free_list(py).insert(obj.as_ptr()) {
|
||||
match (*ffi::Py_TYPE(obj)).tp_free {
|
||||
Some(free) => free(obj as *mut c_void),
|
||||
match get_type_free(ffi::Py_TYPE(obj)) {
|
||||
Some(free) => {
|
||||
let ty = ffi::Py_TYPE(obj);
|
||||
free(obj as *mut c_void);
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
None => tp_free_fallback(obj),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,6 +184,7 @@ mod gil;
|
|||
mod instance;
|
||||
#[macro_use]
|
||||
mod internal_tricks;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub mod marshal;
|
||||
pub mod once_cell;
|
||||
pub mod panic;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
#![cfg(not(Py_LIMITED_API))]
|
||||
//! Support for the Python `marshal` format. Not supported in limited API
|
||||
//! builds.
|
||||
|
||||
use crate::ffi;
|
||||
use crate::types::{PyAny, PyBytes};
|
||||
use crate::{AsPyPointer, FromPyPointer, PyResult, Python};
|
||||
|
|
|
@ -8,9 +8,9 @@ use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo
|
|||
use crate::types::PyAny;
|
||||
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::fmt;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::{fmt, mem};
|
||||
|
||||
/// Base layout of PyCell.
|
||||
/// This is necessary for sharing BorrowFlag between parents and children.
|
||||
|
@ -170,20 +170,26 @@ pub struct PyCell<T: PyClass> {
|
|||
|
||||
impl<T: PyClass> PyCell<T> {
|
||||
/// Get the offset of the dictionary from the start of the struct in bytes.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub(crate) fn dict_offset() -> Option<usize> {
|
||||
if T::Dict::IS_DUMMY {
|
||||
None
|
||||
} else {
|
||||
Some(mem::size_of::<Self>() - mem::size_of::<T::Dict>() - mem::size_of::<T::WeakRef>())
|
||||
Some(
|
||||
std::mem::size_of::<Self>()
|
||||
- std::mem::size_of::<T::Dict>()
|
||||
- std::mem::size_of::<T::WeakRef>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the offset of the weakref list from the start of the struct in bytes.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub(crate) fn weakref_offset() -> Option<usize> {
|
||||
if T::WeakRef::IS_DUMMY {
|
||||
None
|
||||
} else {
|
||||
Some(mem::size_of::<Self>() - mem::size_of::<T::WeakRef>())
|
||||
Some(std::mem::size_of::<Self>() - std::mem::size_of::<T::WeakRef>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -455,7 +461,7 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
|
|||
/// - You want to get super class.
|
||||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(subclass)]
|
||||
/// struct Parent {
|
||||
/// basename: &'static str,
|
||||
/// }
|
||||
|
@ -516,11 +522,11 @@ where
|
|||
/// # Examples
|
||||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(subclass)]
|
||||
/// struct Base1 {
|
||||
/// name1: &'static str,
|
||||
/// }
|
||||
/// #[pyclass(extends=Base1)]
|
||||
/// #[pyclass(extends=Base1, subclass)]
|
||||
/// struct Base2 {
|
||||
/// name2: &'static str,
|
||||
/// }
|
||||
|
|
334
src/pyclass.rs
334
src/pyclass.rs
|
@ -7,11 +7,34 @@ use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
|||
use crate::type_object::{type_flags, PyLayout};
|
||||
use crate::types::PyAny;
|
||||
use crate::{ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CString;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_void;
|
||||
#[cfg(not(PyPy))]
|
||||
use std::mem;
|
||||
use std::os::raw::{c_char, c_int, c_uint, c_void};
|
||||
use std::{ptr, thread};
|
||||
|
||||
#[cfg(PyPy)]
|
||||
unsafe fn get_type_alloc(tp: *mut ffi::PyTypeObject) -> Option<ffi::allocfunc> {
|
||||
(*tp).tp_alloc
|
||||
}
|
||||
|
||||
#[cfg(not(PyPy))]
|
||||
unsafe fn get_type_alloc(tp: *mut ffi::PyTypeObject) -> Option<ffi::allocfunc> {
|
||||
mem::transmute(ffi::PyType_GetSlot(tp, ffi::Py_tp_alloc))
|
||||
}
|
||||
|
||||
#[cfg(PyPy)]
|
||||
pub(crate) unsafe fn get_type_free(tp: *mut ffi::PyTypeObject) -> Option<ffi::freefunc> {
|
||||
(*tp).tp_free
|
||||
}
|
||||
|
||||
#[cfg(not(PyPy))]
|
||||
pub(crate) unsafe fn get_type_free(tp: *mut ffi::PyTypeObject) -> Option<ffi::freefunc> {
|
||||
mem::transmute(ffi::PyType_GetSlot(tp, ffi::Py_tp_free))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn default_new<T: PyTypeInfo>(
|
||||
py: Python,
|
||||
|
@ -19,12 +42,21 @@ pub(crate) unsafe fn default_new<T: PyTypeInfo>(
|
|||
) -> *mut ffi::PyObject {
|
||||
// if the class derives native types(e.g., PyDict), call special new
|
||||
if T::FLAGS & type_flags::EXTENDED != 0 && T::BaseLayout::IS_NATIVE_TYPE {
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
{
|
||||
let base_tp = T::BaseType::type_object_raw(py);
|
||||
if let Some(base_new) = (*base_tp).tp_new {
|
||||
return base_new(subtype, ptr::null_mut(), ptr::null_mut());
|
||||
}
|
||||
}
|
||||
let alloc = (*subtype).tp_alloc.unwrap_or(ffi::PyType_GenericAlloc);
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
{
|
||||
// Silence unused parameter warning.
|
||||
let _ = py;
|
||||
unreachable!("Subclassing native types isn't support in limited API mode");
|
||||
}
|
||||
}
|
||||
let alloc = get_type_alloc(subtype).unwrap_or(ffi::PyType_GenericAlloc);
|
||||
alloc(subtype, 0) as _
|
||||
}
|
||||
|
||||
|
@ -45,14 +77,13 @@ pub trait PyClassAlloc: PyTypeInfo + Sized {
|
|||
unsafe fn dealloc(py: Python, self_: *mut Self::Layout) {
|
||||
(*self_).py_drop(py);
|
||||
let obj = PyAny::from_borrowed_ptr_or_panic(py, self_ as _);
|
||||
if Self::is_exact_instance(obj) && ffi::PyObject_CallFinalizerFromDealloc(obj.as_ptr()) < 0
|
||||
{
|
||||
// tp_finalize resurrected.
|
||||
return;
|
||||
}
|
||||
|
||||
match (*ffi::Py_TYPE(obj.as_ptr())).tp_free {
|
||||
Some(free) => free(obj.as_ptr() as *mut c_void),
|
||||
match get_type_free(ffi::Py_TYPE(obj.as_ptr())) {
|
||||
Some(free) => {
|
||||
let ty = ffi::Py_TYPE(obj.as_ptr());
|
||||
free(obj.as_ptr() as *mut c_void);
|
||||
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
None => tp_free_fallback(obj.as_ptr()),
|
||||
}
|
||||
}
|
||||
|
@ -107,134 +138,151 @@ pub trait PyClass:
|
|||
type BaseNativeType: PyTypeInfo + PyNativeType;
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub(crate) fn initialize_type_object<T>(
|
||||
py: Python,
|
||||
module_name: Option<&str>,
|
||||
type_object: &mut ffi::PyTypeObject,
|
||||
) -> PyResult<()>
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
type_object.tp_doc = match T::DESCRIPTION {
|
||||
// PyPy will segfault if passed only a nul terminator as `tp_doc`, ptr::null() is OK though.
|
||||
"\0" => ptr::null(),
|
||||
s if s.as_bytes().ends_with(b"\0") => s.as_ptr() as _,
|
||||
// If the description is not null-terminated, create CString and leak it
|
||||
s => CString::new(s)?.into_raw(),
|
||||
};
|
||||
/// For collecting slot items.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct TypeSlots(Vec<ffi::PyType_Slot>);
|
||||
|
||||
type_object.tp_base = T::BaseType::type_object_raw(py);
|
||||
|
||||
type_object.tp_name = match module_name {
|
||||
Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(),
|
||||
None => CString::new(T::NAME)?.into_raw(),
|
||||
};
|
||||
|
||||
// dealloc
|
||||
type_object.tp_dealloc = tp_dealloc::<T>();
|
||||
|
||||
// type size
|
||||
type_object.tp_basicsize = std::mem::size_of::<T::Layout>() as ffi::Py_ssize_t;
|
||||
|
||||
// __dict__ support
|
||||
if let Some(dict_offset) = PyCell::<T>::dict_offset() {
|
||||
type_object.tp_dictoffset = dict_offset as ffi::Py_ssize_t;
|
||||
impl TypeSlots {
|
||||
fn push(&mut self, slot: c_int, pfunc: *mut c_void) {
|
||||
self.0.push(ffi::PyType_Slot { slot, pfunc });
|
||||
}
|
||||
|
||||
// weakref support
|
||||
if let Some(weakref_offset) = PyCell::<T>::weakref_offset() {
|
||||
type_object.tp_weaklistoffset = weakref_offset as ffi::Py_ssize_t;
|
||||
}
|
||||
|
||||
// GC support
|
||||
if let Some(gc) = T::gc_methods() {
|
||||
unsafe { gc.as_ref() }.update_typeobj(type_object);
|
||||
}
|
||||
|
||||
// descriptor protocol
|
||||
if let Some(descr) = T::descr_methods() {
|
||||
unsafe { descr.as_ref() }.update_typeobj(type_object);
|
||||
}
|
||||
|
||||
// iterator methods
|
||||
if let Some(iter) = T::iter_methods() {
|
||||
unsafe { iter.as_ref() }.update_typeobj(type_object);
|
||||
}
|
||||
|
||||
// nb_bool is a part of PyObjectProtocol, but should be placed under tp_as_number
|
||||
let mut nb_bool = None;
|
||||
// basic methods
|
||||
if let Some(basic) = T::basic_methods() {
|
||||
unsafe { basic.as_ref() }.update_typeobj(type_object);
|
||||
nb_bool = unsafe { basic.as_ref() }.nb_bool;
|
||||
}
|
||||
|
||||
// number methods
|
||||
type_object.tp_as_number = T::number_methods()
|
||||
.map(|mut p| {
|
||||
unsafe { p.as_mut() }.nb_bool = nb_bool;
|
||||
p.as_ptr()
|
||||
})
|
||||
.unwrap_or_else(|| nb_bool.map_or_else(ptr::null_mut, ffi::PyNumberMethods::from_nb_bool));
|
||||
// mapping methods
|
||||
type_object.tp_as_mapping = T::mapping_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
// sequence methods
|
||||
type_object.tp_as_sequence = T::sequence_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
// async methods
|
||||
type_object.tp_as_async = T::async_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
// buffer protocol
|
||||
type_object.tp_as_buffer = T::buffer_methods().map_or_else(ptr::null_mut, |p| p.as_ptr());
|
||||
|
||||
let (new, call, mut methods) = py_class_method_defs::<T>();
|
||||
|
||||
// normal methods
|
||||
if !methods.is_empty() {
|
||||
methods.push(ffi::PyMethodDef_INIT);
|
||||
type_object.tp_methods = Box::into_raw(methods.into_boxed_slice()) as _;
|
||||
}
|
||||
|
||||
// __new__ method
|
||||
type_object.tp_new = new;
|
||||
// __call__ method
|
||||
type_object.tp_call = call;
|
||||
|
||||
// properties
|
||||
let mut props = py_class_properties::<T>();
|
||||
|
||||
if !T::Dict::IS_DUMMY {
|
||||
props.push(ffi::PyGetSetDef_DICT);
|
||||
}
|
||||
if !props.is_empty() {
|
||||
props.push(ffi::PyGetSetDef_INIT);
|
||||
type_object.tp_getset = Box::into_raw(props.into_boxed_slice()) as _;
|
||||
}
|
||||
|
||||
// set type flags
|
||||
py_class_flags::<T>(type_object);
|
||||
|
||||
// register type object
|
||||
unsafe {
|
||||
if ffi::PyType_Ready(type_object) == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PyErr::fetch(py))
|
||||
pub(crate) fn maybe_push(&mut self, slot: c_int, value: Option<*mut c_void>) {
|
||||
if let Some(pfunc) = value {
|
||||
self.push(slot, pfunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn py_class_flags<T: PyTypeInfo>(type_object: &mut ffi::PyTypeObject) {
|
||||
if type_object.tp_traverse != None
|
||||
|| type_object.tp_clear != None
|
||||
|| T::FLAGS & type_flags::GC != 0
|
||||
{
|
||||
type_object.tp_flags = ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HAVE_GC;
|
||||
fn tp_doc<T: PyClass>() -> PyResult<Option<*mut c_void>> {
|
||||
Ok(match T::DESCRIPTION {
|
||||
"\0" => None,
|
||||
s if s.as_bytes().ends_with(b"\0") => Some(s.as_ptr() as _),
|
||||
// If the description is not null-terminated, create CString and leak it
|
||||
s => Some(CString::new(s)?.into_raw() as _),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_type_name<T: PyTypeInfo>(module_name: Option<&str>) -> PyResult<*mut c_char> {
|
||||
Ok(match module_name {
|
||||
Some(module_name) => CString::new(format!("{}.{}", module_name, T::NAME))?.into_raw(),
|
||||
None => CString::new(T::NAME)?.into_raw(),
|
||||
})
|
||||
}
|
||||
|
||||
fn into_raw<T>(vec: Vec<T>) -> *mut c_void {
|
||||
Box::into_raw(vec.into_boxed_slice()) as _
|
||||
}
|
||||
|
||||
pub(crate) fn create_type_object<T>(
|
||||
py: Python,
|
||||
module_name: Option<&str>,
|
||||
) -> PyResult<*mut ffi::PyTypeObject>
|
||||
where
|
||||
T: PyClass,
|
||||
{
|
||||
let mut slots = TypeSlots::default();
|
||||
|
||||
slots.push(ffi::Py_tp_base, T::BaseType::type_object_raw(py) as _);
|
||||
slots.maybe_push(ffi::Py_tp_doc, tp_doc::<T>()?);
|
||||
slots.maybe_push(ffi::Py_tp_dealloc, tp_dealloc::<T>().map(|v| v as _));
|
||||
|
||||
let (new, call, methods) = py_class_method_defs::<T>();
|
||||
slots.maybe_push(ffi::Py_tp_new, new.map(|v| v as _));
|
||||
slots.maybe_push(ffi::Py_tp_call, call.map(|v| v as _));
|
||||
|
||||
// normal methods
|
||||
if !methods.is_empty() {
|
||||
slots.push(ffi::Py_tp_methods, into_raw(methods));
|
||||
}
|
||||
|
||||
// properties
|
||||
let props = py_class_properties::<T>();
|
||||
if !props.is_empty() {
|
||||
slots.push(ffi::Py_tp_getset, into_raw(props));
|
||||
}
|
||||
|
||||
// protocol methods
|
||||
let mut has_gc_methods = false;
|
||||
for slot in T::get_type_slots() {
|
||||
has_gc_methods |= slot.slot == ffi::Py_tp_clear;
|
||||
has_gc_methods |= slot.slot == ffi::Py_tp_traverse;
|
||||
slots.0.push(slot);
|
||||
}
|
||||
|
||||
slots.push(0, ptr::null_mut());
|
||||
let mut spec = ffi::PyType_Spec {
|
||||
name: get_type_name::<T>(module_name)?,
|
||||
basicsize: std::mem::size_of::<T::Layout>() as c_int,
|
||||
itemsize: 0,
|
||||
flags: py_class_flags::<T>(has_gc_methods),
|
||||
slots: slots.0.as_mut_slice().as_mut_ptr(),
|
||||
};
|
||||
|
||||
let type_object = unsafe { ffi::PyType_FromSpec(&mut spec) };
|
||||
if type_object.is_null() {
|
||||
Err(PyErr::fetch(py))
|
||||
} else {
|
||||
type_object.tp_flags = ffi::Py_TPFLAGS_DEFAULT;
|
||||
tp_init_additional::<T>(type_object as _);
|
||||
Ok(type_object as _)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
fn tp_init_additional<T: PyClass>(type_object: *mut ffi::PyTypeObject) {
|
||||
// Just patch the type objects for the things there's no
|
||||
// PyType_FromSpec API for... there's no reason this should work,
|
||||
// except for that it does and we have tests.
|
||||
|
||||
// Running this causes PyPy to segfault.
|
||||
#[cfg(all(not(PyPy), not(Py_3_10)))]
|
||||
{
|
||||
if T::DESCRIPTION != "\0" {
|
||||
unsafe {
|
||||
// Until CPython 3.10, tp_doc was treated specially for
|
||||
// heap-types, and it removed the text_signature value from it.
|
||||
// We go in after the fact and replace tp_doc with something
|
||||
// that _does_ include the text_signature value!
|
||||
ffi::PyObject_Free((*type_object).tp_doc as _);
|
||||
let data = ffi::PyObject_Malloc(T::DESCRIPTION.len());
|
||||
data.copy_from(T::DESCRIPTION.as_ptr() as _, T::DESCRIPTION.len());
|
||||
(*type_object).tp_doc = data as _;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(buffer) = T::get_buffer() {
|
||||
unsafe {
|
||||
(*(*type_object).tp_as_buffer).bf_getbuffer = buffer.bf_getbuffer;
|
||||
(*(*type_object).tp_as_buffer).bf_releasebuffer = buffer.bf_releasebuffer;
|
||||
}
|
||||
}
|
||||
// __dict__ support
|
||||
if let Some(dict_offset) = PyCell::<T>::dict_offset() {
|
||||
unsafe {
|
||||
(*type_object).tp_dictoffset = dict_offset as ffi::Py_ssize_t;
|
||||
}
|
||||
}
|
||||
// weakref support
|
||||
if let Some(weakref_offset) = PyCell::<T>::weakref_offset() {
|
||||
unsafe {
|
||||
(*type_object).tp_weaklistoffset = weakref_offset as ffi::Py_ssize_t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
fn tp_init_additional<T: PyClass>(_type_object: *mut ffi::PyTypeObject) {}
|
||||
|
||||
fn py_class_flags<T: PyClass + PyTypeInfo>(has_gc_methods: bool) -> c_uint {
|
||||
let mut flags = if has_gc_methods || T::FLAGS & type_flags::GC != 0 {
|
||||
ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HAVE_GC
|
||||
} else {
|
||||
ffi::Py_TPFLAGS_DEFAULT
|
||||
};
|
||||
if T::FLAGS & type_flags::BASETYPE != 0 {
|
||||
type_object.tp_flags |= ffi::Py_TPFLAGS_BASETYPE;
|
||||
flags |= ffi::Py_TPFLAGS_BASETYPE;
|
||||
}
|
||||
flags.try_into().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn py_class_attributes<T: PyMethods>() -> impl Iterator<Item = PyClassAttributeDef> {
|
||||
|
@ -244,6 +292,21 @@ pub(crate) fn py_class_attributes<T: PyMethods>() -> impl Iterator<Item = PyClas
|
|||
})
|
||||
}
|
||||
|
||||
fn fallback_new() -> Option<ffi::newfunc> {
|
||||
unsafe extern "C" fn fallback_new(
|
||||
_subtype: *mut ffi::PyTypeObject,
|
||||
_args: *mut ffi::PyObject,
|
||||
_kwds: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject {
|
||||
crate::callback_body!(py, {
|
||||
Err::<(), _>(crate::exceptions::PyTypeError::new_err(
|
||||
"No constructor defined",
|
||||
))
|
||||
})
|
||||
}
|
||||
Some(fallback_new)
|
||||
}
|
||||
|
||||
fn py_class_method_defs<T: PyMethods>() -> (
|
||||
Option<ffi::newfunc>,
|
||||
Option<ffi::PyCFunctionWithKeywords>,
|
||||
|
@ -251,7 +314,7 @@ fn py_class_method_defs<T: PyMethods>() -> (
|
|||
) {
|
||||
let mut defs = Vec::new();
|
||||
let mut call = None;
|
||||
let mut new = None;
|
||||
let mut new = fallback_new();
|
||||
|
||||
for def in T::py_methods() {
|
||||
match *def {
|
||||
|
@ -272,10 +335,14 @@ fn py_class_method_defs<T: PyMethods>() -> (
|
|||
}
|
||||
}
|
||||
|
||||
if !defs.is_empty() {
|
||||
defs.push(ffi::PyMethodDef_INIT);
|
||||
}
|
||||
|
||||
(new, call, defs)
|
||||
}
|
||||
|
||||
fn py_class_properties<T: PyMethods>() -> Vec<ffi::PyGetSetDef> {
|
||||
fn py_class_properties<T: PyClass>() -> Vec<ffi::PyGetSetDef> {
|
||||
let mut defs = std::collections::HashMap::new();
|
||||
|
||||
for def in T::py_methods() {
|
||||
|
@ -298,7 +365,14 @@ fn py_class_properties<T: PyMethods>() -> Vec<ffi::PyGetSetDef> {
|
|||
}
|
||||
}
|
||||
|
||||
defs.values().cloned().collect()
|
||||
let mut props: Vec<_> = defs.values().cloned().collect();
|
||||
if !T::Dict::IS_DUMMY {
|
||||
props.push(ffi::PyGetSetDef_DICT);
|
||||
}
|
||||
if !props.is_empty() {
|
||||
props.push(ffi::PyGetSetDef_INIT);
|
||||
}
|
||||
props
|
||||
}
|
||||
|
||||
/// This trait is implemented for `#[pyclass]` and handles following two situations:
|
||||
|
|
|
@ -30,12 +30,12 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
|
|||
/// ```
|
||||
/// # use pyo3::prelude::*;
|
||||
/// # use pyo3::py_run;
|
||||
/// #[pyclass]
|
||||
/// #[pyclass(subclass)]
|
||||
/// struct BaseClass {
|
||||
/// #[pyo3(get)]
|
||||
/// basename: &'static str,
|
||||
/// }
|
||||
/// #[pyclass(extends=BaseClass)]
|
||||
/// #[pyclass(extends=BaseClass, subclass)]
|
||||
/// struct SubClass {
|
||||
/// #[pyo3(get)]
|
||||
/// subname: &'static str,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use crate::conversion::IntoPyPointer;
|
||||
use crate::once_cell::GILOnceCell;
|
||||
use crate::pyclass::{initialize_type_object, py_class_attributes, PyClass};
|
||||
use crate::pyclass::{create_type_object, py_class_attributes, PyClass};
|
||||
use crate::pyclass_init::PyObjectInit;
|
||||
use crate::types::{PyAny, PyType};
|
||||
use crate::{ffi, AsPyPointer, PyErr, PyNativeType, PyObject, PyResult, Python};
|
||||
|
@ -157,12 +157,10 @@ impl LazyStaticType {
|
|||
|
||||
pub fn get_or_init<T: PyClass>(&self, py: Python) -> *mut ffi::PyTypeObject {
|
||||
let type_object = *self.value.get_or_init(py, || {
|
||||
let mut type_object = Box::new(ffi::PyTypeObject_INIT);
|
||||
initialize_type_object::<T>(py, T::MODULE, type_object.as_mut()).unwrap_or_else(|e| {
|
||||
create_type_object::<T>(py, T::MODULE).unwrap_or_else(|e| {
|
||||
e.print(py);
|
||||
panic!("An error occurred while initializing class {}", T::NAME)
|
||||
});
|
||||
Box::into_raw(type_object)
|
||||
})
|
||||
});
|
||||
|
||||
// We might want to fill the `tp_dict` with python instances of `T`
|
||||
|
@ -204,10 +202,7 @@ impl LazyStaticType {
|
|||
// Now we hold the GIL and we can assume it won't be released until we
|
||||
// return from the function.
|
||||
let result = self.tp_dict_filled.get_or_init(py, move || {
|
||||
let tp_dict = unsafe { (*type_object).tp_dict };
|
||||
let result = initialize_tp_dict(py, tp_dict, items);
|
||||
// See discussion on #982 for why we need this.
|
||||
unsafe { ffi::PyType_Modified(type_object) };
|
||||
let result = initialize_tp_dict(py, type_object as *mut ffi::PyObject, items);
|
||||
|
||||
// Initialization successfully complete, can clear the thread list.
|
||||
// (No further calls to get_or_init() will try to init, on any thread.)
|
||||
|
@ -226,13 +221,13 @@ impl LazyStaticType {
|
|||
|
||||
fn initialize_tp_dict(
|
||||
py: Python,
|
||||
tp_dict: *mut ffi::PyObject,
|
||||
type_object: *mut ffi::PyObject,
|
||||
items: Vec<(&'static std::ffi::CStr, PyObject)>,
|
||||
) -> PyResult<()> {
|
||||
// We hold the GIL: the dictionary update can be considered atomic from
|
||||
// the POV of other threads.
|
||||
for (key, val) in items {
|
||||
let ret = unsafe { ffi::PyDict_SetItemString(tp_dict, key.as_ptr(), val.into_ptr()) };
|
||||
let ret = unsafe { ffi::PyObject_SetAttrString(type_object, key.as_ptr(), val.into_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(PyErr::fetch(py));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#[cfg(not(PyPy))]
|
||||
#[cfg(all(not(PyPy), not(Py_LIMITED_API)))]
|
||||
use crate::instance::PyNativeType;
|
||||
use crate::{ffi, AsPyPointer, PyAny, Python};
|
||||
#[cfg(not(PyPy))]
|
||||
#[cfg(all(not(PyPy), not(Py_LIMITED_API)))]
|
||||
use std::ops::*;
|
||||
use std::os::raw::c_double;
|
||||
|
||||
|
|
|
@ -83,7 +83,9 @@ impl<'source> FromPyObject<'source> for f32 {
|
|||
mod test {
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::ffi::PyFloat_AS_DOUBLE;
|
||||
use crate::{AsPyPointer, Python, ToPyObject};
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
use crate::AsPyPointer;
|
||||
use crate::{Python, ToPyObject};
|
||||
|
||||
macro_rules! num_to_py_object_and_back (
|
||||
($func_name:ident, $t1:ty, $t2:ty) => (
|
||||
|
|
|
@ -96,4 +96,5 @@ impl PyCFunction {
|
|||
#[repr(transparent)]
|
||||
pub struct PyFunction(PyAny);
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pyobject_native_var_type!(PyFunction, ffi::PyFunction_Type, ffi::PyFunction_Check);
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
//
|
||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||
|
||||
use crate::{
|
||||
ffi, AsPyPointer, PyAny, PyDowncastError, PyErr, PyNativeType, PyResult, PyTryFrom, Python,
|
||||
};
|
||||
use crate::{ffi, AsPyPointer, PyAny, PyErr, PyNativeType, PyResult, Python};
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
use crate::{PyDowncastError, PyTryFrom};
|
||||
|
||||
/// A Python iterator object.
|
||||
///
|
||||
|
@ -28,6 +28,7 @@ use crate::{
|
|||
#[repr(transparent)]
|
||||
pub struct PyIterator(PyAny);
|
||||
pyobject_native_type_named!(PyIterator);
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
pyobject_native_type_extract!(PyIterator);
|
||||
|
||||
impl PyIterator {
|
||||
|
@ -67,6 +68,8 @@ impl<'p> Iterator for &'p PyIterator {
|
|||
}
|
||||
}
|
||||
|
||||
// PyIter_Check does not exist in the limited API until 3.8
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
impl<'v> PyTryFrom<'v> for PyIterator {
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
|
||||
let value = value.into();
|
||||
|
@ -96,7 +99,9 @@ mod tests {
|
|||
use crate::exceptions::PyTypeError;
|
||||
use crate::gil::GILPool;
|
||||
use crate::types::{PyDict, PyList};
|
||||
use crate::{Py, PyAny, PyTryFrom, Python, ToPyObject};
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
use crate::{Py, PyAny, PyTryFrom};
|
||||
use crate::{Python, ToPyObject};
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
|
@ -200,6 +205,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_8))]
|
||||
fn iterator_try_from() {
|
||||
let gil_guard = Python::acquire_gil();
|
||||
let py = gil_guard.python();
|
||||
|
|
|
@ -106,6 +106,8 @@ macro_rules! pyobject_native_type_core {
|
|||
#[macro_export]
|
||||
macro_rules! pyobject_native_type_sized {
|
||||
($name: ty, $layout: path $(,$type_param: ident)*) => {
|
||||
// To prevent inheriting native types with ABI3
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl $crate::type_object::PySizedLayout<$name> for $layout {}
|
||||
impl<'a, $($type_param,)*> $crate::derive_utils::PyBaseTypeUtils for $name {
|
||||
type Dict = $crate::pyclass_slots::PyClassDummySlot;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
//
|
||||
|
||||
use crate::err::{self, PyErr, PyResult};
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
use crate::types::PyIterator;
|
||||
use crate::{
|
||||
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyNativeType, PyObject, Python,
|
||||
ToBorrowedObject, ToPyObject,
|
||||
|
@ -110,12 +112,32 @@ impl PySet {
|
|||
/// Returns an iterator of values in this set.
|
||||
///
|
||||
/// Note that it can be unsafe to use when the set might be changed by other code.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn iter(&self) -> PySetIterator {
|
||||
PySetIterator {
|
||||
set: self.as_ref(),
|
||||
pos: 0,
|
||||
PySetIterator::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
pub struct PySetIterator<'p> {
|
||||
it: &'p PyIterator,
|
||||
}
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
impl PySetIterator<'_> {
|
||||
fn new(set: &PyAny) -> PySetIterator {
|
||||
PySetIterator {
|
||||
it: PyIterator::from_object(set.py(), set).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
impl<'py> Iterator for PySetIterator<'py> {
|
||||
type Item = &'py super::PyAny;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.it.next().map(|p| p.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,6 +147,13 @@ pub struct PySetIterator<'py> {
|
|||
pos: isize,
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl PySetIterator<'_> {
|
||||
fn new(set: &PyAny) -> PySetIterator {
|
||||
PySetIterator { set, pos: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl<'py> Iterator for PySetIterator<'py> {
|
||||
type Item = &'py super::PyAny;
|
||||
|
@ -145,7 +174,6 @@ impl<'py> Iterator for PySetIterator<'py> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl<'a> std::iter::IntoIterator for &'a PySet {
|
||||
type Item = &'a PyAny;
|
||||
type IntoIter = PySetIterator<'a>;
|
||||
|
@ -281,22 +309,17 @@ impl PyFrozenSet {
|
|||
/// Returns an iterator of values in this frozen set.
|
||||
///
|
||||
/// Note that it can be unsafe to use when the set might be changed by other code.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
pub fn iter(&self) -> PySetIterator {
|
||||
self.into_iter()
|
||||
PySetIterator::new(self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
impl<'a> std::iter::IntoIterator for &'a PyFrozenSet {
|
||||
type Item = &'a PyAny;
|
||||
type IntoIter = PySetIterator<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
PySetIterator {
|
||||
set: self.as_ref(),
|
||||
pos: 0,
|
||||
}
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ impl PyString {
|
|||
/// (containing unpaired surrogates).
|
||||
#[inline]
|
||||
pub fn to_str(&self) -> PyResult<&str> {
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
unsafe {
|
||||
let mut size: ffi::Py_ssize_t = 0;
|
||||
let data = ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) as *const u8;
|
||||
|
@ -54,6 +55,16 @@ impl PyString {
|
|||
Ok(std::str::from_utf8_unchecked(slice))
|
||||
}
|
||||
}
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
unsafe {
|
||||
let data = ffi::PyUnicode_AsUTF8String(self.as_ptr());
|
||||
if data.is_null() {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
let bytes = self.py().from_owned_ptr::<PyBytes>(data);
|
||||
Ok(std::str::from_utf8_unchecked(bytes.as_bytes()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the `PyString` into a Rust string.
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::{
|
|||
exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType,
|
||||
PyObject, PyResult, PyTryFrom, Python, ToPyObject,
|
||||
};
|
||||
use std::slice;
|
||||
|
||||
/// Represents a Python `tuple` object.
|
||||
///
|
||||
|
@ -87,7 +86,7 @@ impl PyTuple {
|
|||
// and because tuples are immutable.
|
||||
unsafe {
|
||||
let ptr = self.as_ptr() as *mut ffi::PyTupleObject;
|
||||
let slice = slice::from_raw_parts((*ptr).ob_item.as_ptr(), self.len());
|
||||
let slice = std::slice::from_raw_parts((*ptr).ob_item.as_ptr(), self.len());
|
||||
&*(slice as *const [*mut ffi::PyObject] as *const [&PyAny])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ use crate::err::{PyErr, PyResult};
|
|||
use crate::instance::PyNativeType;
|
||||
use crate::type_object::PyTypeObject;
|
||||
use crate::{ffi, AsPyPointer, PyAny, Python};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CStr;
|
||||
|
||||
/// Represents a reference to a Python `type object`.
|
||||
#[repr(transparent)]
|
||||
|
@ -39,8 +37,8 @@ impl PyType {
|
|||
}
|
||||
|
||||
/// Gets the name of the `PyType`.
|
||||
pub fn name(&self) -> Cow<str> {
|
||||
unsafe { CStr::from_ptr((*self.as_type_ptr()).tp_name).to_string_lossy() }
|
||||
pub fn name(&self) -> PyResult<&str> {
|
||||
self.getattr("__qualname__")?.extract()
|
||||
}
|
||||
|
||||
/// Checks whether `self` is subclass of type `T`.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![cfg(not(Py_LIMITED_API))]
|
||||
|
||||
use pyo3::buffer::PyBuffer;
|
||||
use pyo3::class::PyBufferProtocol;
|
||||
use pyo3::exceptions::PyBufferError;
|
||||
|
|
|
@ -51,7 +51,10 @@ fn class_attributes() {
|
|||
py_assert!(py, foo_obj, "foo_obj.MY_CONST == 'foobar'");
|
||||
}
|
||||
|
||||
// Ignored because heap types are not immutable:
|
||||
// https://github.com/python/cpython/blob/master/Objects/typeobject.c#L3399-L3409
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn class_attributes_are_immutable() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
|
|
@ -119,7 +119,11 @@ fn test_raw_idents() {
|
|||
#[pyclass]
|
||||
struct EmptyClassInModule {}
|
||||
|
||||
// Ignored because heap types do not show up as being in builtins, instead they
|
||||
// raise AttributeError:
|
||||
// https://github.com/python/cpython/blob/master/Objects/typeobject.c#L544-L573
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn empty_class_in_module() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -165,7 +169,7 @@ fn class_with_object_field() {
|
|||
py_assert!(py, ty, "ty(None).value == None");
|
||||
}
|
||||
|
||||
#[pyclass(unsendable)]
|
||||
#[pyclass(unsendable, subclass)]
|
||||
struct UnsendableBase {
|
||||
value: std::rc::Rc<usize>,
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ fn test_cloneable_pyclass() {
|
|||
assert_eq!(&c, &*mrc);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(subclass)]
|
||||
#[derive(Default)]
|
||||
struct BaseClass {
|
||||
value: i32,
|
||||
|
|
|
@ -26,6 +26,8 @@ fn test_compile_errors() {
|
|||
t.compile_fail("tests/ui/invalid_pymethod_receiver.rs");
|
||||
t.compile_fail("tests/ui/invalid_result_conversion.rs");
|
||||
t.compile_fail("tests/ui/missing_clone.rs");
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
t.compile_fail("tests/ui/abi3_nativetype_inheritance.rs");
|
||||
}
|
||||
#[rustversion::before(1.46)]
|
||||
fn tests_rust_1_46(_t: &trybuild::TestCases) {}
|
||||
|
|
|
@ -453,10 +453,11 @@ fn test_cls_impl() {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[pyclass(dict)]
|
||||
#[pyclass(dict, subclass)]
|
||||
struct DunderDictSupport {}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn dunder_dict_support() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -472,6 +473,7 @@ fn dunder_dict_support() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn access_dunder_dict() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -493,6 +495,7 @@ struct InheritDict {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn inherited_dict() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -511,6 +514,7 @@ fn inherited_dict() {
|
|||
struct WeakRefDunderDictSupport {}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn weakref_dunder_dict_support() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
|
|
@ -146,10 +146,11 @@ fn gc_integration2() {
|
|||
py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
|
||||
}
|
||||
|
||||
#[pyclass(weakref)]
|
||||
#[pyclass(weakref, subclass)]
|
||||
struct WeakRefSupport {}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn weakref_support() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -168,6 +169,7 @@ struct InheritWeakRef {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn inherited_weakref() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -179,7 +181,7 @@ fn inherited_weakref() {
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(subclass)]
|
||||
struct BaseClassWithDrop {
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
@ -269,6 +271,16 @@ impl PyGCProtocol for TraversableClass {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(PyPy)]
|
||||
unsafe fn get_type_traverse(tp: *mut pyo3::ffi::PyTypeObject) -> Option<pyo3::ffi::traverseproc> {
|
||||
(*tp).tp_traverse
|
||||
}
|
||||
|
||||
#[cfg(not(PyPy))]
|
||||
unsafe fn get_type_traverse(tp: *mut pyo3::ffi::PyTypeObject) -> Option<pyo3::ffi::traverseproc> {
|
||||
std::mem::transmute(pyo3::ffi::PyType_GetSlot(tp, pyo3::ffi::Py_tp_traverse))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gc_during_borrow() {
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -285,7 +297,7 @@ fn gc_during_borrow() {
|
|||
|
||||
// get the traverse function
|
||||
let ty = TraversableClass::type_object(py).as_type_ptr();
|
||||
let traverse = (*ty).tp_traverse.unwrap();
|
||||
let traverse = get_type_traverse(ty).unwrap();
|
||||
|
||||
// create an object and check that traversing it works normally
|
||||
// when it's not borrowed
|
||||
|
|
|
@ -3,10 +3,9 @@ use pyo3::py_run;
|
|||
|
||||
use pyo3::types::IntoPyDict;
|
||||
|
||||
use pyo3::types::{PyDict, PySet};
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(subclass)]
|
||||
struct BaseClass {
|
||||
#[pyo3(get)]
|
||||
val1: usize,
|
||||
|
@ -106,7 +105,7 @@ fn mutation_fails() {
|
|||
)
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[pyclass(subclass)]
|
||||
struct BaseClassWithResult {
|
||||
_val: usize,
|
||||
}
|
||||
|
@ -153,23 +152,29 @@ except Exception as e:
|
|||
);
|
||||
}
|
||||
|
||||
#[pyclass(extends=PySet)]
|
||||
#[derive(Debug)]
|
||||
struct SetWithName {
|
||||
// Subclassing builtin types is not allowed in the LIMITED API.
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
mod inheriting_native_type {
|
||||
use super::*;
|
||||
use pyo3::types::{PyDict, PySet};
|
||||
|
||||
#[pyclass(extends=PySet)]
|
||||
#[derive(Debug)]
|
||||
struct SetWithName {
|
||||
#[pyo3(get(name))]
|
||||
_name: &'static str,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl SetWithName {
|
||||
#[pymethods]
|
||||
impl SetWithName {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
SetWithName { _name: "Hello :)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inherit_set() {
|
||||
#[test]
|
||||
fn inherit_set() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let set_sub = pyo3::PyCell::new(py, SetWithName::new()).unwrap();
|
||||
|
@ -178,25 +183,25 @@ fn inherit_set() {
|
|||
set_sub,
|
||||
r#"set_sub.add(10); assert list(set_sub) == [10]; assert set_sub._name == "Hello :)""#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends=PyDict)]
|
||||
#[derive(Debug)]
|
||||
struct DictWithName {
|
||||
#[pyclass(extends=PyDict)]
|
||||
#[derive(Debug)]
|
||||
struct DictWithName {
|
||||
#[pyo3(get(name))]
|
||||
_name: &'static str,
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl DictWithName {
|
||||
#[pymethods]
|
||||
impl DictWithName {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
DictWithName { _name: "Hello :)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inherit_dict() {
|
||||
#[test]
|
||||
fn inherit_dict() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let dict_sub = pyo3::PyCell::new(py, DictWithName::new()).unwrap();
|
||||
|
@ -205,4 +210,5 @@ fn inherit_dict() {
|
|||
dict_sub,
|
||||
r#"dict_sub[0] = 1; assert dict_sub[0] == 1; assert dict_sub._name == "Hello :)""#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ impl ClassMethod {
|
|||
#[classmethod]
|
||||
/// Test class method.
|
||||
fn method(cls: &PyType) -> PyResult<String> {
|
||||
Ok(format!("{}.method()!", cls.name()))
|
||||
Ok(format!("{}.method()!", cls.name()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ struct ClassMethodWithArgs {}
|
|||
impl ClassMethodWithArgs {
|
||||
#[classmethod]
|
||||
fn method(cls: &PyType, input: &PyString) -> PyResult<String> {
|
||||
Ok(format!("{}.method({})", cls.name(), input))
|
||||
Ok(format!("{}.method({})", cls.name()?, input))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#[cfg(not(Py_LIMITED_API))]
|
||||
use pyo3::buffer::PyBuffer;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyCFunction, PyFunction};
|
||||
use pyo3::types::PyCFunction;
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
use pyo3::types::PyFunction;
|
||||
use pyo3::{raw_pycfunction, wrap_pyfunction};
|
||||
|
||||
mod common;
|
||||
|
@ -23,6 +26,7 @@ fn test_optional_bool() {
|
|||
py_assert!(py, f, "f(None) == 'None'");
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[pyfunction]
|
||||
fn buffer_inplace_add(py: Python, x: PyBuffer<i32>, y: PyBuffer<i32>) {
|
||||
let x = x.as_mut_slice(py).unwrap();
|
||||
|
@ -33,6 +37,7 @@ fn buffer_inplace_add(py: Python, x: PyBuffer<i32>, y: PyBuffer<i32>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[test]
|
||||
fn test_buffer_add() {
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -64,6 +69,7 @@ assert a, array.array("i", [2, 4, 6, 8])
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
#[pyfunction]
|
||||
fn function_with_pyfunction_arg(fun: &PyFunction) -> PyResult<&PyAny> {
|
||||
fun.call((), None)
|
||||
|
@ -78,21 +84,31 @@ fn function_with_pycfunction_arg(fun: &PyCFunction) -> PyResult<&PyAny> {
|
|||
fn test_functions_with_function_args() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let py_func_arg = wrap_pyfunction!(function_with_pyfunction_arg)(py).unwrap();
|
||||
let py_cfunc_arg = wrap_pyfunction!(function_with_pycfunction_arg)(py).unwrap();
|
||||
let bool_to_string = wrap_pyfunction!(optional_bool)(py).unwrap();
|
||||
|
||||
pyo3::py_run!(
|
||||
py,
|
||||
py_func_arg
|
||||
py_cfunc_arg
|
||||
bool_to_string,
|
||||
r#"
|
||||
def foo(): return "bar"
|
||||
assert py_func_arg(foo) == "bar"
|
||||
assert py_cfunc_arg(bool_to_string) == "Some(true)"
|
||||
"#
|
||||
)
|
||||
);
|
||||
|
||||
#[cfg(not(Py_LIMITED_API))]
|
||||
{
|
||||
let py_func_arg = wrap_pyfunction!(function_with_pyfunction_arg)(py).unwrap();
|
||||
|
||||
pyo3::py_run!(
|
||||
py,
|
||||
py_func_arg,
|
||||
r#"
|
||||
def foo(): return "bar"
|
||||
assert py_func_arg(foo) == "bar"
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -32,6 +32,7 @@ fn class_with_docs() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(all(Py_LIMITED_API, not(Py_3_10)), ignore)]
|
||||
fn class_with_docs_and_signature() {
|
||||
/// docs line1
|
||||
#[pyclass]
|
||||
|
@ -67,6 +68,7 @@ fn class_with_docs_and_signature() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(all(Py_LIMITED_API, not(Py_3_10)), ignore)]
|
||||
fn class_with_signature() {
|
||||
#[pyclass]
|
||||
#[text_signature = "(a, b=None, *, c=42)"]
|
||||
|
@ -86,7 +88,11 @@ fn class_with_signature() {
|
|||
let py = gil.python();
|
||||
let typeobj = py.get_type::<MyClass>();
|
||||
|
||||
py_assert!(py, typeobj, "typeobj.__doc__ is None");
|
||||
py_assert!(
|
||||
py,
|
||||
typeobj,
|
||||
"typeobj.__doc__ is None or typeobj.__doc__ == ''"
|
||||
);
|
||||
py_assert!(
|
||||
py,
|
||||
typeobj,
|
||||
|
|
|
@ -13,6 +13,7 @@ impl UnsendableDictClass {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn test_unsendable_dict() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -32,6 +33,7 @@ impl UnsendableDictClassWithWeakRef {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn test_unsendable_dict_with_weakref() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
|
|
@ -149,6 +149,7 @@ fn add_module(py: Python, module: &PyModule) -> PyResult<()> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(Py_LIMITED_API, ignore)]
|
||||
fn test_pickle() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
//! With abi3, we cannot inherit native types.
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
|
||||
#[pyclass(extends=PyDict)]
|
||||
struct TestClass {}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,13 @@
|
|||
error[E0277]: the trait bound `pyo3::ffi::PyDictObject: pyo3::type_object::PySizedLayout<pyo3::types::PyDict>` is not satisfied
|
||||
--> $DIR/abi3_nativetype_inheritance.rs:5:1
|
||||
|
|
||||
5 | #[pyclass(extends=PyDict)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `pyo3::type_object::PySizedLayout<pyo3::types::PyDict>` is not implemented for `pyo3::ffi::PyDictObject`
|
||||
|
|
||||
::: $WORKSPACE/src/type_object.rs:96:22
|
||||
|
|
||||
96 | type BaseLayout: PySizedLayout<Self::BaseType>;
|
||||
| ----------------------------- required by this bound in `pyo3::PyTypeInfo`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `pyo3::type_object::PySizedLayout<pyo3::types::PyDict>` for `pyo3::pycell::PyCellBase<pyo3::types::PyDict>`
|
||||
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
Loading…
Reference in New Issue