use crate::foundation::{AlgoError, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Dtype {
F32,
F64,
U16,
U32,
}
impl Dtype {
pub fn size(self) -> usize {
match self {
Dtype::F32 | Dtype::U32 => 4,
Dtype::F64 => 8,
Dtype::U16 => 2,
}
}
pub fn as_str(self) -> &'static str {
match self {
Dtype::F32 => "f32",
Dtype::F64 => "f64",
Dtype::U16 => "u16",
Dtype::U32 => "u32",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "kind")]
pub enum LaneKind {
Slab {
elems_per_slab: u64,
},
Flat {
len: u64,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LaneSpec {
pub name: String,
pub dtype: Dtype,
#[serde(flatten)]
pub kind: LaneKind,
}
impl LaneSpec {
pub fn slab(name: impl Into<String>, dtype: Dtype, elems_per_slab: u64) -> Self {
LaneSpec {
name: name.into(),
dtype,
kind: LaneKind::Slab { elems_per_slab },
}
}
pub fn flat(name: impl Into<String>, dtype: Dtype, len: u64) -> Self {
LaneSpec {
name: name.into(),
dtype,
kind: LaneKind::Flat { len },
}
}
pub(crate) fn elem_count(&self, nslabs: u64) -> u64 {
match self.kind {
LaneKind::Slab { elems_per_slab } => nslabs * elems_per_slab,
LaneKind::Flat { len } => len,
}
}
pub(crate) fn byte_len(&self, nslabs: u64) -> u64 {
self.elem_count(nslabs) * self.dtype.size() as u64
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StoreSchema {
pub nslabs: u64,
pub lanes: Vec<LaneSpec>,
#[serde(default)]
pub app: serde_json::Value,
}
impl StoreSchema {
pub fn new(nslabs: u64, lanes: Vec<LaneSpec>) -> Self {
StoreSchema {
nslabs,
lanes,
app: serde_json::Value::Null,
}
}
pub fn with_app(mut self, app: serde_json::Value) -> Self {
self.app = app;
self
}
pub(crate) fn validate(&self) -> Result<()> {
if self.nslabs == 0 {
return Err(AlgoError::InvalidArgument(
"store nslabs must be > 0".into(),
));
}
for (i, lane) in self.lanes.iter().enumerate() {
if lane.name.is_empty() {
return Err(AlgoError::InvalidArgument(format!(
"store lane {i} has an empty name"
)));
}
let elems = match lane.kind {
LaneKind::Slab { elems_per_slab } => elems_per_slab,
LaneKind::Flat { len } => len,
};
if elems == 0 {
return Err(AlgoError::InvalidArgument(format!(
"store lane '{}' has zero elements",
lane.name
)));
}
if self.lanes[..i].iter().any(|o| o.name == lane.name) {
return Err(AlgoError::InvalidArgument(format!(
"store lane name '{}' is not unique",
lane.name
)));
}
}
Ok(())
}
pub(crate) fn lane_index(&self, name: &str) -> Result<usize> {
self.lanes
.iter()
.position(|l| l.name == name)
.ok_or_else(|| AlgoError::NotFound(format!("store lane '{name}'")))
}
}