convert PyString object
This commit is contained in:
parent
ce53e8230b
commit
bc0f9b014f
|
@ -55,6 +55,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
let extra = if let Some(token) = token {
|
||||
Some(quote! {
|
||||
impl _pyo3::PyObjectWithToken for #cls {
|
||||
#[inline]
|
||||
fn token<'p>(&'p self) -> _pyo3::Python<'p> {
|
||||
self.#token.token()
|
||||
}
|
||||
|
@ -100,29 +101,39 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
let py = _pyo3::PyObjectWithToken::token(self);
|
||||
let ptr = <#cls as _pyo3::ToPyPointer>::as_ptr(self);
|
||||
let repr = unsafe {
|
||||
_pyo3::PyString::downcast_from_ptr(
|
||||
py, _pyo3::ffi::PyObject_Repr(ptr)).map_err(|_| std::fmt::Error)?
|
||||
unsafe {
|
||||
let repr = PyObject::from_borrowed_ptr(
|
||||
py, _pyo3::ffi::PyObject_Repr(ptr));
|
||||
|
||||
let result = {
|
||||
let s = _pyo3::PyString::downcast_from(py, &repr);
|
||||
let s = try!(s.map_err(|_| std::fmt::Error));
|
||||
f.write_str(&s.to_string_lossy())
|
||||
};
|
||||
let result = f.write_str(&repr.to_string_lossy(py));
|
||||
py.release(repr);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for #cls {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
let py = _pyo3::PyObjectWithToken::token(self);
|
||||
let ptr = <#cls as _pyo3::ToPyPointer>::as_ptr(self);
|
||||
let str_obj = unsafe {
|
||||
_pyo3::PyString::downcast_from_ptr(
|
||||
py, _pyo3::ffi::PyObject_Str(ptr)).map_err(|_| std::fmt::Error)?
|
||||
unsafe {
|
||||
let repr = PyObject::from_borrowed_ptr(
|
||||
py, _pyo3::ffi::PyObject_Str(ptr));
|
||||
|
||||
let result = {
|
||||
let s = _pyo3::PyString::downcast_from(py, &repr);
|
||||
let s = try!(s.map_err(|_| std::fmt::Error));
|
||||
f.write_str(&s.to_string_lossy())
|
||||
};
|
||||
let result = f.write_str(&str_obj.to_string_lossy(py));
|
||||
py.release(str_obj);
|
||||
py.release(repr);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -184,6 +195,12 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
static mut TYPE_OBJECT: _pyo3::ffi::PyTypeObject = _pyo3::ffi::PyTypeObject_INIT;
|
||||
unsafe { &mut TYPE_OBJECT }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_instance(ptr: *mut ffi::PyObject) -> bool {
|
||||
unsafe {ffi::PyObject_TypeCheck(
|
||||
ptr, <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0}
|
||||
}
|
||||
}
|
||||
|
||||
impl _pyo3::typeob::PyTypeObject for #cls {
|
||||
|
|
|
@ -82,7 +82,7 @@ pub fn parse_args<'p>(py: Python<'p>,
|
|||
if !accept_kwargs && used_keywords != nkeywords {
|
||||
// check for extraneous keyword arguments
|
||||
for (key, _value) in kwargs.unwrap().items(py) {
|
||||
let key = try!(try!(key.cast_as::<PyString>(py)).to_string(py));
|
||||
let key = try!(try!(key.cast_as::<PyString>(py)).to_string());
|
||||
if !params.iter().any(|p| p.name == key) {
|
||||
return Err(err::PyErr::new::<exc::TypeError, _>(
|
||||
py,
|
||||
|
|
|
@ -27,6 +27,12 @@ pub unsafe fn PyString_Check(op : *mut PyObject) -> c_int {
|
|||
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyBaseString_Check(op : *mut PyObject) -> c_int {
|
||||
PyType_FastSubclass(
|
||||
Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS | Py_TPFLAGS_UNICODE_SUBCLASS)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn PyString_CheckExact(op : *mut PyObject) -> c_int {
|
||||
let u : *mut PyTypeObject = &mut PyString_Type;
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::fmt;
|
|||
|
||||
use pointers::PyPtr;
|
||||
use python::Python;
|
||||
use token::InstancePtr;
|
||||
use objectprotocol::ObjectProtocol;
|
||||
|
||||
impl fmt::Debug for PyPtr {
|
||||
|
@ -14,7 +15,7 @@ impl fmt::Debug for PyPtr {
|
|||
// TODO: we shouldn't use fmt::Error when repr() fails
|
||||
let r = self.as_object(py);
|
||||
let repr_obj = try!(r.repr(py).map_err(|_| fmt::Error));
|
||||
let result = f.write_str(&repr_obj.to_string_lossy(py));
|
||||
let result = f.write_str(&repr_obj.as_ref(py).to_string_lossy());
|
||||
py.release(repr_obj);
|
||||
result
|
||||
}
|
||||
|
@ -28,7 +29,7 @@ impl fmt::Display for PyPtr {
|
|||
// TODO: we shouldn't use fmt::Error when repr() fails
|
||||
let r = self.as_object(py);
|
||||
let str_obj = try!(r.str(py).map_err(|_| fmt::Error));
|
||||
let result = f.write_str(&str_obj.to_string_lossy(py));
|
||||
let result = f.write_str(&str_obj.as_ref(py).to_string_lossy());
|
||||
py.release(str_obj);
|
||||
result
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use err::{PyErr, PyResult, self};
|
|||
use python::{Python, PyDowncastInto, ToPyPointer};
|
||||
use objects::{PyObject, PyDict, PyString, PyIterator, PyType};
|
||||
use conversion::{ToPyObject, IntoPyTuple};
|
||||
use token::Py;
|
||||
|
||||
|
||||
pub trait ObjectProtocol {
|
||||
|
@ -62,11 +63,11 @@ pub trait ObjectProtocol {
|
|||
|
||||
/// Compute the string representation of self.
|
||||
/// This is equivalent to the Python expression 'repr(self)'.
|
||||
fn repr(&self, py: Python) -> PyResult<PyString>;
|
||||
fn repr(&self, py: Python) -> PyResult<Py<PyString>>;
|
||||
|
||||
/// Compute the string representation of self.
|
||||
/// This is equivalent to the Python expression 'str(self)'.
|
||||
fn str(&self, py: Python) -> PyResult<PyString>;
|
||||
fn str(&self, py: Python) -> PyResult<Py<PyString>>;
|
||||
|
||||
/// Determines whether this object is callable.
|
||||
fn is_callable(&self, py: Python) -> bool;
|
||||
|
@ -239,16 +240,16 @@ impl<T> ObjectProtocol for T where T: ToPyPointer {
|
|||
/// Compute the string representation of self.
|
||||
/// This is equivalent to the Python expression 'repr(self)'.
|
||||
#[inline]
|
||||
fn repr(&self, py: Python) -> PyResult<PyString> {
|
||||
Ok(PyString::downcast_from_ptr(
|
||||
fn repr(&self, py: Python) -> PyResult<Py<PyString>> {
|
||||
Ok(Py::downcast_from_ptr(
|
||||
py, unsafe{ffi::PyObject_Repr(self.as_ptr())})?)
|
||||
}
|
||||
|
||||
/// Compute the string representation of self.
|
||||
/// This is equivalent to the Python expression 'str(self)'.
|
||||
#[inline]
|
||||
fn str(&self, py: Python) -> PyResult<PyString> {
|
||||
Ok(PyString::downcast_from_ptr(
|
||||
fn str(&self, py: Python) -> PyResult<Py<PyString>> {
|
||||
Ok(Py::downcast_from_ptr(
|
||||
py, unsafe{ffi::PyObject_Str(self.as_ptr())})?)
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,12 @@ macro_rules! pyobject_nativetype(
|
|||
fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
|
||||
unsafe { &mut $crate::ffi::$typeobject }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_instance(ptr: *mut $crate::ffi::PyObject) -> bool {
|
||||
unsafe {$crate::ffi::PyObject_TypeCheck(
|
||||
ptr, <$name as $crate::typeob::PyTypeInfo>::type_object()) != 0}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::typeob::PyTypeObject for $name {
|
||||
|
@ -136,20 +142,26 @@ macro_rules! pyobject_nativetype(
|
|||
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
|
||||
-> Result<(), $crate::std::fmt::Error>
|
||||
{
|
||||
use $crate::python::PyDowncastInto;
|
||||
use $crate::python::PyDowncastFrom;
|
||||
|
||||
let gil = $crate::Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let s = unsafe { $crate::PyString::downcast_from_ptr(
|
||||
unsafe {
|
||||
let repr_ob = PyObject::from_borrowed_ptr(
|
||||
py, $crate::ffi::PyObject_Repr(
|
||||
$crate::python::ToPyPointer::as_ptr(self))) };
|
||||
let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
|
||||
let result = f.write_str(&repr_obj.to_string_lossy(py));
|
||||
py.release(repr_obj);
|
||||
$crate::python::ToPyPointer::as_ptr(self)));
|
||||
|
||||
let result = {
|
||||
let s = $crate::PyString::downcast_from(py, &repr_ob);
|
||||
let s = try!(s.map_err(|_| $crate::std::fmt::Error));
|
||||
f.write_str(&s.to_string_lossy())
|
||||
};
|
||||
py.release(repr_ob);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
|
||||
|
@ -157,17 +169,23 @@ macro_rules! pyobject_nativetype(
|
|||
{
|
||||
let gil = $crate::Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
use $crate::python::PyDowncastInto;
|
||||
use $crate::python::PyDowncastFrom;
|
||||
|
||||
let s = unsafe { $crate::PyString::downcast_from_ptr(
|
||||
unsafe {
|
||||
let str_ob = PyObject::from_borrowed_ptr(
|
||||
py, $crate::ffi::PyObject_Str(
|
||||
$crate::python::ToPyPointer::as_ptr(self))) };
|
||||
let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
|
||||
let result = f.write_str(&str_obj.to_string_lossy(py));
|
||||
py.release(str_obj);
|
||||
$crate::python::ToPyPointer::as_ptr(self)));
|
||||
|
||||
let result = {
|
||||
let s = $crate::PyString::downcast_from(py, &str_ob);
|
||||
let s = try!(s.map_err(|_| $crate::std::fmt::Error));
|
||||
f.write_str(&s.to_string_lossy())
|
||||
};
|
||||
py.release(str_ob);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
|
@ -261,6 +279,172 @@ macro_rules! pyobject_downcast(
|
|||
);
|
||||
);
|
||||
|
||||
macro_rules! pyobject_nativetype2(
|
||||
($name: ident, $typeobject: ident, $checkfunction: ident) => {
|
||||
impl $crate::token::PyNativeType for $name {}
|
||||
|
||||
impl $crate::std::convert::AsRef<PyObject> for $name {
|
||||
fn as_ref(&self) -> &$crate::PyObject {
|
||||
unsafe{$crate::std::mem::transmute(self)}
|
||||
}
|
||||
}
|
||||
impl $crate::PyObjectWithToken for $name {
|
||||
fn token<'p>(&'p self) -> $crate::Python<'p> {
|
||||
unsafe { $crate::Python::assume_gil_acquired() }
|
||||
}
|
||||
}
|
||||
//impl $crate::PyClone for $name {
|
||||
// fn clone_ref(&self, _py: $crate::Python) -> Self {
|
||||
// $name(unsafe{$crate::PyPtr::from_borrowed_ptr(self.as_ptr())})
|
||||
// }
|
||||
//}
|
||||
impl $crate::python::ToPyPointer for $name {
|
||||
/// Gets the underlying FFI pointer, returns a borrowed pointer.
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
}
|
||||
impl<'a> $crate::python::ToPyPointer for &'a $name {
|
||||
/// Gets the underlying FFI pointer, returns a borrowed pointer.
|
||||
#[inline]
|
||||
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::python::PyDowncastFrom for $name
|
||||
{
|
||||
fn downcast_from<'a, 'p>(py: $crate::Python<'p>, ob: &'a $crate::PyObject)
|
||||
-> Result<&'a $name, $crate::PyDowncastError<'p>>
|
||||
{
|
||||
use $crate::ToPyPointer;
|
||||
|
||||
unsafe {
|
||||
if $crate::ffi::$checkfunction(ob.as_ptr()) > 0 {
|
||||
Ok($crate::std::mem::transmute(ob))
|
||||
} else {
|
||||
Err($crate::PyDowncastError(py, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $crate::FromPyObject<'a> for &'a $name
|
||||
{
|
||||
/// Extracts `Self` from the source `PyObject`.
|
||||
fn extract(py: Python, ob: &'a $crate::PyObject) -> $crate::PyResult<Self>
|
||||
{
|
||||
unsafe {
|
||||
if ffi::$checkfunction(ob.as_ptr()) != 0 {
|
||||
Ok($crate::std::mem::transmute(ob))
|
||||
} else {
|
||||
Err($crate::PyDowncastError(py, None).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::typeob::PyTypeInfo for $name {
|
||||
type Type = ();
|
||||
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
$crate::std::mem::size_of::<ffi::PyObject>()
|
||||
}
|
||||
#[inline]
|
||||
fn offset() -> isize {
|
||||
0
|
||||
}
|
||||
#[inline]
|
||||
fn type_name() -> &'static str {
|
||||
stringify!($name)
|
||||
}
|
||||
#[inline]
|
||||
fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
|
||||
unsafe { &mut $crate::ffi::$typeobject }
|
||||
}
|
||||
#[inline]
|
||||
fn is_instance(ptr: *mut $crate::ffi::PyObject) -> bool {
|
||||
unsafe { $crate::ffi::$checkfunction(ptr) > 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::typeob::PyTypeObject for $name {
|
||||
#[inline(always)]
|
||||
fn init_type(_py: Python) {}
|
||||
|
||||
#[inline]
|
||||
fn type_object(py: $crate::Python) -> $crate::PyType {
|
||||
unsafe { $crate::PyType::from_type_ptr(py, &mut $crate::ffi::$typeobject) }
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::ToPyObject for $name
|
||||
{
|
||||
#[inline]
|
||||
fn to_object<'p>(&self, py: $crate::Python<'p>) -> $crate::PyObject {
|
||||
$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R
|
||||
{
|
||||
f(self.0.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::std::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
|
||||
-> Result<(), $crate::std::fmt::Error>
|
||||
{
|
||||
use $crate::python::PyDowncastFrom;
|
||||
|
||||
let py = self.token();
|
||||
|
||||
unsafe {
|
||||
let repr_ob = PyObject::from_borrowed_ptr(
|
||||
py, $crate::ffi::PyObject_Repr(
|
||||
$crate::python::ToPyPointer::as_ptr(self)));
|
||||
|
||||
let result = {
|
||||
let s = $crate::PyString::downcast_from(py, &repr_ob);
|
||||
let s = try!(s.map_err(|_| $crate::std::fmt::Error));
|
||||
f.write_str(&s.to_string_lossy())
|
||||
};
|
||||
py.release(repr_ob);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
|
||||
-> Result<(), $crate::std::fmt::Error>
|
||||
{
|
||||
use $crate::python::PyDowncastFrom;
|
||||
let py = self.token();
|
||||
|
||||
unsafe {
|
||||
let str_ob = PyObject::from_borrowed_ptr(
|
||||
py, $crate::ffi::PyObject_Str(
|
||||
$crate::python::ToPyPointer::as_ptr(self)));
|
||||
|
||||
let result = {
|
||||
let s = $crate::PyString::downcast_from(py, &str_ob);
|
||||
let s = try!(s.map_err(|_| $crate::std::fmt::Error));
|
||||
f.write_str(&s.to_string_lossy())
|
||||
};
|
||||
py.release(str_ob);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
|
||||
macro_rules! pyobject_convert(
|
||||
($name: ident) => (
|
||||
impl $crate::std::convert::From<$name> for $crate::PyObject {
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::borrow::Cow;
|
|||
use std::os::raw::c_char;
|
||||
|
||||
use ffi;
|
||||
use token::{Py, PyObjectWithToken};
|
||||
use pointers::PyPtr;
|
||||
use python::{ToPyPointer, Python};
|
||||
use err::{PyResult, PyErr};
|
||||
|
@ -16,8 +17,7 @@ use super::{PyObject, PyStringData};
|
|||
/// Represents a Python string.
|
||||
pub struct PyString(PyPtr);
|
||||
|
||||
pyobject_convert!(PyString);
|
||||
pyobject_nativetype!(PyString, PyUnicode_Type, PyUnicode_Check);
|
||||
pyobject_nativetype2!(PyString, PyUnicode_Type, PyUnicode_Check);
|
||||
|
||||
/// Represents a Python unicode string.
|
||||
/// Corresponds to `unicode` in Python 2, and `str` in Python 3.
|
||||
|
@ -25,45 +25,41 @@ pub use PyString as PyUnicode;
|
|||
|
||||
/// Represents a Python byte string.
|
||||
pub struct PyBytes(PyPtr);
|
||||
|
||||
pyobject_convert!(PyBytes);
|
||||
pyobject_nativetype!(PyBytes, PyBytes_Type, PyBytes_Check);
|
||||
pyobject_nativetype2!(PyBytes, PyBytes_Type, PyBytes_Check);
|
||||
|
||||
impl PyString {
|
||||
|
||||
/// Creates a new Python string object.
|
||||
///
|
||||
/// Panics if out of memory.
|
||||
pub fn new(_py: Python, s: &str) -> PyString {
|
||||
pub fn new(_py: Python, s: &str) -> Py<PyString> {
|
||||
let ptr = s.as_ptr() as *const c_char;
|
||||
let len = s.len() as ffi::Py_ssize_t;
|
||||
unsafe {
|
||||
PyString(PyPtr::from_owned_ptr_or_panic(
|
||||
ffi::PyUnicode_FromStringAndSize(ptr, len)))
|
||||
Py::from_owned_ptr_or_panic(ffi::PyUnicode_FromStringAndSize(ptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_object(py: Python, src: &PyObject, encoding: &str, errors: &str)
|
||||
-> PyResult<PyString> {
|
||||
-> PyResult<Py<PyString>> {
|
||||
unsafe {
|
||||
Ok(PyString(
|
||||
PyPtr::from_owned_ptr_or_err(
|
||||
Ok(Py::from_owned_ptr_or_err(
|
||||
py, ffi::PyUnicode_FromEncodedObject(
|
||||
src.as_ptr(),
|
||||
encoding.as_ptr() as *const i8,
|
||||
errors.as_ptr() as *const i8))?))
|
||||
errors.as_ptr() as *const i8))?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the python string data in its underlying representation.
|
||||
pub fn data(&self, py: Python) -> PyStringData {
|
||||
pub fn data(&self) -> PyStringData {
|
||||
// TODO: return the original representation instead
|
||||
// of forcing the UTF-8 representation to be created.
|
||||
unsafe {
|
||||
let mut size : ffi::Py_ssize_t = mem::uninitialized();
|
||||
let data = ffi::PyUnicode_AsUTF8AndSize(self.0.as_ptr(), &mut size) as *const u8;
|
||||
if data.is_null() {
|
||||
PyErr::fetch(py).print(py);
|
||||
PyErr::fetch(self.token()).print(self.token());
|
||||
panic!("PyUnicode_AsUTF8AndSize failed");
|
||||
}
|
||||
PyStringData::Utf8(std::slice::from_raw_parts(data, size as usize))
|
||||
|
@ -74,16 +70,16 @@ impl PyString {
|
|||
///
|
||||
/// Returns a `UnicodeDecodeError` if the input is not valid unicode
|
||||
/// (containing unpaired surrogates).
|
||||
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
|
||||
self.data(py).to_string(py)
|
||||
pub fn to_string(&self) -> PyResult<Cow<str>> {
|
||||
self.data().to_string(self.token())
|
||||
}
|
||||
|
||||
/// Convert the `PyString` into a Rust string.
|
||||
///
|
||||
/// Unpaired surrogates invalid UTF-8 sequences are
|
||||
/// replaced with U+FFFD REPLACEMENT CHARACTER.
|
||||
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
|
||||
self.data(py).to_string_lossy()
|
||||
pub fn to_string_lossy(&self) -> Cow<str> {
|
||||
self.data().to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,12 +88,11 @@ impl PyBytes {
|
|||
/// The byte string is initialized by copying the data from the `&[u8]`.
|
||||
///
|
||||
/// Panics if out of memory.
|
||||
pub fn new(_py: Python, s: &[u8]) -> PyBytes {
|
||||
pub fn new(_py: Python, s: &[u8]) -> Py<PyBytes> {
|
||||
let ptr = s.as_ptr() as *const c_char;
|
||||
let len = s.len() as ffi::Py_ssize_t;
|
||||
unsafe {
|
||||
PyBytes(PyPtr::from_owned_ptr_or_panic(
|
||||
ffi::PyBytes_FromStringAndSize(ptr, len)))
|
||||
Py::from_owned_ptr_or_panic(ffi::PyBytes_FromStringAndSize(ptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,29 +9,27 @@ use std::ascii::AsciiExt;
|
|||
use std::os::raw::c_char;
|
||||
|
||||
use ffi;
|
||||
use conversion::FromPyObject;
|
||||
use err::{PyResult, PyDowncastError};
|
||||
use err::PyResult;
|
||||
use pointers::PyPtr;
|
||||
use python::{Python, ToPyPointer, IntoPyPointer, PyDowncastInto, PyDowncastFrom};
|
||||
use token::{Py, PyObjectWithToken};
|
||||
use python::{Python, ToPyPointer};
|
||||
use super::{PyObject, PyStringData};
|
||||
|
||||
/// Represents a Python string.
|
||||
pub struct PyString(PyPtr);
|
||||
|
||||
pyobject_convert!(PyString);
|
||||
pyobject_nativetype!(PyString, PyBaseString_Type);
|
||||
pyobject_nativetype2!(PyString, PyBaseString_Type, PyBaseString_Check);
|
||||
|
||||
/// Represents a Python unicode string.
|
||||
pub struct PyUnicode(PyPtr);
|
||||
|
||||
pyobject_convert!(PyUnicode);
|
||||
pyobject_nativetype!(PyUnicode, PyUnicode_Type, PyUnicode_Check);
|
||||
pyobject_nativetype2!(PyUnicode, PyUnicode_Type, PyUnicode_Check);
|
||||
|
||||
/// Represents a Python byte string. Corresponds to `str` in Python 2
|
||||
pub struct PyBytes(PyPtr);
|
||||
|
||||
pyobject_convert!(PyBytes);
|
||||
pyobject_nativetype!(PyBytes, PyBaseString_Type, PyString_Check);
|
||||
pyobject_nativetype2!(PyBytes, PyBaseString_Type, PyString_Check);
|
||||
|
||||
|
||||
impl PyString {
|
||||
/// Creates a new Python string object.
|
||||
|
@ -41,21 +39,21 @@ impl PyString {
|
|||
/// Use `PyUnicode::new()` to always create a unicode string.
|
||||
///
|
||||
/// Panics if out of memory.
|
||||
pub fn new(py: Python, s: &str) -> PyString {
|
||||
pub fn new(py: Python, s: &str) -> Py<PyString> {
|
||||
if s.is_ascii() {
|
||||
PyBytes::new(py, s.as_bytes()).into_basestring()
|
||||
PyBytes::new(py, s.as_bytes()).into()
|
||||
} else {
|
||||
PyUnicode::new(py, s).into_basestring()
|
||||
PyUnicode::new(py, s).into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_object(py: Python, src: &PyObject,
|
||||
encoding: &str, errors: &str) -> PyResult<PyString> {
|
||||
encoding: &str, errors: &str) -> PyResult<Py<PyString>> {
|
||||
unsafe {
|
||||
Ok(PyString(PyPtr::from_owned_ptr_or_err(
|
||||
Ok(Py::from_owned_ptr_or_err(
|
||||
py, ffi::PyUnicode_FromEncodedObject(
|
||||
src.as_ptr(), encoding.as_ptr() as *const i8, errors.as_ptr() as *const i8))?
|
||||
))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,12 +62,12 @@ impl PyString {
|
|||
/// For Python 2 byte strings, this function always returns `PyStringData::Utf8`,
|
||||
/// even if the bytes are not valid UTF-8.
|
||||
/// For unicode strings, returns the underlying representation used by Python.
|
||||
pub fn data(&self, py: Python) -> PyStringData {
|
||||
pub fn data(&self) -> PyStringData {
|
||||
let ob: &PyObject = self.as_ref();
|
||||
if let Ok(bytes) = ob.cast_as::<PyBytes>(py) {
|
||||
PyStringData::Utf8(bytes.data(py))
|
||||
} else if let Ok(unicode) = ob.cast_as::<PyUnicode>(py) {
|
||||
unicode.data(py)
|
||||
if let Ok(bytes) = ob.cast_as::<PyBytes>(self.token()) {
|
||||
PyStringData::Utf8(bytes.data())
|
||||
} else if let Ok(unicode) = ob.cast_as::<PyUnicode>(self.token()) {
|
||||
unicode.data()
|
||||
} else {
|
||||
panic!("PyString is neither `str` nor `unicode`")
|
||||
}
|
||||
|
@ -83,8 +81,8 @@ impl PyString {
|
|||
/// Returns a `UnicodeDecodeError` if the input is not valid unicode
|
||||
/// (containing unpaired surrogates, or a Python 2.7 byte string that is
|
||||
/// not valid UTF-8).
|
||||
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
|
||||
self.data(py).to_string(py)
|
||||
pub fn to_string(&self) -> PyResult<Cow<str>> {
|
||||
self.data().to_string(self.token())
|
||||
}
|
||||
|
||||
/// Convert the `PyString` into a Rust string.
|
||||
|
@ -94,100 +92,8 @@ impl PyString {
|
|||
///
|
||||
/// Unpaired surrogates and (on Python 2.7) invalid UTF-8 sequences are
|
||||
/// replaced with U+FFFD REPLACEMENT CHARACTER.
|
||||
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
|
||||
self.data(py).to_string_lossy()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_base_string(ptr: *mut ffi::PyObject) -> bool {
|
||||
unsafe {
|
||||
ffi::PyType_FastSubclass(
|
||||
ffi::Py_TYPE(ptr),
|
||||
ffi::Py_TPFLAGS_STRING_SUBCLASS | ffi::Py_TPFLAGS_UNICODE_SUBCLASS) != 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyDowncastFrom for PyString
|
||||
{
|
||||
fn downcast_from<'a, 'p>(py: Python<'p>, ob: &'a PyObject)
|
||||
-> Result<&'a PyString, PyDowncastError<'p>>
|
||||
{
|
||||
unsafe {
|
||||
if PyString::is_base_string(ob.as_ptr()) {
|
||||
let ptr = ob as *const _ as *mut u8 as *mut PyString;
|
||||
Ok(ptr.as_ref().expect("Failed to call as_ref"))
|
||||
} else {
|
||||
Err(PyDowncastError(py, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyDowncastInto for PyString
|
||||
{
|
||||
fn downcast_into<'p, I>(py: Python<'p>, ob: I) -> Result<Self, PyDowncastError<'p>>
|
||||
where I: IntoPyPointer
|
||||
{
|
||||
unsafe{
|
||||
let ptr = ob.into_ptr();
|
||||
if PyString::is_base_string(ptr) {
|
||||
Ok(PyString(PyPtr::from_owned_ptr(ptr)))
|
||||
} else {
|
||||
ffi::Py_DECREF(ptr);
|
||||
Err(PyDowncastError(py, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn downcast_from_ptr<'p>(py: Python<'p>, ptr: *mut ffi::PyObject)
|
||||
-> Result<PyString, PyDowncastError<'p>>
|
||||
{
|
||||
unsafe{
|
||||
if PyString::is_base_string(ptr) {
|
||||
Ok(PyString(PyPtr::from_owned_ptr(ptr)))
|
||||
} else {
|
||||
ffi::Py_DECREF(ptr);
|
||||
Err(PyDowncastError(py, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unchecked_downcast_into<'p, I>(ob: I) -> Self where I: IntoPyPointer
|
||||
{
|
||||
unsafe{
|
||||
PyString(PyPtr::from_owned_ptr(ob.into_ptr()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromPyObject<'a> for PyString
|
||||
{
|
||||
/// Extracts `Self` from the source `PyObject`.
|
||||
fn extract(py: Python, ob: &'a PyObject) -> PyResult<Self>
|
||||
{
|
||||
unsafe {
|
||||
if PyString::is_base_string(ob.as_ptr()) {
|
||||
Ok( PyString(PyPtr::from_borrowed_ptr(ob.as_ptr())) )
|
||||
} else {
|
||||
Err(PyDowncastError(py, None).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromPyObject<'a> for &'a PyString
|
||||
{
|
||||
/// Extracts `Self` from the source `PyObject`.
|
||||
fn extract(py: Python, ob: &'a PyObject) -> PyResult<Self>
|
||||
{
|
||||
unsafe {
|
||||
if PyString::is_base_string(ob.as_ptr()) {
|
||||
Ok(std::mem::transmute(ob))
|
||||
} else {
|
||||
Err(PyDowncastError(py, None).into())
|
||||
}
|
||||
}
|
||||
pub fn to_string_lossy(&self) -> Cow<str> {
|
||||
self.data().to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,23 +102,16 @@ impl PyBytes {
|
|||
/// The byte string is initialized by copying the data from the `&[u8]`.
|
||||
///
|
||||
/// Panics if out of memory.
|
||||
pub fn new(_py: Python, s: &[u8]) -> PyBytes {
|
||||
pub fn new(_py: Python, s: &[u8]) -> Py<PyBytes> {
|
||||
let ptr = s.as_ptr() as *const c_char;
|
||||
let len = s.len() as ffi::Py_ssize_t;
|
||||
unsafe {
|
||||
PyBytes(PyPtr::from_owned_ptr_or_panic(
|
||||
ffi::PyBytes_FromStringAndSize(ptr, len)))
|
||||
Py::from_owned_ptr_or_panic(ffi::PyBytes_FromStringAndSize(ptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `PyBytes` to `PyString`.
|
||||
#[inline]
|
||||
pub fn into_basestring(self) -> PyString {
|
||||
<PyString as ::PyDowncastInto>::unchecked_downcast_into(self)
|
||||
}
|
||||
|
||||
/// Gets the Python string data as byte slice.
|
||||
pub fn data(&self, _py: Python) -> &[u8] {
|
||||
pub fn data(&self) -> &[u8] {
|
||||
unsafe {
|
||||
let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8;
|
||||
let length = ffi::PyBytes_Size(self.as_ptr()) as usize;
|
||||
|
@ -226,36 +125,28 @@ impl PyUnicode {
|
|||
/// Creates a new Python unicode string object.
|
||||
///
|
||||
/// Panics if out of memory.
|
||||
pub fn new(_py: Python, s: &str) -> PyUnicode {
|
||||
pub fn new(_py: Python, s: &str) -> Py<PyUnicode> {
|
||||
let ptr = s.as_ptr() as *const c_char;
|
||||
let len = s.len() as ffi::Py_ssize_t;
|
||||
unsafe {
|
||||
PyUnicode(PyPtr::from_owned_ptr_or_panic(
|
||||
ffi::PyUnicode_FromStringAndSize(ptr, len)))
|
||||
Py::from_owned_ptr_or_panic(ffi::PyUnicode_FromStringAndSize(ptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_object(py: Python, src: &PyObject, encoding: &str, errors: &str)
|
||||
-> PyResult<PyUnicode>
|
||||
-> PyResult<Py<PyUnicode>>
|
||||
{
|
||||
unsafe {
|
||||
Ok(PyUnicode(
|
||||
PyPtr::from_owned_ptr_or_err(
|
||||
Ok(Py::from_owned_ptr_or_err(
|
||||
py, ffi::PyUnicode_FromEncodedObject(
|
||||
src.as_ptr(),
|
||||
encoding.as_ptr() as *const i8,
|
||||
errors.as_ptr() as *const i8))?))
|
||||
errors.as_ptr() as *const i8))?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `PyUnicode` to `PyString`.
|
||||
#[inline]
|
||||
pub fn into_basestring(self) -> PyString {
|
||||
<PyString as ::PyDowncastInto>::unchecked_downcast_into(self)
|
||||
}
|
||||
|
||||
/// Gets the python string data in its underlying representation.
|
||||
pub fn data(&self, _py: Python) -> PyStringData {
|
||||
pub fn data(&self) -> PyStringData {
|
||||
unsafe {
|
||||
let buffer = ffi::PyUnicode_AS_UNICODE(self.as_ptr());
|
||||
let length = ffi::PyUnicode_GET_SIZE(self.as_ptr()) as usize;
|
||||
|
@ -267,18 +158,35 @@ impl PyUnicode {
|
|||
///
|
||||
/// Returns a `UnicodeDecodeError` if the input is not valid unicode
|
||||
/// (containing unpaired surrogates).
|
||||
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
|
||||
self.data(py).to_string(py)
|
||||
pub fn to_string(&self) -> PyResult<Cow<str>> {
|
||||
self.data().to_string(self.token())
|
||||
}
|
||||
|
||||
/// Convert the `PyString` into a Rust string.
|
||||
///
|
||||
/// Unpaired surrogates are replaced with U+FFFD REPLACEMENT CHARACTER.
|
||||
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
|
||||
self.data(py).to_string_lossy()
|
||||
pub fn to_string_lossy(&self) -> Cow<str> {
|
||||
self.data().to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `PyBytes` to `PyString`.
|
||||
impl std::convert::From<Py<PyBytes>> for Py<PyString> {
|
||||
#[inline]
|
||||
fn from(ob: Py<PyBytes>) -> Py<PyString> {
|
||||
<Py<PyString> as ::PyDowncastInto>::unchecked_downcast_into(ob)
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `PyUnicode` to `PyString`.
|
||||
impl std::convert::From<Py<PyUnicode>> for Py<PyString> {
|
||||
#[inline]
|
||||
fn from(ob: Py<PyUnicode>) -> Py<PyString> {
|
||||
<Py<PyString> as ::PyDowncastInto>::unchecked_downcast_into(ob)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use python::Python;
|
||||
|
|
|
@ -53,7 +53,7 @@ impl<'a> IntoPyObject for &'a String {
|
|||
/// Allows extracting strings from Python objects.
|
||||
/// Accepts Python `str` and `unicode` objects.
|
||||
pyobject_extract!(py, obj to Cow<'source, str> => {
|
||||
try!(obj.cast_as::<PyString>(py)).to_string(py)
|
||||
try!(obj.cast_as::<PyString>(py)).to_string()
|
||||
});
|
||||
|
||||
|
||||
|
@ -61,7 +61,7 @@ pyobject_extract!(py, obj to Cow<'source, str> => {
|
|||
/// Accepts Python `str` and `unicode` objects.
|
||||
pyobject_extract!(py, obj to String => {
|
||||
let s = try!(obj.cast_as::<PyString>(py));
|
||||
s.to_string(py).map(Cow::into_owned)
|
||||
s.to_string().map(Cow::into_owned)
|
||||
});
|
||||
|
||||
|
||||
|
|
37
src/token.rs
37
src/token.rs
|
@ -12,10 +12,12 @@ use python::{Python, IntoPyPointer, ToPyPointer, PyDowncastInto};
|
|||
use typeob::{PyTypeInfo, PyObjectAlloc};
|
||||
|
||||
|
||||
pub trait PyNativeType {}
|
||||
|
||||
pub struct PyToken(PhantomData<Rc<()>>);
|
||||
|
||||
impl PyToken {
|
||||
pub fn token(&self) -> Python {
|
||||
pub fn token<'p>(&'p self) -> Python<'p> {
|
||||
unsafe { Python::assume_gil_acquired() }
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +72,7 @@ pub trait AsPyRef<T> : Sized {
|
|||
}
|
||||
|
||||
/// Wrapper around unsafe `*mut ffi::PyObject` pointer. Decrement ref counter on `Drop`
|
||||
#[derive(Debug)]
|
||||
pub struct Py<T>(*mut ffi::PyObject, std::marker::PhantomData<T>);
|
||||
|
||||
// `PyPtr` is thread-safe, because any python related operations require a Python<'p> token.
|
||||
|
@ -179,7 +182,7 @@ impl<T> Py<T> where T: PyTypeInfo,
|
|||
impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo {
|
||||
|
||||
#[inline]
|
||||
fn as_ref(&self, _py: Python) -> &T {
|
||||
default fn as_ref(&self, _py: Python) -> &T {
|
||||
let offset = <T as PyTypeInfo>::offset();
|
||||
unsafe {
|
||||
let ptr = (self.as_ptr() as *mut u8).offset(offset) as *mut T;
|
||||
|
@ -187,7 +190,7 @@ impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo {
|
|||
}
|
||||
}
|
||||
#[inline]
|
||||
fn as_mut(&self, _py: Python) -> &mut T {
|
||||
default fn as_mut(&self, _py: Python) -> &mut T {
|
||||
let offset = <T as PyTypeInfo>::offset();
|
||||
unsafe {
|
||||
let ptr = (self.as_ptr() as *mut u8).offset(offset) as *mut T;
|
||||
|
@ -196,6 +199,18 @@ impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> InstancePtr<T> for Py<T> where T: PyTypeInfo + PyNativeType {
|
||||
|
||||
#[inline]
|
||||
fn as_ref(&self, _py: Python) -> &T {
|
||||
unsafe {std::mem::transmute(self)}
|
||||
}
|
||||
#[inline]
|
||||
fn as_mut(&self, _py: Python) -> &mut T {
|
||||
unsafe {std::mem::transmute(self as *const _ as *mut T)}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToPyObject for Py<T> {
|
||||
fn to_object(&self, py: Python) -> PyObject {
|
||||
PyObject::from_borrowed_ptr(py, self.as_ptr())
|
||||
|
@ -250,6 +265,7 @@ impl<T> Drop for Py<T> {
|
|||
|
||||
|
||||
impl<T> std::convert::From<Py<T>> for PyObject {
|
||||
#[inline]
|
||||
fn from(ob: Py<T>) -> Self {
|
||||
unsafe {std::mem::transmute(ob)}
|
||||
}
|
||||
|
@ -294,11 +310,7 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
|
|||
where I: IntoPyPointer
|
||||
{
|
||||
unsafe{
|
||||
let ptr = ob.into_ptr();
|
||||
let checked = ffi::PyObject_TypeCheck(
|
||||
ptr, <T as PyTypeInfo>::type_object()) != 0;
|
||||
|
||||
if checked {
|
||||
if T::is_instance(ptr) {
|
||||
Ok(Py::from_owned_ptr(ptr))
|
||||
} else {
|
||||
ffi::Py_DECREF(ptr);
|
||||
|
@ -311,8 +323,7 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
|
|||
-> Result<Self, PyDowncastError<'p>>
|
||||
{
|
||||
unsafe{
|
||||
let checked = ffi::PyObject_TypeCheck(ptr, <T as PyTypeInfo>::type_object()) != 0;
|
||||
if checked {
|
||||
if T::is_instance(ptr) {
|
||||
Ok(Py::from_owned_ptr(ptr))
|
||||
} else {
|
||||
ffi::Py_DECREF(ptr);
|
||||
|
@ -330,17 +341,13 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, T> ::FromPyObject<'a> for Py<T> where T: PyTypeInfo
|
||||
{
|
||||
/// Extracts `Self` from the source `PyObject`.
|
||||
fn extract(py: Python, ob: &'a PyObject) -> PyResult<Self>
|
||||
{
|
||||
unsafe {
|
||||
let checked = ffi::PyObject_TypeCheck(
|
||||
ob.as_ptr(), <T as PyTypeInfo>::type_object()) != 0;
|
||||
|
||||
if checked {
|
||||
if T::is_instance(ob.as_ptr()) {
|
||||
Ok( Py::from_borrowed_ptr(ob.as_ptr()) )
|
||||
} else {
|
||||
Err(::PyDowncastError(py, None).into())
|
||||
|
|
|
@ -35,6 +35,9 @@ pub trait PyTypeInfo {
|
|||
/// PyTypeObject instance for this type
|
||||
fn type_object() -> &'static mut ffi::PyTypeObject;
|
||||
|
||||
/// Check `*mut ffi::PyObject` if it is the same type
|
||||
fn is_instance(ptr: *mut ffi::PyObject) -> bool;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,6 +63,12 @@ impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
|
|||
default fn type_object() -> &'static mut ffi::PyTypeObject {
|
||||
<T as PyTypeInfo>::type_object()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn is_instance(ptr: *mut ffi::PyObject) -> bool {
|
||||
<T as PyTypeInfo>::is_instance(ptr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub trait PyObjectAlloc<T> {
|
||||
|
|
|
@ -305,7 +305,7 @@ struct ClassMethodWithArgs{token: PyToken}
|
|||
#[py::methods]
|
||||
impl ClassMethodWithArgs {
|
||||
#[classmethod]
|
||||
fn method(cls: &PyType, py: Python, input: PyString) -> PyResult<String> {
|
||||
fn method(cls: &PyType, py: Python, input: &PyString) -> PyResult<String> {
|
||||
Ok(format!("{}.method({})", cls.name(py), input))
|
||||
}
|
||||
}
|
||||
|
@ -483,12 +483,12 @@ impl<'p> PyObjectProtocol<'p> for StringMethods {
|
|||
Ok(format!("format({})", format_spec))
|
||||
}
|
||||
|
||||
fn __unicode__(&self, py: Python) -> PyResult<PyString> {
|
||||
Ok(PyString::new(py, "unicode"))
|
||||
fn __unicode__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(PyString::new(py, "unicode").into())
|
||||
}
|
||||
|
||||
fn __bytes__(&self, py: Python) -> PyResult<PyBytes> {
|
||||
Ok(PyBytes::new(py, b"bytes"))
|
||||
fn __bytes__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Ok(PyBytes::new(py, b"bytes").into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue