2015-04-19 03:22:03 +00:00
|
|
|
// Copyright (c) 2015 Daniel Grunwald
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
|
|
// software and associated documentation files (the "Software"), to deal in the Software
|
|
|
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
|
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
|
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in all copies or
|
|
|
|
// substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
|
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
|
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2015-01-11 17:56:59 +00:00
|
|
|
use python::{Python, PythonObject, ToPythonPointer};
|
2015-08-26 02:00:01 +00:00
|
|
|
use err::{self, PyErr, PyResult};
|
2015-01-07 00:40:48 +00:00
|
|
|
use super::object::PyObject;
|
2015-01-11 17:56:59 +00:00
|
|
|
use super::exc;
|
2015-01-07 00:40:48 +00:00
|
|
|
use ffi::{self, Py_ssize_t};
|
2015-07-18 20:39:55 +00:00
|
|
|
use conversion::{ToPyObject, ExtractPyObject};
|
2015-09-20 17:40:18 +00:00
|
|
|
use std::slice;
|
2015-01-07 00:40:48 +00:00
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Represents a Python tuple object.
|
2015-10-25 16:55:29 +00:00
|
|
|
pub struct PyTuple(PyObject);
|
2015-06-27 20:45:35 +00:00
|
|
|
|
2015-01-07 00:40:48 +00:00
|
|
|
pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);
|
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
impl PyTuple {
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Construct a new tuple with the given elements.
|
2015-10-25 16:55:29 +00:00
|
|
|
pub fn new(py: Python, elements: &[PyObject]) -> PyTuple {
|
2015-01-07 00:40:48 +00:00
|
|
|
unsafe {
|
|
|
|
let len = elements.len();
|
|
|
|
let ptr = ffi::PyTuple_New(len as Py_ssize_t);
|
2015-06-27 20:45:35 +00:00
|
|
|
let t = err::result_cast_from_owned_ptr::<PyTuple>(py, ptr).unwrap();
|
2015-01-07 00:40:48 +00:00
|
|
|
for (i, e) in elements.iter().enumerate() {
|
2015-10-25 16:55:29 +00:00
|
|
|
ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.steal_ptr(py));
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
2015-01-11 17:56:59 +00:00
|
|
|
t
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-11 17:56:59 +00:00
|
|
|
|
|
|
|
/// Retrieves the empty tuple.
|
2015-10-25 16:55:29 +00:00
|
|
|
pub fn empty(py: Python) -> PyTuple {
|
2015-01-11 17:56:59 +00:00
|
|
|
unsafe {
|
2015-06-27 20:45:35 +00:00
|
|
|
err::result_cast_from_owned_ptr::<PyTuple>(py, ffi::PyTuple_New(0)).unwrap()
|
2015-01-11 17:56:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Gets the length of the tuple.
|
2015-01-07 00:40:48 +00:00
|
|
|
#[inline]
|
2015-01-11 03:21:05 +00:00
|
|
|
pub fn len(&self) -> usize {
|
2015-10-25 16:55:29 +00:00
|
|
|
// Safe despite not taking a `Python`, because tuples are immutable.
|
2015-01-07 00:40:48 +00:00
|
|
|
unsafe {
|
2015-10-25 16:55:29 +00:00
|
|
|
// non-negative Py_ssize_t should always fit into Rust uint
|
|
|
|
ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-23 21:52:38 +00:00
|
|
|
|
|
|
|
/// Gets the item at the specified index.
|
|
|
|
///
|
|
|
|
/// Panics if the index is out of range.
|
2015-10-25 16:55:29 +00:00
|
|
|
pub fn get_item(&self, index: usize, py: Python) -> PyObject {
|
2015-05-23 21:52:38 +00:00
|
|
|
assert!(index < self.len());
|
|
|
|
unsafe {
|
2015-10-25 16:55:29 +00:00
|
|
|
PyObject::from_borrowed_ptr(py, ffi::PyTuple_GET_ITEM(self.0.as_ptr(), index as Py_ssize_t))
|
2015-05-23 21:52:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-07 00:40:48 +00:00
|
|
|
#[inline]
|
2015-10-25 16:55:29 +00:00
|
|
|
pub fn as_slice<'a>(&'a self) -> &'a [PyObject] {
|
2015-01-07 00:40:48 +00:00
|
|
|
// This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
|
|
|
|
// and because tuples are immutable.
|
|
|
|
unsafe {
|
2015-10-25 16:55:29 +00:00
|
|
|
let ptr = self.0.as_ptr() as *mut ffi::PyTupleObject;
|
|
|
|
PyObject::borrow_from_owned_ptr_slice(
|
2015-09-20 17:40:18 +00:00
|
|
|
slice::from_raw_parts(
|
|
|
|
(*ptr).ob_item.as_ptr(),
|
|
|
|
self.len()))
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
/*
|
|
|
|
impl IntoIterator for PyTuple {
|
|
|
|
type Item = PyObject;
|
|
|
|
type IntoIter = PyTupleIterator;
|
2015-05-24 16:20:35 +00:00
|
|
|
|
|
|
|
#[inline]
|
2015-10-25 16:55:29 +00:00
|
|
|
fn into_iter(self) -> PyTupleIterator {
|
2015-09-20 17:40:18 +00:00
|
|
|
PyTupleIterator { index: 0, end: self.len(), tuple: self }
|
2015-05-24 16:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
impl <'a> IntoIterator for &'a PyTuple {
|
2015-05-24 16:20:35 +00:00
|
|
|
type Item = PyObject<'p>;
|
|
|
|
type IntoIter = PyTupleIterator<'p>;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn into_iter(self) -> PyTupleIterator<'p> {
|
2015-09-20 17:40:18 +00:00
|
|
|
PyTupleIterator { index: 0, end: self.len(), tuple: self.clone() }
|
2015-05-24 16:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Used by `impl IntoIterator for &PyTuple`.
|
2015-05-24 16:20:35 +00:00
|
|
|
pub struct PyTupleIterator<'p> {
|
|
|
|
tuple: PyTuple<'p>,
|
|
|
|
index: usize,
|
2015-09-20 17:40:18 +00:00
|
|
|
end: usize
|
2015-05-24 16:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl <'p> Iterator for PyTupleIterator<'p> {
|
|
|
|
type Item = PyObject<'p>;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<PyObject<'p>> {
|
2015-09-20 17:40:18 +00:00
|
|
|
if self.index < self.end {
|
2015-05-24 16:20:35 +00:00
|
|
|
let item = self.tuple.get_item(self.index);
|
|
|
|
self.index += 1;
|
|
|
|
Some(item)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
2015-09-20 17:40:18 +00:00
|
|
|
(self.len(), Some(self.len()))
|
2015-05-24 16:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <'p> ExactSizeIterator for PyTupleIterator<'p> {
|
|
|
|
#[inline]
|
|
|
|
fn len(&self) -> usize {
|
2015-09-20 17:40:18 +00:00
|
|
|
self.end - self.index
|
2015-05-24 16:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-25 16:55:29 +00:00
|
|
|
*/
|
2015-05-24 16:20:35 +00:00
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
fn wrong_tuple_length(t: &PyTuple, expected_length: usize, py: Python) -> PyErr {
|
2015-01-11 17:56:59 +00:00
|
|
|
let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len());
|
2015-05-23 21:52:38 +00:00
|
|
|
PyErr::new_lazy_init(py.get_type::<exc::ValueError>(), Some(msg.to_py_object(py).into_object()))
|
2015-01-11 17:56:59 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 23:07:14 +00:00
|
|
|
macro_rules! id (($a:expr) => ($a));
|
|
|
|
|
2015-01-11 17:56:59 +00:00
|
|
|
macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => (
|
2015-10-25 16:55:29 +00:00
|
|
|
impl <'p, $($T: ToPyObject),+> ToPyObject for ($($T,)+) {
|
|
|
|
type ObjectType = PyTuple;
|
2015-01-11 17:56:59 +00:00
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
fn to_py_object(&self, py: Python) -> PyTuple {
|
2015-04-18 23:07:14 +00:00
|
|
|
PyTuple::new(py, &[
|
|
|
|
$(id!(self.$n.to_py_object(py)).into_object(),)+
|
|
|
|
])
|
2015-01-11 17:56:59 +00:00
|
|
|
}
|
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
fn into_py_object(self, py: Python) -> PyTuple {
|
2015-04-18 23:07:14 +00:00
|
|
|
PyTuple::new(py, &[
|
|
|
|
$(id!(self.$n.into_py_object(py)).into_object(),)+
|
|
|
|
])
|
2015-01-11 17:56:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
/*TODO: reimplement this without slice matching
|
2015-01-11 17:56:59 +00:00
|
|
|
impl <'p, 's, $($T: FromPyObject<'p, 's>),+> FromPyObject<'p, 's> for ($($T,)+) {
|
|
|
|
fn from_py_object(s : &'s PyObject<'p>) -> PyResult<'p, ($($T,)+)> {
|
|
|
|
let t = try!(s.cast_as::<PyTuple>());
|
|
|
|
match t.as_slice() {
|
|
|
|
[$(ref $refN,)+] => Ok((
|
|
|
|
$(try!($refN.extract::<$T>()),)+
|
|
|
|
)),
|
|
|
|
_ => Err(wrong_tuple_length(t, 2))
|
|
|
|
}
|
|
|
|
}
|
2015-10-25 16:55:29 +00:00
|
|
|
}*/
|
2015-01-11 17:56:59 +00:00
|
|
|
));
|
|
|
|
|
|
|
|
tuple_conversion!(1, (ref0, 0, A));
|
|
|
|
tuple_conversion!(2, (ref0, 0, A), (ref1, 1, B));
|
|
|
|
tuple_conversion!(3, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C));
|
|
|
|
tuple_conversion!(4, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D));
|
|
|
|
tuple_conversion!(5, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
|
|
|
|
(ref4, 4, E));
|
|
|
|
tuple_conversion!(6, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
|
|
|
|
(ref4, 4, E), (ref5, 5, F));
|
|
|
|
tuple_conversion!(7, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
|
|
|
|
(ref4, 4, E), (ref5, 5, F), (ref6, 6, G));
|
|
|
|
tuple_conversion!(8, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
|
|
|
|
(ref4, 4, E), (ref5, 5, F), (ref6, 6, G), (ref7, 7, H));
|
|
|
|
tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
|
|
|
|
(ref4, 4, E), (ref5, 5, F), (ref6, 6, G), (ref7, 7, H), (ref8, 8, I));
|
|
|
|
|
|
|
|
// Empty tuple:
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// An empty struct that represents the empty argument list.
|
|
|
|
/// Corresponds to the empty tuple `()` in Python.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// let gil_guard = cpython::Python::acquire_gil();
|
|
|
|
/// let py = gil_guard.python();
|
|
|
|
/// let os = py.import("os").unwrap();
|
2015-10-25 16:55:29 +00:00
|
|
|
/// let pid = os.call("get_pid", cpython::NoArgs, None, py);
|
2015-06-27 20:45:35 +00:00
|
|
|
/// ```
|
2015-10-25 16:55:29 +00:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2015-01-11 17:56:59 +00:00
|
|
|
pub struct NoArgs;
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Converts `NoArgs` to an empty Python tuple.
|
2015-10-25 16:55:29 +00:00
|
|
|
impl ToPyObject for NoArgs {
|
|
|
|
type ObjectType = PyTuple;
|
2015-01-11 17:56:59 +00:00
|
|
|
|
2015-10-25 16:55:29 +00:00
|
|
|
fn to_py_object(&self, py: Python) -> PyTuple {
|
2015-04-18 23:07:14 +00:00
|
|
|
PyTuple::empty(py)
|
2015-01-11 17:56:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
|
|
|
|
/// Otherwise, returns an error.
|
2015-10-25 16:55:29 +00:00
|
|
|
extract!(obj to NoArgs; py => {
|
|
|
|
let t = try!(obj.cast_as::<PyTuple>(py));
|
2015-07-18 20:39:55 +00:00
|
|
|
if t.len() == 0 {
|
|
|
|
Ok(NoArgs)
|
|
|
|
} else {
|
2015-10-25 16:55:29 +00:00
|
|
|
Err(wrong_tuple_length(t, 0, py))
|
2015-01-11 17:56:59 +00:00
|
|
|
}
|
2015-07-18 20:39:55 +00:00
|
|
|
});
|
2015-01-11 17:56:59 +00:00
|
|
|
|