From 6a687317b1055822fe2d141ffdee3e0d02b8d26f Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 14 Jul 2026 11:52:14 +0200 Subject: [PATCH 1/4] Add descriptor support to c-api --- crates/capi/src/descrobject.rs | 255 ++++++++++++++++++++++++++++++++- crates/vm/src/builtins/mod.rs | 4 + 2 files changed, 257 insertions(+), 2 deletions(-) diff --git a/crates/capi/src/descrobject.rs b/crates/capi/src/descrobject.rs index b0d24667dc7..8abb64b9e7d 100644 --- a/crates/capi/src/descrobject.rs +++ b/crates/capi/src/descrobject.rs @@ -1,7 +1,41 @@ use crate::PyObject; +use crate::methodobject::{PyMethodDef, build_method_def}; +use crate::object::PyTypeObject; use crate::pystate::with_vm; -use rustpython_vm::PyPayload; -use rustpython_vm::builtins::PyMappingProxy; +use core::ffi::{CStr, c_char, c_int, c_void}; +use core::ptr::NonNull; +use rustpython_vm::builtins::{ + DescriptorMemberDef, MemberGetter, MemberKind, MemberSetter, PyDescriptorOwned, PyMappingProxy, + PyMemberDescriptor, +}; +use rustpython_vm::common::lock::PyRwLock; +use rustpython_vm::function::PySetterValue; +use rustpython_vm::{PyObjectRef, PyPayload, PyResult}; + +#[repr(C)] +pub struct PyGetSetDef { + pub name: *const c_char, + pub get: + Option *mut PyObject>, + pub set: Option< + unsafe extern "C" fn( + slf: *mut PyObject, + value: *mut PyObject, + closure: *mut c_void, + ) -> c_int, + >, + pub doc: *const c_char, + pub closure: *mut c_void, +} + +#[repr(C)] +pub struct PyMemberDef { + pub name: *const c_char, + pub type_code: c_int, + pub offset: isize, + pub flags: c_int, + pub doc: *const c_char, +} #[unsafe(no_mangle)] pub unsafe extern "C" fn PyDictProxy_New(mapping: *mut PyObject) -> *mut PyObject { @@ -11,6 +45,223 @@ pub unsafe extern "C" fn PyDictProxy_New(mapping: *mut PyObject) -> *mut PyObjec }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewMethod( + typ: *mut PyTypeObject, + method: *mut PyMethodDef, +) -> *mut PyObject { + with_vm(|vm| -> PyResult { + let method = build_method_def(vm, unsafe { &*method }, true)?; + Ok(method.build_method(unsafe { &*typ }, vm).into()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewClassMethod( + typ: *mut PyTypeObject, + method: *mut PyMethodDef, +) -> *mut PyObject { + with_vm(|vm| -> PyResult { + let method = build_method_def(vm, unsafe { &*method }, true)?; + Ok(method.build_method(unsafe { &*typ }, vm).into()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewGetSet( + typ: *mut PyTypeObject, + getset: *mut PyGetSetDef, +) -> *mut PyObject { + with_vm(|vm| -> PyResult { + let typ = unsafe { &*typ }; + let getset = unsafe { &*getset }; + let name = unsafe { CStr::from_ptr(getset.name) } + .to_str() + .map_err(|_| vm.new_system_error("PyGetSetDef name was not valid UTF-8"))?; + + let descriptor = match (getset.get, getset.set) { + (Some(get), Some(set)) => { + let closure = getset.closure as usize; + vm.ctx.new_static_getset( + name, + typ, + move |obj: PyObjectRef, + vm: &rustpython_vm::VirtualMachine| + -> PyResult { + unsafe { + let closure = closure as *mut c_void; + let ret_ptr = get(obj.as_raw().cast_mut(), closure); + let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { + vm.take_raised_exception().expect( + "Native function returned NULL, but there was no exception set", + ) + })?; + Ok(PyObjectRef::from_raw(ret_ptr)) + } + }, + move |obj: PyObjectRef, + value: PySetterValue, + vm: &rustpython_vm::VirtualMachine| unsafe { + let closure = closure as *mut c_void; + let value = value.unwrap_or_none(vm); + let result = + set(obj.as_raw().cast_mut(), value.as_raw().cast_mut(), closure); + if result == 0 { + Ok(()) + } else { + Err(vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "C setter returned error but did not set an exception", + ) + })) + } + }, + ) + } + (Some(get), None) => { + let closure = getset.closure as usize; + vm.ctx.new_readonly_getset( + name, + typ, + move |obj: PyObjectRef, + vm: &rustpython_vm::VirtualMachine| + -> PyResult { + unsafe { + let closure = closure as *mut c_void; + let ret_ptr = get(obj.as_raw().cast_mut(), closure); + let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { + vm.take_raised_exception().expect( + "Native function returned NULL, but there was no exception set", + ) + })?; + Ok(PyObjectRef::from_raw(ret_ptr)) + } + }, + ) + } + (None, Some(set)) => { + let closure = getset.closure as usize; + vm.ctx.new_static_getset( + name, + typ, + move |_obj: PyObjectRef, + vm: &rustpython_vm::VirtualMachine| + -> PyResult { + Err(vm.new_attribute_error("unreadable attribute")) + }, + move |obj: PyObjectRef, + value: PySetterValue, + vm: &rustpython_vm::VirtualMachine| unsafe { + let closure = closure as *mut c_void; + let value = value.unwrap_or_none(vm); + let result = + set(obj.as_raw().cast_mut(), value.as_raw().cast_mut(), closure); + if result == 0 { + Ok(()) + } else { + Err(vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "C setter returned error but did not set an exception", + ) + })) + } + }, + ) + } + (None, None) => vm.ctx.new_readonly_getset( + name, + typ, + move |_obj: PyObjectRef, + vm: &rustpython_vm::VirtualMachine| + -> PyResult { + Err(vm.new_attribute_error("unreadable attribute")) + }, + ), + }; + + Ok(descriptor.into()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewMember( + typ: *mut PyTypeObject, + member: *mut PyMemberDef, +) -> *mut PyObject { + const PY_READONLY: c_int = 1; + const PY_RELATIVE_OFFSET: c_int = 8; + + with_vm(|vm| -> PyResult { + let typ = unsafe { &*typ }; + let member = unsafe { &*member }; + let name = unsafe { CStr::from_ptr(member.name) } + .to_str() + .map_err(|_| vm.new_system_error("PyMemberDef name was not valid UTF-8"))?; + let kind = match member.type_code { + 6 => MemberKind::Object, + 16 => MemberKind::ObjectEx, + 14 => MemberKind::Bool, + _ => { + return Err(vm.new_system_error(format!( + "PyDescr_NewMember does not support member type code {}", + member.type_code + ))); + } + }; + if member.offset < 0 { + return Err(vm.new_system_error("PyDescr_NewMember does not support negative offsets")); + } + if member.flags & PY_RELATIVE_OFFSET != 0 { + return Err( + vm.new_system_error("PyDescr_NewMember does not support Py_RELATIVE_OFFSET") + ); + } + + let doc = NonNull::new(member.doc.cast_mut()) + .map(|doc| { + unsafe { CStr::from_ptr(doc.as_ptr()) } + .to_str() + .map(|s| s.to_owned()) + .map_err(|_| vm.new_system_error("PyMemberDef doc was not valid UTF-8")) + }) + .transpose()?; + + let descriptor = PyMemberDescriptor { + common: PyDescriptorOwned { + typ: typ.to_owned(), + name: vm.ctx.intern_str(name), + qualname: PyRwLock::new(None), + }, + member: DescriptorMemberDef { + name: name.to_owned(), + kind, + getter: MemberGetter::Offset(member.offset as usize), + setter: if member.flags & PY_READONLY != 0 { + MemberSetter::Setter(None) + } else { + MemberSetter::Offset(member.offset as usize) + }, + doc, + }, + }; + + Ok(descriptor.into_ref(&vm.ctx).into()) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyWrapper_New(descr: *mut PyObject, obj: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let descr = unsafe { &*descr }; + let obj = unsafe { &*obj }; + vm.call_special_method( + descr, + vm.ctx.names.__get__, + (obj.to_owned(), obj.class().to_owned()), + ) + }) +} + #[cfg(test)] mod tests { use pyo3::prelude::*; diff --git a/crates/vm/src/builtins/mod.rs b/crates/vm/src/builtins/mod.rs index ffc01b00f29..f08a2b46721 100644 --- a/crates/vm/src/builtins/mod.rs +++ b/crates/vm/src/builtins/mod.rs @@ -99,6 +99,10 @@ pub use zip::PyZip; pub(crate) mod union_; pub use union_::{PyUnion, make_union}; pub(crate) mod descriptor; +pub use descriptor::{ + MemberGetter, MemberKind, MemberSetter, PyDescriptorOwned, PyMemberDef as DescriptorMemberDef, + PyMemberDescriptor, +}; pub use float::float_from_string as parse_float_from_string; pub use float::try_to_bigint as try_f64_to_bigint; From 54ff206925335c118b39d71d24e272c0544cc59c Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 14 Jul 2026 11:59:59 +0200 Subject: [PATCH 2/4] Review --- crates/capi/src/descrobject.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/capi/src/descrobject.rs b/crates/capi/src/descrobject.rs index 8abb64b9e7d..e02be91b6ac 100644 --- a/crates/capi/src/descrobject.rs +++ b/crates/capi/src/descrobject.rs @@ -92,9 +92,11 @@ pub unsafe extern "C" fn PyDescr_NewGetSet( let closure = closure as *mut c_void; let ret_ptr = get(obj.as_raw().cast_mut(), closure); let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { - vm.take_raised_exception().expect( - "Native function returned NULL, but there was no exception set", - ) + vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "Native function returned NULL, but there was no exception set", + ) + }) })?; Ok(PyObjectRef::from_raw(ret_ptr)) } @@ -130,9 +132,11 @@ pub unsafe extern "C" fn PyDescr_NewGetSet( let closure = closure as *mut c_void; let ret_ptr = get(obj.as_raw().cast_mut(), closure); let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { - vm.take_raised_exception().expect( - "Native function returned NULL, but there was no exception set", - ) + vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "Native function returned NULL, but there was no exception set", + ) + }) })?; Ok(PyObjectRef::from_raw(ret_ptr)) } From 4b29795df277b5c9c568ddcbd1d88dfdaec78a36 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 14 Jul 2026 14:28:10 +0200 Subject: [PATCH 3/4] Extract getset builder --- crates/capi/src/descrobject.rs | 228 +++++++++++++++------------------ 1 file changed, 106 insertions(+), 122 deletions(-) diff --git a/crates/capi/src/descrobject.rs b/crates/capi/src/descrobject.rs index e02be91b6ac..c75b3fd9682 100644 --- a/crates/capi/src/descrobject.rs +++ b/crates/capi/src/descrobject.rs @@ -5,12 +5,12 @@ use crate::pystate::with_vm; use core::ffi::{CStr, c_char, c_int, c_void}; use core::ptr::NonNull; use rustpython_vm::builtins::{ - DescriptorMemberDef, MemberGetter, MemberKind, MemberSetter, PyDescriptorOwned, PyMappingProxy, - PyMemberDescriptor, + DescriptorMemberDef, MemberGetter, MemberKind, MemberSetter, PyDescriptorOwned, PyGetSet, + PyMappingProxy, PyMemberDescriptor, PyType, }; use rustpython_vm::common::lock::PyRwLock; use rustpython_vm::function::PySetterValue; -use rustpython_vm::{PyObjectRef, PyPayload, PyResult}; +use rustpython_vm::{Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine}; #[repr(C)] pub struct PyGetSetDef { @@ -28,6 +28,102 @@ pub struct PyGetSetDef { pub closure: *mut c_void, } +impl PyGetSetDef { + pub(crate) fn build( + &self, + ty: &'static Py, + vm: &VirtualMachine, + ) -> PyResult> { + let name = unsafe { CStr::from_ptr(self.name) } + .to_str() + .map_err(|_| vm.new_system_error("PyGetSetDef name was not valid UTF-8"))?; + let closure = self.closure as usize; + + let descriptor = match (self.get, self.set) { + (Some(get), Some(set)) => vm.ctx.new_static_getset( + name, + ty, + move |obj: PyObjectRef, vm: &VirtualMachine| -> PyResult { + unsafe { + let closure = closure as *mut c_void; + let ret_ptr = get(obj.as_raw().cast_mut(), closure); + let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { + vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "Native function returned NULL, but there was no exception set", + ) + }) + })?; + Ok(PyObjectRef::from_raw(ret_ptr)) + } + }, + move |obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine| unsafe { + let closure = closure as *mut c_void; + let value = value.unwrap_or_none(vm); + let result = set(obj.as_raw().cast_mut(), value.as_raw().cast_mut(), closure); + if result == 0 { + Ok(()) + } else { + Err(vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "C setter returned error but did not set an exception", + ) + })) + } + }, + ), + (Some(get), None) => vm.ctx.new_readonly_getset( + name, + ty, + move |obj: PyObjectRef, vm: &VirtualMachine| -> PyResult { + unsafe { + let closure = closure as *mut c_void; + let ret_ptr = get(obj.as_raw().cast_mut(), closure); + let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { + vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "Native function returned NULL, but there was no exception set", + ) + }) + })?; + Ok(PyObjectRef::from_raw(ret_ptr)) + } + }, + ), + (None, Some(set)) => vm.ctx.new_static_getset( + name, + ty, + move |_obj: PyObjectRef, vm: &VirtualMachine| -> PyResult { + Err(vm.new_attribute_error("unreadable attribute")) + }, + move |obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine| unsafe { + let closure = closure as *mut c_void; + let value = value.unwrap_or_none(vm); + let result = set(obj.as_raw().cast_mut(), value.as_raw().cast_mut(), closure); + if result == 0 { + Ok(()) + } else { + Err(vm.take_raised_exception().unwrap_or_else(|| { + vm.new_system_error( + "C setter returned error but did not set an exception", + ) + })) + } + }, + ), + (None, None) => vm.ctx.new_readonly_getset( + name, + ty, + move |_obj: PyObjectRef, vm: &VirtualMachine| -> PyResult { + Err(vm.new_attribute_error("unreadable attribute")) + }, + ), + }; + + Ok(descriptor) + } +} + #[repr(C)] pub struct PyMemberDef { pub name: *const c_char, @@ -50,9 +146,9 @@ pub unsafe extern "C" fn PyDescr_NewMethod( typ: *mut PyTypeObject, method: *mut PyMethodDef, ) -> *mut PyObject { - with_vm(|vm| -> PyResult { + with_vm(|vm| { let method = build_method_def(vm, unsafe { &*method }, true)?; - Ok(method.build_method(unsafe { &*typ }, vm).into()) + Ok(method.build_method(unsafe { &*typ }, vm)) }) } @@ -61,9 +157,9 @@ pub unsafe extern "C" fn PyDescr_NewClassMethod( typ: *mut PyTypeObject, method: *mut PyMethodDef, ) -> *mut PyObject { - with_vm(|vm| -> PyResult { + with_vm(|vm| { let method = build_method_def(vm, unsafe { &*method }, true)?; - Ok(method.build_method(unsafe { &*typ }, vm).into()) + Ok(method.build_method(unsafe { &*typ }, vm)) }) } @@ -72,119 +168,7 @@ pub unsafe extern "C" fn PyDescr_NewGetSet( typ: *mut PyTypeObject, getset: *mut PyGetSetDef, ) -> *mut PyObject { - with_vm(|vm| -> PyResult { - let typ = unsafe { &*typ }; - let getset = unsafe { &*getset }; - let name = unsafe { CStr::from_ptr(getset.name) } - .to_str() - .map_err(|_| vm.new_system_error("PyGetSetDef name was not valid UTF-8"))?; - - let descriptor = match (getset.get, getset.set) { - (Some(get), Some(set)) => { - let closure = getset.closure as usize; - vm.ctx.new_static_getset( - name, - typ, - move |obj: PyObjectRef, - vm: &rustpython_vm::VirtualMachine| - -> PyResult { - unsafe { - let closure = closure as *mut c_void; - let ret_ptr = get(obj.as_raw().cast_mut(), closure); - let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { - vm.take_raised_exception().unwrap_or_else(|| { - vm.new_system_error( - "Native function returned NULL, but there was no exception set", - ) - }) - })?; - Ok(PyObjectRef::from_raw(ret_ptr)) - } - }, - move |obj: PyObjectRef, - value: PySetterValue, - vm: &rustpython_vm::VirtualMachine| unsafe { - let closure = closure as *mut c_void; - let value = value.unwrap_or_none(vm); - let result = - set(obj.as_raw().cast_mut(), value.as_raw().cast_mut(), closure); - if result == 0 { - Ok(()) - } else { - Err(vm.take_raised_exception().unwrap_or_else(|| { - vm.new_system_error( - "C setter returned error but did not set an exception", - ) - })) - } - }, - ) - } - (Some(get), None) => { - let closure = getset.closure as usize; - vm.ctx.new_readonly_getset( - name, - typ, - move |obj: PyObjectRef, - vm: &rustpython_vm::VirtualMachine| - -> PyResult { - unsafe { - let closure = closure as *mut c_void; - let ret_ptr = get(obj.as_raw().cast_mut(), closure); - let ret_ptr = NonNull::new(ret_ptr).ok_or_else(|| { - vm.take_raised_exception().unwrap_or_else(|| { - vm.new_system_error( - "Native function returned NULL, but there was no exception set", - ) - }) - })?; - Ok(PyObjectRef::from_raw(ret_ptr)) - } - }, - ) - } - (None, Some(set)) => { - let closure = getset.closure as usize; - vm.ctx.new_static_getset( - name, - typ, - move |_obj: PyObjectRef, - vm: &rustpython_vm::VirtualMachine| - -> PyResult { - Err(vm.new_attribute_error("unreadable attribute")) - }, - move |obj: PyObjectRef, - value: PySetterValue, - vm: &rustpython_vm::VirtualMachine| unsafe { - let closure = closure as *mut c_void; - let value = value.unwrap_or_none(vm); - let result = - set(obj.as_raw().cast_mut(), value.as_raw().cast_mut(), closure); - if result == 0 { - Ok(()) - } else { - Err(vm.take_raised_exception().unwrap_or_else(|| { - vm.new_system_error( - "C setter returned error but did not set an exception", - ) - })) - } - }, - ) - } - (None, None) => vm.ctx.new_readonly_getset( - name, - typ, - move |_obj: PyObjectRef, - vm: &rustpython_vm::VirtualMachine| - -> PyResult { - Err(vm.new_attribute_error("unreadable attribute")) - }, - ), - }; - - Ok(descriptor.into()) - }) + with_vm(|vm| unsafe { &*getset }.build(unsafe { &*typ }, vm)) } #[unsafe(no_mangle)] @@ -195,7 +179,7 @@ pub unsafe extern "C" fn PyDescr_NewMember( const PY_READONLY: c_int = 1; const PY_RELATIVE_OFFSET: c_int = 8; - with_vm(|vm| -> PyResult { + with_vm(|vm| { let typ = unsafe { &*typ }; let member = unsafe { &*member }; let name = unsafe { CStr::from_ptr(member.name) } @@ -249,7 +233,7 @@ pub unsafe extern "C" fn PyDescr_NewMember( }, }; - Ok(descriptor.into_ref(&vm.ctx).into()) + Ok(descriptor.into_ref(&vm.ctx)) }) } From f99a214d47f28e7cda0e8644647d10f848325f40 Mon Sep 17 00:00:00 2001 From: Bas Schoenmaeckers Date: Tue, 14 Jul 2026 15:28:06 +0200 Subject: [PATCH 4/4] Extract memberdef builder --- crates/capi/src/descrobject.rs | 118 +++++++++++++++++---------------- 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/crates/capi/src/descrobject.rs b/crates/capi/src/descrobject.rs index c75b3fd9682..ecc0b53f82a 100644 --- a/crates/capi/src/descrobject.rs +++ b/crates/capi/src/descrobject.rs @@ -133,79 +133,39 @@ pub struct PyMemberDef { pub doc: *const c_char, } -#[unsafe(no_mangle)] -pub unsafe extern "C" fn PyDictProxy_New(mapping: *mut PyObject) -> *mut PyObject { - with_vm(|vm| { - let mapping = unsafe { &*mapping }.to_owned(); - Ok(PyMappingProxy::from_object(mapping, vm)?.into_ref(&vm.ctx)) - }) -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn PyDescr_NewMethod( - typ: *mut PyTypeObject, - method: *mut PyMethodDef, -) -> *mut PyObject { - with_vm(|vm| { - let method = build_method_def(vm, unsafe { &*method }, true)?; - Ok(method.build_method(unsafe { &*typ }, vm)) - }) -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn PyDescr_NewClassMethod( - typ: *mut PyTypeObject, - method: *mut PyMethodDef, -) -> *mut PyObject { - with_vm(|vm| { - let method = build_method_def(vm, unsafe { &*method }, true)?; - Ok(method.build_method(unsafe { &*typ }, vm)) - }) -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn PyDescr_NewGetSet( - typ: *mut PyTypeObject, - getset: *mut PyGetSetDef, -) -> *mut PyObject { - with_vm(|vm| unsafe { &*getset }.build(unsafe { &*typ }, vm)) -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn PyDescr_NewMember( - typ: *mut PyTypeObject, - member: *mut PyMemberDef, -) -> *mut PyObject { +impl PyMemberDef { const PY_READONLY: c_int = 1; const PY_RELATIVE_OFFSET: c_int = 8; - with_vm(|vm| { - let typ = unsafe { &*typ }; - let member = unsafe { &*member }; - let name = unsafe { CStr::from_ptr(member.name) } + pub(crate) fn build( + &self, + ty: &Py, + vm: &VirtualMachine, + ) -> PyResult> { + let name = unsafe { CStr::from_ptr(self.name) } .to_str() .map_err(|_| vm.new_system_error("PyMemberDef name was not valid UTF-8"))?; - let kind = match member.type_code { + let kind = match self.type_code { 6 => MemberKind::Object, 16 => MemberKind::ObjectEx, 14 => MemberKind::Bool, _ => { return Err(vm.new_system_error(format!( "PyDescr_NewMember does not support member type code {}", - member.type_code + self.type_code ))); } }; - if member.offset < 0 { + if self.offset < 0 { return Err(vm.new_system_error("PyDescr_NewMember does not support negative offsets")); } - if member.flags & PY_RELATIVE_OFFSET != 0 { + if self.flags & Self::PY_RELATIVE_OFFSET != 0 { return Err( vm.new_system_error("PyDescr_NewMember does not support Py_RELATIVE_OFFSET") ); } - let doc = NonNull::new(member.doc.cast_mut()) + let doc = NonNull::new(self.doc.cast_mut()) .map(|doc| { unsafe { CStr::from_ptr(doc.as_ptr()) } .to_str() @@ -216,27 +176,73 @@ pub unsafe extern "C" fn PyDescr_NewMember( let descriptor = PyMemberDescriptor { common: PyDescriptorOwned { - typ: typ.to_owned(), + typ: ty.to_owned(), name: vm.ctx.intern_str(name), qualname: PyRwLock::new(None), }, member: DescriptorMemberDef { name: name.to_owned(), kind, - getter: MemberGetter::Offset(member.offset as usize), - setter: if member.flags & PY_READONLY != 0 { + getter: MemberGetter::Offset(self.offset as usize), + setter: if self.flags & Self::PY_READONLY != 0 { MemberSetter::Setter(None) } else { - MemberSetter::Offset(member.offset as usize) + MemberSetter::Offset(self.offset as usize) }, doc, }, }; Ok(descriptor.into_ref(&vm.ctx)) + } +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDictProxy_New(mapping: *mut PyObject) -> *mut PyObject { + with_vm(|vm| { + let mapping = unsafe { &*mapping }.to_owned(); + Ok(PyMappingProxy::from_object(mapping, vm)?.into_ref(&vm.ctx)) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewMethod( + typ: *mut PyTypeObject, + method: *mut PyMethodDef, +) -> *mut PyObject { + with_vm(|vm| { + let method = build_method_def(vm, unsafe { &*method }, true)?; + Ok(method.build_method(unsafe { &*typ }, vm)) + }) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewClassMethod( + typ: *mut PyTypeObject, + method: *mut PyMethodDef, +) -> *mut PyObject { + with_vm(|vm| { + let method = build_method_def(vm, unsafe { &*method }, true)?; + Ok(method.build_method(unsafe { &*typ }, vm)) }) } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewGetSet( + typ: *mut PyTypeObject, + getset: *mut PyGetSetDef, +) -> *mut PyObject { + with_vm(|vm| unsafe { &*getset }.build(unsafe { &*typ }, vm)) +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn PyDescr_NewMember( + typ: *mut PyTypeObject, + member: *mut PyMemberDef, +) -> *mut PyObject { + with_vm(|vm| Ok(unsafe { &*member }.build(unsafe { &*typ }, vm))) +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn PyWrapper_New(descr: *mut PyObject, obj: *mut PyObject) -> *mut PyObject { with_vm(|vm| {