#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(all(not(feature = "std"), feature = "serde"))]
extern crate alloc;
#[cfg(all(not(feature = "std"), feature = "serde"))]
use alloc::{string::String, vec::Vec};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub mod trust_hierarchy;
pub const TRUST_RAW: u8 = 0x00;
pub const TRUST_VERIFIED: u8 = 0x01;
pub const TRUST_ANOMALY: u8 = 0x02;
pub const TRUST_ENTERPRISE: u8 = 0xFF;
pub const PREDICATE_NORMAL: u32 = 0x00000001;
pub const PREDICATE_WARNING: u32 = 0x00000002;
pub const PREDICATE_CRITICAL: u32 = 0x00000003;
pub const PREDICATE_CONSISTENCY: u32 = 0x00000004;
pub const PREDICATE_TRIANGULATED: u32 = 0x00000005;
pub const PREDICATE_ANOMALY: u32 = 0x00000006;
pub const PREDICATE_TREND_STABLE: u32 = 0x00000007;
pub const PREDICATE_TREND_RISING_FAST: u32 = 0x00000008;
pub const PREDICATE_SENSOR_STUCK_WARNING: u32 = 0x00000009;
pub const PREDICATE_API_DATA_INCONSISTENCY: u32 = 0x0000000A;
pub const PREDICATE_POTENTIAL_DATA_ANOMALY: u32 = 0x0000000B;
pub const TELEMETRY_WATER_LEVEL_MM: u16 = 0x0001;
pub const TELEMETRY_TEMPERATURE_C: u16 = 0x0002;
pub const TELEMETRY_HUMIDITY_PERCENT: u16 = 0x0003;
pub const TELEMETRY_PRESSURE_PA: u16 = 0x0004;
pub const TELEMETRY_PRECIPITATION_MM: u16 = 0x0005;
pub const HEADER_VERIFIED: u16 = 0x8000;
pub const HEADER_SIGNED: u16 = 0x4000;
pub const HEADER_ENCRYPTED: u16 = 0x2000;
pub const HEADER_RAW_DATA: u16 = 0x0001;
pub const TAG_HYDROLOGICAL: u32 = 0x000001;
pub const TAG_METEOROLOGICAL: u32 = 0x000002;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct SemanticAtom {
pub entity_id: u32,
pub telemetry_info: u32,
pub predicate_id: u32,
pub value_mm: u32,
pub timestamp_us: u64,
pub tag_trust: u32,
pub pqc_anchor: u32,
}
impl SemanticAtom {
#[inline]
pub fn new(
entity_id: u32,
telemetry_type: u16,
predicate_id: u32,
value_mm: u32,
timestamp_us: u64,
tag_id: u32,
trust_level: u8,
) -> Self {
let telemetry_info = (telemetry_type as u32) << 16;
let tag_trust = ((tag_id & 0x00FFFFFF) << 8) | (trust_level as u32);
Self {
entity_id,
telemetry_info,
predicate_id,
value_mm,
timestamp_us,
tag_trust,
pqc_anchor: 0,
}
}
#[inline]
pub fn telemetry_type(&self) -> u16 {
(self.telemetry_info >> 16) as u16
}
#[inline]
pub fn tag_id(&self) -> u32 {
self.tag_trust >> 8
}
#[inline]
pub fn trust_level(&self) -> u8 {
(self.tag_trust & 0xFF) as u8
}
#[inline]
pub fn set_pqc_anchor(&mut self, anchor: u32) {
self.pqc_anchor = anchor;
}
#[inline]
pub fn is_critical_or_warning(&self) -> bool {
matches!(
self.predicate_id,
PREDICATE_WARNING
| PREDICATE_CRITICAL
| PREDICATE_API_DATA_INCONSISTENCY
| PREDICATE_POTENTIAL_DATA_ANOMALY
)
}
#[inline]
pub fn get_value(&self) -> f64 {
self.value_mm as f64 / 100.0
}
#[inline]
pub fn to_bytes(&self) -> [u8; 32] {
let mut bytes = [0u8; 32];
bytes[0..4].copy_from_slice(&self.entity_id.to_le_bytes());
bytes[4..8].copy_from_slice(&self.telemetry_info.to_le_bytes());
bytes[8..12].copy_from_slice(&self.predicate_id.to_le_bytes());
bytes[12..16].copy_from_slice(&self.value_mm.to_le_bytes());
bytes[16..24].copy_from_slice(&self.timestamp_us.to_le_bytes());
bytes[24..28].copy_from_slice(&self.tag_trust.to_le_bytes());
bytes[28..32].copy_from_slice(&self.pqc_anchor.to_le_bytes());
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, &'static str> {
if bytes.len() != 32 {
return Err("Invalid length");
}
Ok(Self {
entity_id: u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
telemetry_info: u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
predicate_id: u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
value_mm: u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
timestamp_us: u64::from_le_bytes([
bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22],
bytes[23],
]),
tag_trust: u32::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]),
pqc_anchor: u32::from_le_bytes([bytes[28], bytes[29], bytes[30], bytes[31]]),
})
}
#[cfg(feature = "pqc")]
pub fn compute_hash(&self) -> [u8; 32] {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(self.to_bytes());
hasher.finalize().into()
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AtomError {
InvalidAtom(&'static str),
InvalidEntity(u32),
InvalidPredicate(u32),
PhysicsViolation(&'static str),
InvalidTimestamp,
CryptographicError(&'static str),
InvalidLength(usize),
}
impl core::fmt::Display for AtomError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
AtomError::InvalidAtom(msg) => write!(f, "Invalid atom: {}", msg),
AtomError::InvalidEntity(id) => write!(f, "Invalid entity ID: 0x{:08X}", id),
AtomError::InvalidPredicate(id) => write!(f, "Invalid predicate ID: 0x{:08X}", id),
AtomError::PhysicsViolation(msg) => write!(f, "Physics violation: {}", msg),
AtomError::InvalidTimestamp => write!(f, "Invalid timestamp"),
AtomError::CryptographicError(msg) => write!(f, "Cryptographic error: {}", msg),
AtomError::InvalidLength(len) => write!(f, "Invalid length: {} (expected 32)", len),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for AtomError {}
pub type BsaResult<T> = Result<T, AtomError>;
#[cfg(feature = "serde")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entity {
pub id: u32,
pub name: String,
pub description: String,
pub source: Option<String>,
}
#[cfg(feature = "serde")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Predicate {
pub id: u32,
pub name: String,
pub description: String,
pub tag: String,
}
#[cfg(feature = "serde")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub entities: Vec<Entity>,
pub predicates: Vec<Predicate>,
}