use crate::err::{PyDowncastError, PyResult};
use crate::ffi;
use crate::instance::Py;
use crate::object::PyObject;
use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::typeob::PyTypeInfo;
use crate::types::{PyObjectRef, PyTuple};
pub trait ToPyObject {
fn to_object(&self, py: Python) -> PyObject;
}
pub trait ToBorrowedObject: ToPyObject {
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R
where
F: FnOnce(*mut ffi::PyObject) -> R,
{
let ptr = self.to_object(py).into_ptr();
let result = f(ptr);
unsafe {
ffi::Py_XDECREF(ptr);
}
result
}
}
impl<T> ToBorrowedObject for T where T: ToPyObject {}
impl<T> ToBorrowedObject for T
where
T: ToPyObject + ToPyPointer,
{
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
where
F: FnOnce(*mut ffi::PyObject) -> R,
{
f(self.as_ptr())
}
}
pub trait IntoPyObject {
fn into_object(self, py: Python) -> PyObject;
}
pub trait IntoPyTuple {
fn into_tuple(self, py: Python) -> Py<PyTuple>;
}
pub trait FromPyObject<'source>: Sized {
fn extract(ob: &'source PyObjectRef) -> PyResult<Self>;
}
impl<'a, T: ?Sized> ToPyObject for &'a T
where
T: ToPyObject,
{
#[inline]
fn to_object(&self, py: Python) -> PyObject {
<T as ToPyObject>::to_object(*self, py)
}
}
impl<T> ToPyObject for Option<T>
where
T: ToPyObject,
{
fn to_object(&self, py: Python) -> PyObject {
match *self {
Some(ref val) => val.to_object(py),
None => py.None(),
}
}
}
impl<T> IntoPyObject for Option<T>
where
T: IntoPyObject,
{
fn into_object(self, py: Python) -> PyObject {
match self {
Some(val) => val.into_object(py),
None => py.None(),
}
}
}
impl ToPyObject for () {
fn to_object(&self, py: Python) -> PyObject {
py.None()
}
}
impl IntoPyObject for () {
fn into_object(self, py: Python) -> PyObject {
py.None()
}
}
impl<'a, T> IntoPyObject for &'a T
where
T: ToPyPointer,
{
#[inline]
fn into_object(self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<'a, T> IntoPyObject for &'a mut T
where
T: ToPyPointer,
{
#[inline]
fn into_object(self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<'a, T> FromPyObject<'a> for &'a T
where
T: PyTryFrom,
{
#[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a T> {
Ok(T::try_from(ob)?)
}
}
impl<'a, T> FromPyObject<'a> for &'a mut T
where
T: PyTryFrom,
{
#[inline]
default fn extract(ob: &'a PyObjectRef) -> PyResult<&'a mut T> {
Ok(T::try_from_mut(ob)?)
}
}
impl<'a, T> FromPyObject<'a> for Option<T>
where
T: FromPyObject<'a>,
{
fn extract(obj: &'a PyObjectRef) -> PyResult<Self> {
if obj.as_ptr() == unsafe { ffi::Py_None() } {
Ok(None)
} else {
match T::extract(obj) {
Ok(v) => Ok(Some(v)),
Err(e) => Err(e),
}
}
}
}
pub trait PyTryInto<T>: Sized {
type Error;
fn try_into(&self) -> Result<&T, Self::Error>;
fn try_into_exact(&self) -> Result<&T, Self::Error>;
fn try_into_mut(&self) -> Result<&mut T, Self::Error>;
fn try_into_mut_exact(&self) -> Result<&mut T, Self::Error>;
}
pub trait PyTryFrom: Sized {
fn try_from(value: &PyObjectRef) -> Result<&Self, PyDowncastError>;
fn try_from_exact(value: &PyObjectRef) -> Result<&Self, PyDowncastError>;
fn try_from_mut(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>;
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut Self, PyDowncastError>;
}
impl<U> PyTryInto<U> for PyObjectRef
where
U: PyTryFrom,
{
type Error = PyDowncastError;
fn try_into(&self) -> Result<&U, PyDowncastError> {
U::try_from(self)
}
fn try_into_exact(&self) -> Result<&U, PyDowncastError> {
U::try_from_exact(self)
}
fn try_into_mut(&self) -> Result<&mut U, PyDowncastError> {
U::try_from_mut(self)
}
fn try_into_mut_exact(&self) -> Result<&mut U, PyDowncastError> {
U::try_from_mut_exact(self)
}
}
impl<T> PyTryFrom for T
where
T: PyTypeInfo,
{
fn try_from(value: &PyObjectRef) -> Result<&T, PyDowncastError> {
unsafe {
if T::is_instance(value) {
let ptr = if T::OFFSET == 0 {
value as *const _ as *mut u8 as *mut T
} else {
(value.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T
};
Ok(&*ptr)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_exact(value: &PyObjectRef) -> Result<&T, PyDowncastError> {
unsafe {
if T::is_exact_instance(value) {
let ptr = if T::OFFSET == 0 {
value as *const _ as *mut u8 as *mut T
} else {
(value.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T
};
Ok(&*ptr)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut(value: &PyObjectRef) -> Result<&mut T, PyDowncastError> {
unsafe {
if T::is_instance(value) {
let ptr = if T::OFFSET == 0 {
value as *const _ as *mut u8 as *mut T
} else {
(value.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T
};
Ok(&mut *ptr)
} else {
Err(PyDowncastError)
}
}
}
fn try_from_mut_exact(value: &PyObjectRef) -> Result<&mut T, PyDowncastError> {
unsafe {
if T::is_exact_instance(value) {
let ptr = if T::OFFSET == 0 {
value as *const _ as *mut u8 as *mut T
} else {
(value.as_ptr() as *mut u8).offset(T::OFFSET) as *mut T
};
Ok(&mut *ptr)
} else {
Err(PyDowncastError)
}
}
}
}
pub trait ReturnTypeIntoPyResult {
type Inner;
fn return_type_into_py_result(self) -> PyResult<Self::Inner>;
}
impl<T: IntoPyObject> ReturnTypeIntoPyResult for T {
type Inner = T;
default fn return_type_into_py_result(self) -> PyResult<Self::Inner> {
Ok(self)
}
}
impl<T: IntoPyObject> ReturnTypeIntoPyResult for PyResult<T> {
type Inner = T;
fn return_type_into_py_result(self) -> PyResult<Self::Inner> {
self
}
}