1use crate::c::{
29 _SpiceDataType_SPICE_BOOL, _SpiceDataType_SPICE_CHR, _SpiceDataType_SPICE_DP,
30 _SpiceDataType_SPICE_INT, _SpiceDataType_SPICE_TIME, SpiceCell, SpiceCellDataType, SpiceChar,
31 SpiceDouble, SpiceInt,
32};
33use crate::core::ffi::{from_cbuf, to_cstring, CELL_CTRLSZ};
34use std::fmt;
35use std::marker::PhantomData;
36use std::ops::Deref;
37
38pub const CELL_MAX_LEN: usize = crate::MAX_LEN_OUT;
40
41pub const CELL_MAXID: usize = 10_000;
43
44pub trait CellItem: Sized {
52 const DTYPE: SpiceCellDataType;
54
55 type Raw: Copy + Default;
57
58 fn read(slot: &[Self::Raw]) -> Self;
60
61 fn append(cell: &mut Cell<Self>, item: Self);
63}
64
65pub struct Cell<T: CellItem> {
71 raw: SpiceCell,
73 buf: Vec<T::Raw>,
75 elem: usize,
77 _marker: PhantomData<fn() -> T>,
78}
79
80impl<T: CellItem> Cell<T> {
81 pub fn new(size: usize) -> Self {
87 Self::with_length(size, CELL_MAX_LEN)
88 }
89
90 pub fn with_length(size: usize, length: usize) -> Self {
96 Self::build(T::DTYPE, size, length)
97 }
98
99 fn build(dtype: SpiceCellDataType, size: usize, length: usize) -> Self {
101 let character = dtype == _SpiceDataType_SPICE_CHR;
102 let elem = if character { length.max(1) } else { 1 };
103
104 let mut buf = vec![T::Raw::default(); (CELL_CTRLSZ + size) * elem];
105 let base = buf.as_mut_ptr();
106
107 Self {
108 raw: SpiceCell {
109 dtype,
110 length: if character { elem as SpiceInt } else { 0 },
111 size: size as SpiceInt,
112 card: 0,
113 isSet: 1,
114 adjust: 0,
115 init: 0,
116 base: base.cast(),
117 data: unsafe { base.add(CELL_CTRLSZ * elem) }.cast(),
119 },
120 buf,
121 elem,
122 _marker: PhantomData,
123 }
124 }
125
126 pub fn len(&self) -> usize {
128 self.raw.card.max(0) as usize
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.len() == 0
134 }
135
136 pub fn capacity(&self) -> usize {
138 self.raw.size.max(0) as usize
139 }
140
141 pub fn get(&self, index: usize) -> Option<T> {
143 if index >= self.len() {
144 return None;
145 }
146 let start = (CELL_CTRLSZ + index) * self.elem;
147 Some(T::read(&self.buf[start..start + self.elem]))
148 }
149
150 pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
152 (0..self.len()).filter_map(move |index| self.get(index))
153 }
154
155 pub fn to_vec(&self) -> Vec<T> {
157 self.iter().collect()
158 }
159
160 pub fn push(&mut self, item: T) {
162 T::append(self, item);
163 }
164
165 pub fn clear(&mut self) {
167 let cell = self.as_mut_ptr();
168 unsafe { crate::c::scard_c(0, cell) };
169 }
170
171 pub fn as_ptr(&self) -> *const SpiceCell {
173 &self.raw
174 }
175
176 pub fn as_mut_ptr(&mut self) -> *mut SpiceCell {
183 let base = self.buf.as_mut_ptr();
184 self.raw.base = base.cast();
185 self.raw.data = unsafe { base.add(CELL_CTRLSZ * self.elem) }.cast();
187 &mut self.raw
188 }
189}
190
191impl Cell<i32> {
192 pub fn new_int(size: i32) -> Self {
194 Self::new(size.max(0) as usize)
195 }
196
197 pub fn new_bool(size: i32) -> Self {
199 Self::build(_SpiceDataType_SPICE_BOOL, size.max(0) as usize, 0)
200 }
201
202 pub fn get_data_int(&self, index: usize) -> i32 {
204 self.get(index).unwrap_or_default()
205 }
206
207 pub fn get_data_bool(&self, index: usize) -> i32 {
209 self.get_data_int(index)
210 }
211}
212
213impl Cell<f64> {
214 pub fn new_double(size: i32) -> Self {
216 Self::new(size.max(0) as usize)
217 }
218
219 pub fn new_time(size: i32) -> Self {
221 Self::build(_SpiceDataType_SPICE_TIME, size.max(0) as usize, 0)
222 }
223
224 pub fn get_data_double(&self, index: usize) -> f64 {
226 self.get(index).unwrap_or_default()
227 }
228}
229
230impl Cell<String> {
231 pub fn new_character(size: i32, length: i32) -> Self {
233 Self::with_length(size.max(0) as usize, length.max(1) as usize)
234 }
235
236 pub fn get_data_character(&self, index: usize) -> String {
238 self.get(index).unwrap_or_default()
239 }
240}
241
242impl CellItem for i32 {
243 const DTYPE: SpiceCellDataType = _SpiceDataType_SPICE_INT;
244 type Raw = SpiceInt;
245
246 fn read(slot: &[Self::Raw]) -> Self {
247 slot[0]
248 }
249
250 fn append(cell: &mut Cell<Self>, item: Self) {
251 let raw = cell.as_mut_ptr();
252 unsafe { crate::c::appndi_c(item, raw) };
253 }
254}
255
256impl CellItem for f64 {
257 const DTYPE: SpiceCellDataType = _SpiceDataType_SPICE_DP;
258 type Raw = SpiceDouble;
259
260 fn read(slot: &[Self::Raw]) -> Self {
261 slot[0]
262 }
263
264 fn append(cell: &mut Cell<Self>, item: Self) {
265 let raw = cell.as_mut_ptr();
266 unsafe { crate::c::appndd_c(item, raw) };
267 }
268}
269
270impl CellItem for String {
271 const DTYPE: SpiceCellDataType = _SpiceDataType_SPICE_CHR;
272 type Raw = SpiceChar;
273
274 fn read(slot: &[Self::Raw]) -> Self {
275 from_cbuf(slot)
276 }
277
278 fn append(cell: &mut Cell<Self>, item: String) {
279 let item = to_cstring(item);
280 let raw = cell.as_mut_ptr();
281 unsafe { crate::c::appndc_c(item.as_ptr() as *mut SpiceChar, raw) };
282 }
283}
284
285impl<T: CellItem> Deref for Cell<T> {
287 type Target = SpiceCell;
288
289 fn deref(&self) -> &Self::Target {
290 &self.raw
291 }
292}
293
294impl<T: CellItem> Clone for Cell<T> {
295 fn clone(&self) -> Self {
296 let mut clone = Self {
297 raw: self.raw,
298 buf: self.buf.clone(),
299 elem: self.elem,
300 _marker: PhantomData,
301 };
302 clone.as_mut_ptr();
304 clone
305 }
306}
307
308impl<T: CellItem + fmt::Debug> fmt::Debug for Cell<T> {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 f.debug_struct("Cell")
311 .field("card", &self.len())
312 .field("size", &self.capacity())
313 .field("items", &self.to_vec())
314 .finish()
315 }
316}
317
318unsafe impl<T: CellItem + Send> Send for Cell<T> {}