Adjust to rust nightly

This commit is contained in:
Daniel Grunwald 2015-03-08 15:29:44 +01:00
parent 77b178af40
commit 913f3ea2e5
9 changed files with 42 additions and 182 deletions

View File

@ -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"

View File

@ -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())
);
);

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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};

View File

@ -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))))

View File

@ -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());
}

View File

@ -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.