miniextendr_api/list/
named.rs1use std::collections::HashMap;
8
9use crate::from_r::{SexpError, TryFromSexp};
10use crate::into_r::IntoR;
11use crate::{SEXP, SexpExt};
12
13use super::List;
14
15pub struct NamedList {
37 list: List,
38 index: HashMap<String, usize>,
39}
40
41impl NamedList {
42 pub fn new(list: List) -> Option<Self> {
47 list.names()?;
49 let n: usize = list
50 .len()
51 .try_into()
52 .expect("list length must be non-negative");
53 let mut index = HashMap::with_capacity(n);
54
55 for (i, s) in list.text_names() {
56 if !s.is_empty() && !index.contains_key(s) {
57 let i: usize = i.try_into().expect("list position is non-negative");
58 index.insert(s.to_owned(), i);
59 }
60 }
61
62 Some(NamedList { list, index })
63 }
64
65 #[inline]
71 pub fn get<T>(&self, name: &str) -> Option<T>
72 where
73 T: TryFromSexp,
74 {
75 let &idx = self.index.get(name)?;
76 let idx_isize: isize = idx.try_into().ok()?;
77 let elem = self.list.as_sexp().vector_elt(idx_isize);
78 T::try_from_sexp(elem).ok()
79 }
80
81 #[inline]
83 pub fn get_raw(&self, name: &str) -> Option<SEXP> {
84 let &idx = self.index.get(name)?;
85 let idx_isize: isize = idx.try_into().ok()?;
86 Some(self.list.as_sexp().vector_elt(idx_isize))
87 }
88
89 #[inline]
93 pub fn get_index<T>(&self, idx: isize) -> Option<T>
94 where
95 T: TryFromSexp,
96 {
97 self.list.get_index(idx)
98 }
99
100 #[inline]
102 pub fn contains(&self, name: &str) -> bool {
103 self.index.contains_key(name)
104 }
105
106 #[inline]
108 pub fn len(&self) -> isize {
109 self.list.len()
110 }
111
112 #[inline]
114 pub fn is_empty(&self) -> bool {
115 self.list.is_empty()
116 }
117
118 #[inline]
120 pub fn named_len(&self) -> usize {
121 self.index.len()
122 }
123
124 #[inline]
126 pub fn as_list(&self) -> List {
127 self.list
128 }
129
130 #[inline]
132 pub fn into_list(self) -> List {
133 self.list
134 }
135
136 pub fn names(&self) -> impl Iterator<Item = &str> {
138 self.index.keys().map(|s| s.as_str())
139 }
140
141 pub fn entries(&self) -> impl Iterator<Item = (&str, usize)> {
143 self.index.iter().map(|(k, &v)| (k.as_str(), v))
144 }
145}
146
147impl IntoR for NamedList {
148 type Error = std::convert::Infallible;
149 fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
150 Ok(self.into_sexp())
151 }
152 unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
153 self.try_into_sexp()
154 }
155 #[inline]
156 fn into_sexp(self) -> SEXP {
157 self.list.into_sexp()
158 }
159}
160
161impl TryFromSexp for NamedList {
162 type Error = SexpError;
163
164 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
165 let list = List::try_from_sexp(sexp)?;
166 NamedList::new(list)
167 .ok_or_else(|| SexpError::InvalidValue("list has no names attribute".into()))
168 }
169}
170
171impl TryFromSexp for Option<NamedList> {
172 type Error = SexpError;
173
174 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
175 if sexp == SEXP::nil() {
176 return Ok(None);
177 }
178 let named = NamedList::try_from_sexp(sexp)?;
179 Ok(Some(named))
180 }
181}
182
183