use super::*;
use crate::robj::Attributes;
use extendr_ffi::{dataptr, R_xlen_t, SET_VECTOR_ELT, VECTOR_ELT};
use std::{collections::HashMap, iter::FromIterator};
#[derive(PartialEq, Clone)]
pub struct List {
pub(crate) robj: Robj,
}
impl Default for List {
fn default() -> Self {
List::new(0)
}
}
impl List {
pub fn new(size: usize) -> Self {
let robj = Robj::alloc_vector(SEXPTYPE::VECSXP, size);
Self { robj }
}
pub fn from_values<V>(values: V) -> Self
where
V: IntoIterator,
V::IntoIter: ExactSizeIterator,
V::Item: Into<Robj>,
{
Self {
robj: make_vector(SEXPTYPE::VECSXP, values),
}
}
pub fn from_pairs<V>(pairs: V) -> Self
where
V: IntoIterator,
V::IntoIter: ExactSizeIterator + Clone,
V::Item: KeyValue,
{
let iter = pairs.into_iter();
let mut names = Vec::with_capacity(iter.len());
let mut values = Vec::with_capacity(iter.len());
for pair in iter {
names.push(pair.key());
values.push(pair.value());
}
let mut res = List::from_values(values);
res.as_robj_mut()
.set_names(names)
.unwrap()
.as_list()
.unwrap()
}
#[deprecated(
since = "0.8.1",
note = "Use `List::try_from(map)` or `map.try_into()` instead"
)]
pub fn from_hashmap<K, V>(val: HashMap<K, V>) -> Result<Self>
where
V: IntoRobj,
K: Into<String>,
{
val.try_into()
}
pub fn from_names_and_values<N, V>(names: N, values: V) -> Result<Self>
where
N: IntoIterator,
N::IntoIter: ExactSizeIterator,
N::Item: ToVectorValue + AsRef<str>,
V: IntoIterator,
V::IntoIter: ExactSizeIterator,
V::Item: Into<Robj>,
{
let mut list = List::from_values(values);
list.set_names(names)?;
Ok(list)
}
pub fn values(&self) -> ListIter {
ListIter::from_parts(self.robj.clone(), 0, self.robj.len())
}
pub fn iter(&self) -> NamedListIter {
self.names()
.map(|n| n.zip(self.values()))
.unwrap_or_else(|| StrIter::new(self.len()).zip(self.values()))
}
pub fn as_slice(&self) -> &[Robj] {
unsafe {
let data = dataptr(self.robj.get()) as *const Robj;
let len = self.robj.len();
std::slice::from_raw_parts(data, len)
}
}
pub fn elt(&self, i: usize) -> Result<Robj> {
if i >= self.robj.len() {
Err(Error::OutOfRange(self.robj.clone()))
} else {
unsafe {
let sexp = VECTOR_ELT(self.robj.get(), i as R_xlen_t);
Ok(Robj::from_sexp(sexp))
}
}
}
pub fn set_elt(&mut self, i: usize, value: Robj) -> Result<()> {
single_threaded(|| unsafe {
if i >= self.robj.len() {
Err(Error::OutOfRange(self.robj.clone()))
} else {
SET_VECTOR_ELT(self.robj.get_mut(), i as R_xlen_t, value.get());
Ok(())
}
})
}
#[deprecated(
since = "0.8.1",
note = "Use `HashMap::try_from(list)` or `list.try_into()` instead"
)]
pub fn into_hashmap(self) -> HashMap<&'static str, Robj> {
self.try_into().unwrap()
}
}
impl<T> TryFrom<&List> for HashMap<&str, T>
where
T: TryFrom<Robj, Error = error::Error>,
{
type Error = Error;
fn try_from(value: &List) -> Result<Self> {
let value = value
.iter()
.map(|(name, value)| -> Result<(&str, T)> { value.try_into().map(|x| (name, x)) })
.collect::<Result<HashMap<_, _>>>()?;
Ok(value)
}
}
impl<T> TryFrom<&List> for HashMap<String, T>
where
T: TryFrom<Robj, Error = error::Error>,
{
type Error = Error;
fn try_from(value: &List) -> Result<Self> {
let value: HashMap<&str, _> = value.try_into()?;
Ok(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}
}
impl TryFrom<&List> for HashMap<&str, Robj> {
type Error = Error;
fn try_from(value: &List) -> Result<Self> {
Ok(value.iter().collect())
}
}
impl TryFrom<&List> for HashMap<String, Robj> {
type Error = Error;
fn try_from(value: &List) -> Result<Self> {
let value: HashMap<&str, _> = value.try_into()?;
Ok(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
}
}
impl<T> TryFrom<List> for HashMap<&str, T>
where
T: TryFrom<Robj, Error = error::Error>,
{
type Error = Error;
fn try_from(value: List) -> Result<Self> {
(&value).try_into()
}
}
impl<T> TryFrom<List> for HashMap<String, T>
where
T: TryFrom<Robj, Error = error::Error>,
{
type Error = Error;
fn try_from(value: List) -> Result<Self> {
(&value).try_into()
}
}
impl TryFrom<List> for HashMap<&str, Robj> {
type Error = Error;
fn try_from(value: List) -> Result<Self> {
(&value).try_into()
}
}
impl TryFrom<List> for HashMap<String, Robj> {
type Error = Error;
fn try_from(value: List) -> Result<Self> {
(&value).try_into()
}
}
impl<K, V> TryFrom<HashMap<K, V>> for List
where
K: Into<String>,
V: IntoRobj,
{
type Error = Error;
fn try_from(val: HashMap<K, V>) -> Result<Self> {
let (names, values): (Vec<_>, Vec<_>) = val
.into_iter()
.map(|(k, v)| (k.into(), v.into_robj()))
.unzip();
let mut res: Self = Self::from_values(values);
res.set_names(names)?;
Ok(res)
}
}
impl IntoIterator for List {
type IntoIter = NamedListIter;
type Item = (&'static str, Robj);
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone)]
pub struct ListIter {
robj: Robj,
i: usize,
len: usize,
}
impl Default for ListIter {
fn default() -> Self {
ListIter::new()
}
}
impl ListIter {
pub fn new() -> Self {
ListIter::from_parts(().into(), 0, 0)
}
pub(crate) fn from_parts(robj: Robj, i: usize, len: usize) -> Self {
Self { robj, i, len }
}
}
impl Iterator for ListIter {
type Item = Robj;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
fn next(&mut self) -> Option<Self::Item> {
let i = self.i;
self.i += 1;
if i >= self.len {
None
} else {
Some(unsafe { Robj::from_sexp(VECTOR_ELT(self.robj.get(), i as isize)) })
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.i += n;
self.next()
}
}
impl ExactSizeIterator for ListIter {
fn len(&self) -> usize {
self.len - self.i
}
}
pub struct FromList<T>(pub T);
impl<T> TryFrom<&Robj> for FromList<Vec<T>>
where
T: TryFrom<Robj>,
<T as TryFrom<Robj>>::Error: Into<Error>,
{
type Error = Error;
fn try_from(robj: &Robj) -> Result<Self> {
let listiter: ListIter = robj.try_into()?;
let res: Result<Vec<_>> = listiter
.map(|robj| T::try_from(robj).map_err(|e| e.into()))
.collect();
res.map(FromList)
}
}
impl<T> TryFrom<Robj> for FromList<Vec<T>>
where
T: TryFrom<Robj>,
<T as TryFrom<Robj>>::Error: Into<Error>,
{
type Error = Error;
fn try_from(robj: Robj) -> Result<Self> {
<FromList<Vec<T>>>::try_from(&robj)
}
}
impl TryFrom<&Robj> for ListIter {
type Error = Error;
fn try_from(robj: &Robj) -> Result<Self> {
let list: List = robj.try_into()?;
Ok(list.values())
}
}
impl TryFrom<Robj> for ListIter {
type Error = Error;
fn try_from(robj: Robj) -> Result<Self> {
<ListIter>::try_from(&robj)
}
}
impl From<ListIter> for Robj {
fn from(iter: ListIter) -> Self {
iter.robj
}
}
pub trait KeyValue {
fn key(&self) -> String;
fn value(self) -> Robj;
}
impl<T: AsRef<str>> KeyValue for (T, Robj) {
fn key(&self) -> String {
self.0.as_ref().to_owned()
}
fn value(self) -> Robj {
self.1
}
}
impl<T: Into<Robj>> FromIterator<T> for List {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let iter_collect: Vec<_> = iter.into_iter().collect();
let len = iter_collect.len();
crate::single_threaded(|| unsafe {
let mut robj = Robj::alloc_vector(SEXPTYPE::VECSXP, len);
for (i, v) in iter_collect.into_iter().enumerate() {
let item: Robj = v.into();
SET_VECTOR_ELT(robj.get_mut(), i as isize, item.get());
}
List { robj }
})
}
}
impl Attributes for List {}
impl Deref for List {
type Target = [Robj];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl std::fmt::Debug for List {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.names().is_none() {
write!(
f,
"list!({})",
self.values()
.map(|v| format!("{:?}", v))
.collect::<Vec<_>>()
.join(", ")
)
} else {
write!(
f,
"list!({})",
self.iter()
.map(|(k, v)| if !k.is_empty() {
format!("{}={:?}", k, v)
} else {
format!("{:?}", v)
})
.collect::<Vec<_>>()
.join(", ")
)
}
}
}