physics_in_parallel 3.0.0

High-performance infrastructure for numerical simulations in physics
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;

pub trait ToJsonPayload {
    type Payload: Serialize;

    fn to_json_payload(&self) -> Result<Self::Payload, serde_json::Error>;

    fn to_json_value(&self) -> Result<Value, serde_json::Error> {
        serde_json::to_value(self.to_json_payload()?)
    }

    fn to_json_string(&self) -> Result<String, serde_json::Error> {
        serde_json::to_string_pretty(&self.to_json_payload()?)
    }
}

pub trait FromJsonPayload: Sized {
    type Payload: for<'de> Deserialize<'de>;

    fn from_json_payload(payload: Self::Payload) -> Result<Self, String>;
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlatPayload<T> {
    pub kind: String,
    pub shape: Vec<usize>,
    pub data: Vec<T>,
}

impl<T> FlatPayload<T> {
    pub fn new(kind: &str, shape: Vec<usize>, data: Vec<T>) -> Self {
        Self {
            kind: kind.to_string(),
            shape,
            data,
        }
    }

    pub fn validate_kind(&self, expected_kind: &str) -> Result<(), String> {
        if self.kind != expected_kind {
            return Err(format!("{expected_kind} kind must be '{expected_kind}'"));
        }
        Ok(())
    }
    pub fn validate_shape(&self, context: &str) -> Result<usize, String> {
        checked_num_elements(&self.shape, context)
    }

    pub fn validate_dense(&self, expected_kind: &str) -> Result<(), String> {
        self.validate_kind(expected_kind)?;
        let expected_len = self.validate_shape(expected_kind)?;
        if self.data.len() != expected_len {
            return Err(format!(
                "{expected_kind} data length mismatch: expected {expected_len}, got {}",
                self.data.len()
            ));
        }
        Ok(())
    }
}

pub fn checked_num_elements(shape: &[usize], context: &str) -> Result<usize, String> {
    if shape.is_empty() || shape.iter().any(|&dim| dim == 0) {
        return Err(format!(
            "{context} shape must contain only nonzero dimensions"
        ));
    }

    let mut expected_len = 1usize;
    for &dim in shape {
        expected_len = expected_len
            .checked_mul(dim)
            .ok_or_else(|| format!("{context} shape product overflow: {shape:?}"))?;
    }
    Ok(expected_len)
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LabeledPayload {
    pub label: String,
    pub payload: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttrsCorePayload {
    pub n_objects: Option<usize>,
    pub num_attrs: usize,
    pub attrs: Vec<LabeledPayload>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PhysObjPayload {
    pub meta: Value,
    pub core: AttrsCorePayload,
}

#[derive(Debug, Clone, Serialize)]
pub struct FlatPayloadRef<'a, T> {
    pub kind: &'a str,
    pub shape: &'a [usize],
    pub data: &'a [T],
}