Skip to content

Commit c449564

Browse files
Add more object c-api's (RustPython#8170)
1 parent 83ce1a7 commit c449564

2 files changed

Lines changed: 254 additions & 30 deletions

File tree

crates/capi/src/object.rs

Lines changed: 246 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use core::ptr::NonNull;
55
use rustpython_vm::builtins::{PyStr, PyType, object_generic_set_dict, object_get_dict};
66
use rustpython_vm::bytecode::ComparisonOperator;
77
use rustpython_vm::function::PySetterValue;
8-
use rustpython_vm::{AsObject, Py, PyPayload};
8+
use rustpython_vm::types::{PyComparisonOp, hash_not_implemented};
9+
use rustpython_vm::{AsObject, Py, PyPayload, PyResult, VirtualMachine};
910

1011
pub type PyTypeObject = Py<PyType>;
1112

@@ -100,25 +101,27 @@ pub unsafe extern "C" fn PyType_GetFullyQualifiedName(ptr: *const PyTypeObject)
100101
})
101102
}
102103

104+
#[inline]
105+
fn get_constant(vm: &VirtualMachine, constant_id: c_uint) -> PyResult<&PyObject> {
106+
let ctx = &vm.ctx;
107+
match constant_id {
108+
0 => Ok(ctx.none.as_object()),
109+
1 => Ok(ctx.false_value.as_object()),
110+
2 => Ok(ctx.true_value.as_object()),
111+
3 => Ok(ctx.ellipsis.as_object()),
112+
4 => Ok(ctx.not_implemented.as_object()),
113+
_ => Err(vm.new_system_error("Invalid constant ID passed to Py_GetConstantBorrowed")),
114+
}
115+
}
116+
103117
#[unsafe(no_mangle)]
104118
pub extern "C" fn Py_GetConstantBorrowed(constant_id: c_uint) -> *mut PyObject {
105-
with_vm(|vm| {
106-
let ctx = &vm.ctx;
107-
let constant = match constant_id {
108-
0 => ctx.none.as_object(),
109-
1 => ctx.false_value.as_object(),
110-
2 => ctx.true_value.as_object(),
111-
3 => ctx.ellipsis.as_object(),
112-
4 => ctx.not_implemented.as_object(),
113-
_ => {
114-
return Err(
115-
vm.new_system_error("Invalid constant ID passed to Py_GetConstantBorrowed")
116-
);
117-
}
118-
}
119-
.as_raw();
120-
Ok(constant)
121-
})
119+
with_vm(|vm| get_constant(vm, constant_id).map(PyObject::as_raw))
120+
}
121+
122+
#[unsafe(no_mangle)]
123+
pub extern "C" fn Py_GetConstant(constant_id: c_uint) -> *mut PyObject {
124+
with_vm(|vm| get_constant(vm, constant_id).map(ToOwned::to_owned))
122125
}
123126

124127
#[unsafe(no_mangle)]
@@ -143,12 +146,22 @@ pub unsafe extern "C" fn PyObject_GetAttrString(
143146
let name = unsafe {
144147
CStr::from_ptr(attr_name)
145148
.to_str()
146-
.expect("attribute name must be valid UTF-8")
149+
.map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?
147150
};
148151
obj.get_attr(name, vm)
149152
})
150153
}
151154

155+
#[unsafe(no_mangle)]
156+
pub unsafe extern "C" fn PyObject_ASCII(obj: *mut PyObject) -> *mut PyObject {
157+
with_vm(|vm| unsafe { &*obj }.ascii(vm))
158+
}
159+
160+
#[unsafe(no_mangle)]
161+
pub unsafe extern "C" fn PyObject_Bytes(obj: *mut PyObject) -> *mut PyObject {
162+
with_vm(|vm| unsafe { &*obj }.to_owned().bytes(vm))
163+
}
164+
152165
#[unsafe(no_mangle)]
153166
pub unsafe extern "C" fn PyObject_GetOptionalAttr(
154167
obj: *mut PyObject,
@@ -172,6 +185,31 @@ pub unsafe extern "C" fn PyObject_GetOptionalAttr(
172185
})
173186
}
174187

188+
#[unsafe(no_mangle)]
189+
pub unsafe extern "C" fn PyObject_GetOptionalAttrString(
190+
obj: *mut PyObject,
191+
attr_name: *const c_char,
192+
result: *mut *mut PyObject,
193+
) -> c_int {
194+
with_vm(|vm| {
195+
unsafe {
196+
*result = core::ptr::null_mut();
197+
}
198+
let obj = unsafe { &*obj };
199+
let name = unsafe { CStr::from_ptr(attr_name) }
200+
.to_str()
201+
.map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?;
202+
if let Some(attr) = vm.get_attribute_opt(obj.to_owned(), name)? {
203+
unsafe {
204+
*result = attr.into_raw().as_ptr();
205+
}
206+
Ok(true)
207+
} else {
208+
Ok(false)
209+
}
210+
})
211+
}
212+
175213
#[unsafe(no_mangle)]
176214
pub unsafe extern "C" fn PyObject_SetAttrString(
177215
obj: *mut PyObject,
@@ -182,7 +220,7 @@ pub unsafe extern "C" fn PyObject_SetAttrString(
182220
let obj = unsafe { &*obj };
183221
let name = unsafe { CStr::from_ptr(attr_name) }
184222
.to_str()
185-
.expect("attribute name must be valid UTF-8");
223+
.map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?;
186224
let value = unsafe { &*value }.to_owned();
187225
obj.set_attr(name, value, vm)
188226
})
@@ -202,6 +240,46 @@ pub unsafe extern "C" fn PyObject_SetAttr(
202240
})
203241
}
204242

243+
#[unsafe(no_mangle)]
244+
pub unsafe extern "C" fn PyObject_DelAttr(obj: *mut PyObject, name: *mut PyObject) -> c_int {
245+
with_vm(|vm| {
246+
let obj = unsafe { &*obj };
247+
let name = unsafe { &*name }.try_downcast_ref::<PyStr>(vm)?;
248+
obj.del_attr(name, vm)
249+
})
250+
}
251+
252+
#[unsafe(no_mangle)]
253+
pub unsafe extern "C" fn PyObject_DelAttrString(
254+
obj: *mut PyObject,
255+
attr_name: *const c_char,
256+
) -> c_int {
257+
with_vm(|vm| {
258+
let obj = unsafe { &*obj };
259+
let name = unsafe { CStr::from_ptr(attr_name) }
260+
.to_str()
261+
.map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?;
262+
obj.del_attr(name, vm)
263+
})
264+
}
265+
266+
#[unsafe(no_mangle)]
267+
pub unsafe extern "C" fn PyObject_GenericSetAttr(
268+
obj: *mut PyObject,
269+
name: *mut PyObject,
270+
value: *mut PyObject,
271+
) -> c_int {
272+
with_vm(|vm| {
273+
let obj = unsafe { &*obj };
274+
let name = unsafe { &*name }.try_downcast_ref::<PyStr>(vm)?;
275+
let value = match NonNull::new(value) {
276+
Some(value) => PySetterValue::Assign(unsafe { value.as_ref() }.to_owned()),
277+
None => PySetterValue::Delete,
278+
};
279+
obj.generic_setattr(name, value, vm)
280+
})
281+
}
282+
205283
#[unsafe(no_mangle)]
206284
pub unsafe extern "C" fn PyObject_HasAttrWithError(
207285
obj: *mut PyObject,
@@ -214,6 +292,63 @@ pub unsafe extern "C" fn PyObject_HasAttrWithError(
214292
})
215293
}
216294

295+
#[unsafe(no_mangle)]
296+
pub unsafe extern "C" fn PyObject_HasAttr(obj: *mut PyObject, attr_name: *mut PyObject) -> c_int {
297+
with_vm(|vm| {
298+
let obj = unsafe { &*obj };
299+
let name = match unsafe { &*attr_name }.try_downcast_ref::<PyStr>(vm) {
300+
Ok(name) => name,
301+
Err(err) => {
302+
vm.run_unraisable(err, None, obj.to_owned());
303+
return false;
304+
}
305+
};
306+
307+
match obj.has_attr(name, vm) {
308+
Ok(has_attr) => has_attr,
309+
Err(err) => {
310+
vm.run_unraisable(err, None, obj.to_owned());
311+
false
312+
}
313+
}
314+
})
315+
}
316+
317+
#[unsafe(no_mangle)]
318+
pub unsafe extern "C" fn PyObject_HasAttrString(
319+
obj: *mut PyObject,
320+
attr_name: *const c_char,
321+
) -> c_int {
322+
with_vm(|vm| {
323+
let obj = unsafe { &*obj };
324+
let Ok(name) = unsafe { CStr::from_ptr(attr_name) }.to_str() else {
325+
return false;
326+
};
327+
328+
match obj.has_attr(name, vm) {
329+
Ok(has_attr) => has_attr,
330+
Err(err) => {
331+
vm.run_unraisable(err, None, obj.to_owned());
332+
false
333+
}
334+
}
335+
})
336+
}
337+
338+
#[unsafe(no_mangle)]
339+
pub unsafe extern "C" fn PyObject_HasAttrStringWithError(
340+
obj: *mut PyObject,
341+
attr_name: *const c_char,
342+
) -> c_int {
343+
with_vm(|vm| {
344+
let obj = unsafe { &*obj };
345+
let name = unsafe { CStr::from_ptr(attr_name) }
346+
.to_str()
347+
.map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?;
348+
obj.has_attr(name, vm)
349+
})
350+
}
351+
217352
#[unsafe(no_mangle)]
218353
pub unsafe extern "C" fn PyObject_GenericGetAttr(
219354
obj: *mut PyObject,
@@ -248,26 +383,44 @@ pub extern "C" fn PyObject_Str(obj: *mut PyObject) -> *mut PyObject {
248383
})
249384
}
250385

386+
#[inline]
387+
fn parse_richcompare_op(vm: &VirtualMachine, op: c_int) -> PyResult<PyComparisonOp> {
388+
match op {
389+
0 => Ok(ComparisonOperator::Less),
390+
1 => Ok(ComparisonOperator::LessOrEqual),
391+
2 => Ok(ComparisonOperator::Equal),
392+
3 => Ok(ComparisonOperator::NotEqual),
393+
4 => Ok(ComparisonOperator::Greater),
394+
5 => Ok(ComparisonOperator::GreaterOrEqual),
395+
_ => Err(vm.new_system_error("invalid comparison operator")),
396+
}
397+
.map(Into::into)
398+
}
399+
251400
#[unsafe(no_mangle)]
252401
pub unsafe extern "C" fn PyObject_RichCompare(
253402
left: *mut PyObject,
254403
right: *mut PyObject,
255404
op: c_int,
256405
) -> *mut PyObject {
257406
with_vm(|vm| {
258-
let op = match op {
259-
0 => ComparisonOperator::Less,
260-
1 => ComparisonOperator::LessOrEqual,
261-
2 => ComparisonOperator::Equal,
262-
3 => ComparisonOperator::NotEqual,
263-
4 => ComparisonOperator::Greater,
264-
5 => ComparisonOperator::GreaterOrEqual,
265-
_ => return Err(vm.new_system_error("invalid comparison operator")),
266-
};
267407
let left = unsafe { &*left };
268408
let right = unsafe { &*right };
269409
left.to_owned()
270-
.rich_compare(right.to_owned(), op.into(), vm)
410+
.rich_compare(right.to_owned(), parse_richcompare_op(vm, op)?, vm)
411+
})
412+
}
413+
414+
#[unsafe(no_mangle)]
415+
pub unsafe extern "C" fn PyObject_RichCompareBool(
416+
left: *mut PyObject,
417+
right: *mut PyObject,
418+
op: c_int,
419+
) -> c_int {
420+
with_vm(|vm| {
421+
let left = unsafe { &*left };
422+
let right = unsafe { &*right };
423+
left.rich_compare_bool(right, parse_richcompare_op(vm, op)?, vm)
271424
})
272425
}
273426

@@ -298,6 +451,69 @@ pub unsafe extern "C" fn PyObject_IsTrue(obj: *mut PyObject) -> c_int {
298451
})
299452
}
300453

454+
#[unsafe(no_mangle)]
455+
pub unsafe extern "C" fn PyObject_Not(obj: *mut PyObject) -> c_int {
456+
with_vm(|vm| {
457+
let obj = unsafe { &*obj };
458+
obj.to_owned().not(vm)
459+
})
460+
}
461+
462+
#[unsafe(no_mangle)]
463+
pub unsafe extern "C" fn PyObject_Hash(obj: *mut PyObject) -> isize {
464+
with_vm(|vm| {
465+
let obj = unsafe { &*obj };
466+
obj.hash(vm).map(|hash| hash as isize)
467+
})
468+
}
469+
470+
#[unsafe(no_mangle)]
471+
pub unsafe extern "C" fn PyObject_HashNotImplemented(obj: *mut PyObject) -> isize {
472+
with_vm(|vm| {
473+
let obj = unsafe { &*obj };
474+
hash_not_implemented(obj, vm).map(|hash| hash as isize)
475+
})
476+
}
477+
478+
#[unsafe(no_mangle)]
479+
pub unsafe extern "C" fn PyObject_SelfIter(obj: *mut PyObject) -> *mut PyObject {
480+
with_vm(|_vm| unsafe { (&*obj).to_owned() })
481+
}
482+
483+
#[unsafe(no_mangle)]
484+
pub unsafe extern "C" fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int {
485+
(x == y) as c_int
486+
}
487+
488+
#[unsafe(no_mangle)]
489+
pub unsafe extern "C" fn Py_IsNone(x: *mut PyObject) -> c_int {
490+
with_vm(|vm| vm.is_none(unsafe { &*x }))
491+
}
492+
493+
#[unsafe(no_mangle)]
494+
pub unsafe extern "C" fn Py_ReprEnter(obj: *mut PyObject) -> c_int {
495+
with_vm(|vm| {
496+
let obj = unsafe { &*obj };
497+
let id = obj.get_id();
498+
let mut guards = vm.repr_guards.borrow_mut();
499+
if guards.contains(&id) {
500+
true
501+
} else {
502+
guards.insert(id);
503+
false
504+
}
505+
})
506+
}
507+
508+
#[unsafe(no_mangle)]
509+
pub unsafe extern "C" fn Py_ReprLeave(obj: *mut PyObject) {
510+
with_vm(|vm| {
511+
vm.repr_guards
512+
.borrow_mut()
513+
.remove(&unsafe { &*obj }.get_id());
514+
})
515+
}
516+
301517
#[unsafe(no_mangle)]
302518
pub unsafe extern "C" fn PyObject_GenericGetDict(
303519
obj: *mut PyObject,

crates/capi/src/util.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ impl FfiResult<isize> for usize {
101101
}
102102
}
103103

104+
impl FfiResult for isize {
105+
const ERR_VALUE: Self = -1;
106+
107+
fn into_output(self, _vm: &VirtualMachine) -> Self {
108+
self
109+
}
110+
}
111+
104112
impl FfiResult for c_long {
105113
const ERR_VALUE: Self = -1;
106114

0 commit comments

Comments
 (0)