use crate::c::{
_SpiceDataType_SPICE_BOOL, _SpiceDataType_SPICE_CHR, _SpiceDataType_SPICE_DP,
_SpiceDataType_SPICE_INT, _SpiceDataType_SPICE_TIME, SpiceCell, SpiceCellDataType, SpiceChar,
SpiceDouble, SpiceInt,
};
use crate::core::ffi::{from_cbuf, to_cstring, CELL_CTRLSZ};
use std::fmt;
use std::marker::PhantomData;
use std::ops::Deref;
pub const CELL_MAX_LEN: usize = crate::MAX_LEN_OUT;
pub const CELL_MAXID: usize = 10_000;
pub trait CellItem: Sized {
const DTYPE: SpiceCellDataType;
type Raw: Copy + Default;
fn read(slot: &[Self::Raw]) -> Self;
fn append(cell: &mut Cell<Self>, item: Self);
}
pub struct Cell<T: CellItem> {
raw: SpiceCell,
buf: Vec<T::Raw>,
elem: usize,
_marker: PhantomData<fn() -> T>,
}
impl<T: CellItem> Cell<T> {
pub fn new(size: usize) -> Self {
Self::with_length(size, CELL_MAX_LEN)
}
pub fn with_length(size: usize, length: usize) -> Self {
Self::build(T::DTYPE, size, length)
}
fn build(dtype: SpiceCellDataType, size: usize, length: usize) -> Self {
let character = dtype == _SpiceDataType_SPICE_CHR;
let elem = if character { length.max(1) } else { 1 };
let mut buf = vec![T::Raw::default(); (CELL_CTRLSZ + size) * elem];
let base = buf.as_mut_ptr();
Self {
raw: SpiceCell {
dtype,
length: if character { elem as SpiceInt } else { 0 },
size: size as SpiceInt,
card: 0,
isSet: 1,
adjust: 0,
init: 0,
base: base.cast(),
data: unsafe { base.add(CELL_CTRLSZ * elem) }.cast(),
},
buf,
elem,
_marker: PhantomData,
}
}
pub fn len(&self) -> usize {
self.raw.card.max(0) as usize
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
self.raw.size.max(0) as usize
}
pub fn get(&self, index: usize) -> Option<T> {
if index >= self.len() {
return None;
}
let start = (CELL_CTRLSZ + index) * self.elem;
Some(T::read(&self.buf[start..start + self.elem]))
}
pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
(0..self.len()).filter_map(move |index| self.get(index))
}
pub fn to_vec(&self) -> Vec<T> {
self.iter().collect()
}
pub fn push(&mut self, item: T) {
T::append(self, item);
}
pub fn clear(&mut self) {
let cell = self.as_mut_ptr();
unsafe { crate::c::scard_c(0, cell) };
}
pub fn as_ptr(&self) -> *const SpiceCell {
&self.raw
}
pub fn as_mut_ptr(&mut self) -> *mut SpiceCell {
let base = self.buf.as_mut_ptr();
self.raw.base = base.cast();
self.raw.data = unsafe { base.add(CELL_CTRLSZ * self.elem) }.cast();
&mut self.raw
}
}
impl Cell<i32> {
pub fn new_int(size: i32) -> Self {
Self::new(size.max(0) as usize)
}
pub fn new_bool(size: i32) -> Self {
Self::build(_SpiceDataType_SPICE_BOOL, size.max(0) as usize, 0)
}
pub fn get_data_int(&self, index: usize) -> i32 {
self.get(index).unwrap_or_default()
}
pub fn get_data_bool(&self, index: usize) -> i32 {
self.get_data_int(index)
}
}
impl Cell<f64> {
pub fn new_double(size: i32) -> Self {
Self::new(size.max(0) as usize)
}
pub fn new_time(size: i32) -> Self {
Self::build(_SpiceDataType_SPICE_TIME, size.max(0) as usize, 0)
}
pub fn get_data_double(&self, index: usize) -> f64 {
self.get(index).unwrap_or_default()
}
}
impl Cell<String> {
pub fn new_character(size: i32, length: i32) -> Self {
Self::with_length(size.max(0) as usize, length.max(1) as usize)
}
pub fn get_data_character(&self, index: usize) -> String {
self.get(index).unwrap_or_default()
}
}
impl CellItem for i32 {
const DTYPE: SpiceCellDataType = _SpiceDataType_SPICE_INT;
type Raw = SpiceInt;
fn read(slot: &[Self::Raw]) -> Self {
slot[0]
}
fn append(cell: &mut Cell<Self>, item: Self) {
let raw = cell.as_mut_ptr();
unsafe { crate::c::appndi_c(item, raw) };
}
}
impl CellItem for f64 {
const DTYPE: SpiceCellDataType = _SpiceDataType_SPICE_DP;
type Raw = SpiceDouble;
fn read(slot: &[Self::Raw]) -> Self {
slot[0]
}
fn append(cell: &mut Cell<Self>, item: Self) {
let raw = cell.as_mut_ptr();
unsafe { crate::c::appndd_c(item, raw) };
}
}
impl CellItem for String {
const DTYPE: SpiceCellDataType = _SpiceDataType_SPICE_CHR;
type Raw = SpiceChar;
fn read(slot: &[Self::Raw]) -> Self {
from_cbuf(slot)
}
fn append(cell: &mut Cell<Self>, item: String) {
let item = to_cstring(item);
let raw = cell.as_mut_ptr();
unsafe { crate::c::appndc_c(item.as_ptr() as *mut SpiceChar, raw) };
}
}
impl<T: CellItem> Deref for Cell<T> {
type Target = SpiceCell;
fn deref(&self) -> &Self::Target {
&self.raw
}
}
impl<T: CellItem> Clone for Cell<T> {
fn clone(&self) -> Self {
let mut clone = Self {
raw: self.raw,
buf: self.buf.clone(),
elem: self.elem,
_marker: PhantomData,
};
clone.as_mut_ptr();
clone
}
}
impl<T: CellItem + fmt::Debug> fmt::Debug for Cell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Cell")
.field("card", &self.len())
.field("size", &self.capacity())
.field("items", &self.to_vec())
.finish()
}
}
unsafe impl<T: CellItem + Send> Send for Cell<T> {}