Skip to content

Commit 0eccf4b

Browse files
Add more object c-api's
1 parent c876709 commit 0eccf4b

2 files changed

Lines changed: 255 additions & 30 deletions

File tree

crates/capi/src/object.rs

Lines changed: 247 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,64 @@ 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+
vm.run_unraisable(vm.new_value_error("attribute name must be valid UTF-8"), None, obj.to_owned());
326+
return false;
327+
};
328+
329+
match obj.has_attr(name, vm) {
330+
Ok(has_attr) => has_attr,
331+
Err(err) => {
332+
vm.run_unraisable(err, None, obj.to_owned());
333+
false
334+
}
335+
}
336+
})
337+
}
338+
339+
#[unsafe(no_mangle)]
340+
pub unsafe extern "C" fn PyObject_HasAttrStringWithError(
341+
obj: *mut PyObject,
342+
attr_name: *const c_char,
343+
) -> c_int {
344+
with_vm(|vm| {
345+
let obj = unsafe { &*obj };
346+
let name = unsafe { CStr::from_ptr(attr_name) }
347+
.to_str()
348+
.map_err(|_| vm.new_value_error("attribute name must be valid UTF-8"))?;
349+
obj.has_attr(name, vm)
350+
})
351+
}
352+
217353
#[unsafe(no_mangle)]
218354
pub unsafe extern "C" fn PyObject_GenericGetAttr(
219355
obj: *mut PyObject,
@@ -248,26 +384,44 @@ pub extern "C" fn PyObject_Str(obj: *mut PyObject) -> *mut PyObject {
248384
})
249385
}
250386

387+
#[inline]
388+
fn parse_richcompare_op(vm: &VirtualMachine, op: c_int) -> PyResult<PyComparisonOp> {
389+
match op {
390+
0 => Ok(ComparisonOperator::Less),
391+
1 => Ok(ComparisonOperator::LessOrEqual),
392+
2 => Ok(ComparisonOperator::Equal),
393+
3 => Ok(ComparisonOperator::NotEqual),
394+
4 => Ok(ComparisonOperator::Greater),
395+
5 => Ok(ComparisonOperator::GreaterOrEqual),
396+
_ => Err(vm.new_system_error("invalid comparison operator")),
397+
}
398+
.map(Into::into)
399+
}
400+
251401
#[unsafe(no_mangle)]
252402
pub unsafe extern "C" fn PyObject_RichCompare(
253403
left: *mut PyObject,
254404
right: *mut PyObject,
255405
op: c_int,
256406
) -> *mut PyObject {
257407
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-
};
267408
let left = unsafe { &*left };
268409
let right = unsafe { &*right };
269410
left.to_owned()
270-
.rich_compare(right.to_owned(), op.into(), vm)
411+
.rich_compare(right.to_owned(), parse_richcompare_op(vm, op)?, vm)
412+
})
413+
}
414+
415+
#[unsafe(no_mangle)]
416+
pub unsafe extern "C" fn PyObject_RichCompareBool(
417+
left: *mut PyObject,
418+
right: *mut PyObject,
419+
op: c_int,
420+
) -> c_int {
421+
with_vm(|vm| {
422+
let left = unsafe { &*left };
423+
let right = unsafe { &*right };
424+
left.rich_compare_bool(right, parse_richcompare_op(vm, op)?, vm)
271425
})
272426
}
273427

@@ -298,6 +452,69 @@ pub unsafe extern "C" fn PyObject_IsTrue(obj: *mut PyObject) -> c_int {
298452
})
299453
}
300454

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