use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ScalarKind {
Bool,
U8,
I8,
U16,
I16,
U32,
I32,
U64,
I64,
F32,
F64,
String,
}
impl ScalarKind {
#[must_use]
pub fn natural_align(self) -> usize {
match self {
ScalarKind::Bool | ScalarKind::U8 | ScalarKind::I8 => 1,
ScalarKind::U16 | ScalarKind::I16 => 2,
ScalarKind::U32 | ScalarKind::I32 | ScalarKind::F32 | ScalarKind::String => 4,
ScalarKind::U64 | ScalarKind::I64 | ScalarKind::F64 => 8,
}
}
#[must_use]
pub fn xcdr2_align(self) -> usize {
self.natural_align().min(4)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Member {
pub name: String,
pub kind: ScalarKind,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TypeShape {
pub name: String,
pub members: Vec<Member>,
#[serde(default)]
pub appendable: bool,
}
impl TypeShape {
#[must_use]
pub fn index_of(&self, name: &str) -> Option<usize> {
self.members.iter().position(|m| m.name == name)
}
#[must_use]
pub fn has(&self, name: &str) -> bool {
self.index_of(name).is_some()
}
}
#[derive(Debug, Clone, Default)]
pub struct TypeRegistry {
shapes: BTreeMap<String, TypeShape>,
}
impl TypeRegistry {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, shape: TypeShape) -> &mut Self {
self.shapes.insert(shape.name.clone(), shape);
self
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&TypeShape> {
self.shapes.get(name)
}
pub fn from_json(s: &str) -> crate::error::Result<Self> {
let shapes: Vec<TypeShape> = serde_json::from_str(s)
.map_err(|e| crate::error::RoutingError::Config(format!("type shapes json: {e}")))?;
let mut reg = Self::new();
for sh in shapes {
reg.insert(sh);
}
Ok(reg)
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn align_rules() {
assert_eq!(ScalarKind::U64.natural_align(), 8);
assert_eq!(ScalarKind::U64.xcdr2_align(), 4);
assert_eq!(ScalarKind::U16.xcdr2_align(), 2);
assert_eq!(ScalarKind::String.natural_align(), 4);
}
#[test]
fn registry_json() {
let js =
r#"[{"name":"T","members":[{"name":"a","kind":"u32"},{"name":"b","kind":"string"}]}]"#;
let reg = TypeRegistry::from_json(js).unwrap();
let sh = reg.get("T").unwrap();
assert_eq!(sh.members.len(), 2);
assert_eq!(sh.index_of("b"), Some(1));
assert!(!sh.appendable);
}
}