Adjust to rust nightly
This commit is contained in:
parent
77b178af40
commit
913f3ea2e5
|
@ -5,9 +5,9 @@ version = "0.0.1"
|
|||
description = "Bindings to Python 2.7"
|
||||
authors = ["Daniel Grunwald <daniel@danielgrunwald.de>"]
|
||||
|
||||
#[dependencies]
|
||||
#python27-sys="0.0.2"
|
||||
[dependencies]
|
||||
python27-sys="0.0.3"
|
||||
|
||||
[dependencies.python27-sys]
|
||||
path = "../python27-sys"
|
||||
#[dependencies.python27-sys]
|
||||
#path = "../python27-sys"
|
||||
|
||||
|
|
149
src/cstr.rs
149
src/cstr.rs
|
@ -1,149 +0,0 @@
|
|||
use libc::c_char;
|
||||
use std::ffi::CString;
|
||||
use std::borrow::{BorrowFrom, ToOwned};
|
||||
use std::{fmt, mem, ops, str};
|
||||
|
||||
// Idea:
|
||||
// CString = Vec<u8> + 0-invariant (0-terminated, but no interior 0)
|
||||
// this makes it similar to
|
||||
// String = Vec<u8> + UTF-8-invariant
|
||||
|
||||
// Dereferencing String results in
|
||||
// str = [u8] + UTF-8 invariant
|
||||
|
||||
// So why does dereferencing CString result in [u8], dropping the 0-invariant?
|
||||
// This module implements a type CStr = [u8] + 0-invariant.
|
||||
|
||||
// This allows writing safe FFI bindings that accept &CStr and call a C function:
|
||||
// fn f(s: &CStr) { ffi::f(s.as_ptr()) }
|
||||
|
||||
// Without CStr, f() would have to take &CString (forcing the string to be heap-allocated),
|
||||
// or f() could take &[u8] and verify the 0-invariant itself -- but this verification is redundant
|
||||
// when the &[u8] was borrowed from a CString.
|
||||
// (or otherwise known to be valid, e.g. the output of a cstr!("string literal") macro)
|
||||
|
||||
|
||||
// CString changes if this type is adopted in std::ffi:
|
||||
// * <CString as Deref>::Target should change from &[c_char] to &CStr
|
||||
// * CString::{as_slice_with_nul, as_bytes, as_bytes_with_nul} can be deleted, as they already available through Deref
|
||||
// * The free functions c_str_to_bytes and c_str_to_bytes_with_nul can be removed, as the same functionality is
|
||||
// available through CStr::from_ptr( ).as_bytes() / CStr::from_ptr( ).as_bytes_with_nul()
|
||||
|
||||
// Independently from CStr:
|
||||
// * CString::from_slice(s.as_bytes()) looks weird, since both 'as_slice' and 'as_bytes'
|
||||
// exist on CString with different return types.
|
||||
// CString::from_slice should be renamed to from_bytes
|
||||
|
||||
// #[derive(PartialEq, PartialOrd, Eq, Ord, Hash) -- ICE #18805
|
||||
// #[repr(newtype)] or something, for the transmute in from_slice_with_nul_unchecked
|
||||
pub struct CStr {
|
||||
// invariants:
|
||||
// - data.len() >= 1
|
||||
// - data[0..data.len()-1] does not contain '\0'
|
||||
// - data[data.len()-1] == '\0'
|
||||
inner: [c_char]
|
||||
}
|
||||
|
||||
|
||||
impl CStr {
|
||||
/// Convert a C string pointer into a &CStr reference.
|
||||
///
|
||||
/// Unsafe because:
|
||||
/// * The pointer is assumed to point to a valid C string.
|
||||
/// * The lifetime provided may not be a suitable lifetime for the returned &CStr.
|
||||
pub unsafe fn from_ptr<'a>(raw: &'a *const c_char) -> &'a CStr {
|
||||
CStr::from_bytes_with_nul_unchecked(::std::ffi::c_str_to_bytes_with_nul(raw))
|
||||
}
|
||||
|
||||
/// Create a C-compatible string slice from a byte slice.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the last byte in the slice is not 0,
|
||||
/// or if any other bytes are 0.
|
||||
pub fn from_bytes_with_nul(v: &[u8]) -> &CStr {
|
||||
assert!(v[v.len() - 1] == 0 && !v[..v.len() - 1].iter().any(|&x| x == 0));
|
||||
unsafe { CStr::from_bytes_with_nul_unchecked(v) }
|
||||
}
|
||||
|
||||
/// Create a C-compatible string slice from a byte slice.
|
||||
/// The slice must have a length >= 1, the last byte must be 0,
|
||||
/// and no other bytes may be 0.
|
||||
///
|
||||
/// Violating these constraints causes undefined behavior.
|
||||
pub unsafe fn from_bytes_with_nul_unchecked(v: &[u8]) -> &CStr {
|
||||
// TODO: does this transmute have defined behavior?
|
||||
// we're relying on repr([u8]) = repr(CStr) here, newtypes would surely be helpful
|
||||
mem::transmute::<&[u8], &CStr>(v)
|
||||
}
|
||||
|
||||
// as_ptr(), as_slice(): should be coming from Deref<Target=c_char>, but
|
||||
// we need to re-implement them to avoid an ICE (#16812 ?)
|
||||
pub fn as_ptr(&self) -> *const c_char {
|
||||
self.inner.as_ptr()
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[c_char] {
|
||||
&self.inner[..self.inner.len() - 1]
|
||||
}
|
||||
|
||||
/// Create a view into this C string which includes the trailing nul
|
||||
/// terminator at the end of the string.
|
||||
pub fn as_slice_with_nul(&self) -> &[c_char] {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
unsafe { mem::transmute(self.as_slice()) }
|
||||
}
|
||||
|
||||
pub fn as_bytes_with_nul(&self) -> &[u8] {
|
||||
unsafe { mem::transmute(self.as_slice_with_nul()) }
|
||||
}
|
||||
|
||||
pub fn as_utf8(&self) -> Result<&str, str::Utf8Error> {
|
||||
str::from_utf8(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl ops::Deref for CStr {
|
||||
type Target = [c_char];
|
||||
|
||||
fn deref(&self) -> &[c_char] {
|
||||
// Does not underflow thanks to our invariant.
|
||||
// But rustc doesn't know that, so it may need some help to generate efficient code.
|
||||
&self.inner[..self.inner.len() - 1]
|
||||
}
|
||||
}
|
||||
|
||||
impl BorrowFrom<CString> for CStr {
|
||||
fn borrow_from(owned: &CString) -> &CStr {
|
||||
// This is safe because CStr and CString have the same invariant.
|
||||
unsafe { CStr::from_bytes_with_nul_unchecked(owned.as_bytes_with_nul()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ToOwned<CString> for CStr {
|
||||
fn to_owned(&self) -> CString {
|
||||
// This is safe because CStr and CString have the same invariant.
|
||||
unsafe {
|
||||
CString::from_vec_unchecked(self.as_bytes_with_nul().to_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for CStr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
String::from_utf8_lossy(self.as_bytes()).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cstr(
|
||||
($s: tt) => (
|
||||
// TODO: verify that $s is a string literal without nuls,
|
||||
// and remove the runtime check by using from_bytes_with_nul_unchecked.
|
||||
$crate::CStr::from_bytes_with_nul(concat!($s, "\0").as_bytes())
|
||||
);
|
||||
);
|
||||
|
|
@ -5,7 +5,7 @@ use objects::oldstyle::PyClass;
|
|||
use ffi;
|
||||
use libc;
|
||||
use conversion::ToPyObject;
|
||||
use cstr::CStr;
|
||||
use std::ffi::CStr;
|
||||
|
||||
/// Represents a python exception that was raised.
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -248,7 +248,7 @@ mod tests {
|
|||
let py = gil.python();
|
||||
PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), None).restore();
|
||||
assert!(PyErr::occurred(py));
|
||||
drop(PyErr::fetch(py))
|
||||
drop(PyErr::fetch(py));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -1,7 +1,7 @@
|
|||
#![feature(core)]
|
||||
#![feature(libc)]
|
||||
#![feature(std_misc)]
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(unsafe_no_drop_flag)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![allow(unused_imports, dead_code, unused_variables)]
|
||||
|
||||
|
@ -14,10 +14,18 @@ pub use objects::*;
|
|||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
|
||||
pub use conversion::{FromPyObject, ToPyObject};
|
||||
pub use objectprotocol::{ObjectProtocol};
|
||||
pub use cstr::CStr;
|
||||
pub use std::ffi::CStr;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cstr(
|
||||
($s: tt) => (
|
||||
// TODO: verify that $s is a string literal without nuls
|
||||
unsafe {
|
||||
::std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr() as *const _)
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
#[macro_use]
|
||||
mod cstr;
|
||||
mod python;
|
||||
mod err;
|
||||
mod conversion;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std;
|
||||
use std::{fmt, string};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use ffi;
|
||||
use libc;
|
||||
|
@ -234,7 +235,7 @@ impl <'p> fmt::Debug for PyObject<'p> {
|
|||
fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
use objectprotocol::ObjectProtocol;
|
||||
let repr_obj = try!(self.str().map_err(|_| fmt::Error));
|
||||
let repr = try!(repr_obj.extract::<string::CowString>().map_err(|_| fmt::Error));
|
||||
let repr = try!(repr_obj.extract::<Cow<str>>().map_err(|_| fmt::Error));
|
||||
f.write_str(&*repr)
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +244,7 @@ impl <'p> fmt::Display for PyObject<'p> {
|
|||
fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
use objectprotocol::ObjectProtocol;
|
||||
let repr_obj = try!(self.repr().map_err(|_| fmt::Error));
|
||||
let repr = try!(repr_obj.extract::<string::CowString>().map_err(|_| fmt::Error));
|
||||
let repr = try!(repr_obj.extract::<Cow<str>>().map_err(|_| fmt::Error));
|
||||
f.write_str(&*repr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use libc::c_char;
|
|||
use std::ops::Range;
|
||||
use std::str::Utf8Error;
|
||||
use std::mem;
|
||||
use cstr::CStr;
|
||||
use std::ffi::CStr;
|
||||
use ffi;
|
||||
use python::{Python, ToPythonPointer, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectDowncastError, PythonObjectWithTypeObject};
|
||||
use err::{self, PyResult};
|
||||
|
|
|
@ -5,7 +5,7 @@ use python::{Python, PythonObject, ToPythonPointer};
|
|||
use conversion::ToPyObject;
|
||||
use objects::{PyObject, PyType, PyDict, exc};
|
||||
use err::{self, PyResult, PyErr};
|
||||
use cstr::CStr;
|
||||
use std::ffi::CStr;
|
||||
|
||||
pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type);
|
||||
|
||||
|
@ -34,7 +34,7 @@ impl <'p> PyModule<'p> {
|
|||
Err(PyErr::fetch(py))
|
||||
} else {
|
||||
let ptr = ptr as *const c_char;
|
||||
let slice = std::ffi::c_str_to_bytes(&ptr);
|
||||
let slice = CStr::from_ptr(ptr).to_bytes();
|
||||
match std::str::from_utf8(slice) {
|
||||
Ok(s) => Ok(std::mem::copy_lifetime(self, s)),
|
||||
Err(e) => Err(PyErr::new(try!(exc::UnicodeDecodeError::new_utf8(py, slice, e))))
|
||||
|
|
|
@ -2,7 +2,6 @@ use std;
|
|||
use std::{char, str};
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
use std::string::CowString;
|
||||
use libc::c_char;
|
||||
use ffi;
|
||||
use python::{Python, PythonObject, ToPythonPointer};
|
||||
|
@ -21,7 +20,7 @@ impl <'p> PyString<'p> {
|
|||
unsafe {
|
||||
let buffer = ffi::PyString_AS_STRING(self.as_ptr()) as *const u8;
|
||||
let length = ffi::PyString_GET_SIZE(self.as_ptr()) as usize;
|
||||
std::slice::from_raw_buf(std::mem::copy_lifetime(self, &buffer), length)
|
||||
std::slice::from_raw_parts(buffer, length)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +34,7 @@ impl <'p> PyUnicode<'p> {
|
|||
unsafe {
|
||||
let buffer = ffi::PyUnicode_AS_UNICODE(self.as_ptr()) as *const _;
|
||||
let length = ffi::PyUnicode_GET_SIZE(self.as_ptr()) as usize;
|
||||
std::slice::from_raw_buf(std::mem::copy_lifetime(self, &buffer), length)
|
||||
std::slice::from_raw_parts(buffer, length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +45,8 @@ impl <'p> ToPyObject<'p> for str {
|
|||
type ObjectType = PyObject<'p>;
|
||||
|
||||
fn to_py_object(&self, py : Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
let ptr : *const c_char = self.as_ptr() as *const _;
|
||||
let len : ffi::Py_ssize_t = std::num::from_uint(self.len()).unwrap();
|
||||
let ptr = self.as_ptr() as *const c_char;
|
||||
let len = self.len() as ffi::Py_ssize_t;
|
||||
unsafe {
|
||||
let obj = if self.is_ascii() {
|
||||
ffi::PyString_FromStringAndSize(ptr, len)
|
||||
|
@ -71,8 +70,8 @@ fn u32_as_bytes(input: &[u32]) -> &[u8] {
|
|||
unsafe { std::mem::transmute(input) }
|
||||
}
|
||||
|
||||
impl <'p, 's> FromPyObject<'p, 's> for CowString<'s> {
|
||||
fn from_py_object(o: &'s PyObject<'p>) -> PyResult<'p, CowString<'s>> {
|
||||
impl <'p, 's> FromPyObject<'p, 's> for Cow<'s, str> {
|
||||
fn from_py_object(o: &'s PyObject<'p>) -> PyResult<'p, Cow<'s, str>> {
|
||||
let py = o.python();
|
||||
if let Ok(s) = o.cast_as::<PyString>() {
|
||||
match s.as_str() {
|
||||
|
@ -101,19 +100,18 @@ impl <'p, 's> FromPyObject<'p, 's> for CowString<'s> {
|
|||
|
||||
impl <'p, 's> FromPyObject<'p, 's> for String {
|
||||
fn from_py_object(o: &'s PyObject<'p>) -> PyResult<'p, String> {
|
||||
Ok(try!(o.extract::<CowString>()).into_owned())
|
||||
Ok(try!(o.extract::<Cow<str>>()).into_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_as_slice<'a, 'p>(s: &'a PyObject<'p>) -> PyResult<'p, &'a [u8]> {
|
||||
fn string_as_slice<'a, 'p>(s: &'a PyObject<'p>) -> PyResult<'p, &'a [u8]> {
|
||||
unsafe {
|
||||
let mut buffer : *mut c_char = std::mem::uninitialized();
|
||||
let mut length : ffi::Py_ssize_t = std::mem::uninitialized();
|
||||
if ffi::PyString_AsStringAndSize(s.as_ptr(), &mut buffer, &mut length) == 1 {
|
||||
Err(PyErr::fetch(s.python()))
|
||||
} else {
|
||||
let buffer = buffer as *const u8; // TODO see std::ffi
|
||||
Ok(std::slice::from_raw_buf(std::mem::copy_lifetime(s, &buffer), length as usize))
|
||||
Ok(std::slice::from_raw_parts(buffer as *const u8, length as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +123,6 @@ fn test_non_bmp() {
|
|||
let py = gil.python();
|
||||
let s = "\u{1F30F}";
|
||||
let py_string = s.to_py_object(py).unwrap();
|
||||
assert_eq!(s, py_string.extract::<CowString>().unwrap());
|
||||
assert_eq!(s, py_string.extract::<Cow<str>>().unwrap());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
use std;
|
||||
use std::marker::{InvariantLifetime};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use ffi;
|
||||
use objects::{PyObject, PyType, PyBool, PyModule};
|
||||
use err::PyResult;
|
||||
use pythonrun::GILGuard;
|
||||
use cstr::CStr;
|
||||
use std::ffi::CStr;
|
||||
|
||||
// Dummy struct representing the global state in the python interpreter.
|
||||
struct PythonInterpreterState;
|
||||
impl !Sync for PythonInterpreterState {}
|
||||
|
||||
/// The 'Python' struct is a zero-size marker struct that is required for most python operations.
|
||||
/// This is used to indicate that the operation accesses/modifies the python interpreter state,
|
||||
|
@ -15,9 +19,7 @@ use cstr::CStr;
|
|||
/// You can imagine the GIL to be a giant "Mutex<AllPythonState>". This makes 'p the lifetime of the
|
||||
/// python state protected by that mutex.
|
||||
#[derive(Copy)]
|
||||
pub struct Python<'p>(InvariantLifetime<'p>);
|
||||
|
||||
impl <'p> !Send for Python<'p> {}
|
||||
pub struct Python<'p>(PhantomData<&'p PythonInterpreterState>);
|
||||
|
||||
// Trait for converting from Self to *mut ffi::PyObject
|
||||
pub trait ToPythonPointer {
|
||||
|
@ -108,7 +110,7 @@ impl<'p> Python<'p> {
|
|||
/// and stays acquired for the lifetime 'p
|
||||
#[inline]
|
||||
pub unsafe fn assume_gil_acquired() -> Python<'p> {
|
||||
Python(InvariantLifetime)
|
||||
Python(PhantomData)
|
||||
}
|
||||
|
||||
/// Acquires the global interpreter lock, which allows access to the Python runtime.
|
||||
|
|
Loading…
Reference in New Issue