use std::iter::IntoIterator;
use std::mem;
use std::ops::Deref;
use crate::pytypes::PyArg;
#[derive(Clone, Debug, PartialEq)]
pub struct PyTuple {
pub(crate) elem: PyArg,
pub(crate) idx: usize,
pub(crate) next: Option<Box<PyTuple>>,
}
#[allow(clippy::len_without_is_empty)]
impl<'a> PyTuple {
#[doc(hidden)]
pub fn new(elem: PyArg, idx: usize, next: Option<Box<PyTuple>>) -> PyTuple {
PyTuple { elem, idx, next }
}
#[doc(hidden)]
pub fn set_next(&mut self, next: Option<Box<PyTuple>>) {
self.next = next;
}
pub unsafe fn from_ptr(ptr: *mut PyTuple) -> PyTuple {
*(Box::from_raw(ptr))
}
pub(crate) fn as_mut(&mut self, idx: usize) -> Result<&mut PyArg, &str> {
if idx == self.idx {
Ok(&mut self.elem)
} else {
match self.next {
Some(ref mut e) => (**e).as_mut(idx),
None => Err("PyTuple index out of range."),
}
}
}
#[doc(hidden)]
pub fn replace_elem(&mut self, idx: usize) -> Result<PyArg, &str> {
if idx == self.idx {
let e = mem::replace(&mut self.elem, PyArg::None);
Ok(e)
} else {
match self.next {
Some(ref mut e) => (**e).replace_elem(idx),
None => Err("PyTuple index out of range."),
}
}
}
pub(crate) fn as_ref(&self, idx: usize) -> Result<&PyArg, &str> {
if idx == self.idx {
Ok(&self.elem)
} else {
match self.next {
Some(ref e) => (**e).as_ref(idx),
None => Err("PyTuple index out of range."),
}
}
}
fn push(&mut self, next: PyTuple) {
self.next = Some(Box::new(next));
}
pub fn len(&self) -> usize {
match self.next {
Some(ref e) => e.len(),
None => self.idx + 1,
}
}
pub fn into_raw(self) -> *mut PyTuple {
Box::into_raw(Box::new(self))
}
}
impl<'a> IntoIterator for &'a PyTuple {
type Item = &'a PyArg;
type IntoIter = ::std::vec::IntoIter<&'a PyArg>;
fn into_iter(self) -> Self::IntoIter {
let l = self.len();
let mut iter = Vec::with_capacity(l);
for i in 0..l {
iter.push(self.as_ref(i).unwrap());
}
iter.into_iter()
}
}
impl Deref for PyTuple {
type Target = PyArg;
fn deref(&self) -> &PyArg {
&self.elem
}
}
#[macro_export]
macro_rules! pytuple {
( $( $elem:ident ),+ ) => {{
use rustypy::PyTuple;
let mut cnt;
let mut tuple = Vec::new();
cnt = 0usize;
$(
let tuple_e = PyTuple::new(
$elem,
cnt,
None,
);
tuple.push(tuple_e);
cnt += 1;
)*;
if cnt == tuple.len() {}; let t_len = tuple.len() - 1;
for i in 1..(t_len + 1) {
let idx = t_len - i;
let last = tuple.pop().unwrap();
let prev = tuple.get_mut(idx).unwrap();
prev.set_next(Some(Box::new(last)));
}
tuple.pop().unwrap()
}};
( $( $elem:expr ),+ ) => {{
use rustypy::PyTuple;
let mut cnt;
let mut tuple = Vec::new();
cnt = 0usize;
$(
let tuple_e = PyTuple::new(
$elem,
cnt,
None,
);
tuple.push(tuple_e);
cnt += 1;
)*;
let t_len = cnt - 1;
for i in 1..cnt {
let idx = t_len - i;
let last = tuple.pop().unwrap();
let prev = tuple.get_mut(idx).unwrap();
prev.set_next(Some(Box::new(last)));
}
tuple.pop().unwrap()
}};
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn pytuple_new(idx: usize, elem: *mut PyArg) -> *mut PyTuple {
let tuple = PyTuple {
elem: *(Box::from_raw(elem)),
idx,
next: None,
};
tuple.into_raw()
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn pytuple_push(next: *mut PyTuple, prev: &mut PyTuple) {
let next: PyTuple = *(Box::from_raw(next));
prev.push(next)
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn pytuple_free(ptr: *mut PyTuple) {
if ptr.is_null() {
return;
}
Box::from_raw(ptr);
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn pytuple_len(ptr: *mut PyTuple) -> usize {
let tuple = &*ptr;
tuple.len()
}
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn pytuple_get_element(ptr: *mut PyTuple, index: usize) -> *mut PyArg {
let tuple = &mut *ptr;
let elem = &PyTuple::as_mut(tuple, index).unwrap();
let copied: PyArg = (*elem).clone();
Box::into_raw(Box::new(copied))
}