Skip to main content

omwei_atom/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4#[cfg(all(not(feature = "std"), feature = "serde"))]
5extern crate alloc;
6
7#[cfg(all(not(feature = "std"), feature = "serde"))]
8use alloc::{string::String, vec::Vec};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13// --- [Constants stay the same as in your version] ---
14pub const TRUST_RAW: u8 = 0x00;
15pub const TRUST_VERIFIED: u8 = 0x01;
16pub const TRUST_ANOMALY: u8 = 0x02;
17pub const TRUST_ENTERPRISE: u8 = 0xFF;
18
19pub const PREDICATE_NORMAL: u32 = 0x00000001;
20pub const PREDICATE_WARNING: u32 = 0x00000002;
21pub const PREDICATE_CRITICAL: u32 = 0x00000003;
22pub const PREDICATE_CONSISTENCY: u32 = 0x00000004;
23pub const PREDICATE_TRIANGULATED: u32 = 0x00000005;
24pub const PREDICATE_ANOMALY: u32 = 0x00000006;
25pub const PREDICATE_TREND_STABLE: u32 = 0x00000007;
26pub const PREDICATE_TREND_RISING_FAST: u32 = 0x00000008;
27pub const PREDICATE_SENSOR_STUCK_WARNING: u32 = 0x00000009;
28pub const PREDICATE_API_DATA_INCONSISTENCY: u32 = 0x0000000A;
29pub const PREDICATE_POTENTIAL_DATA_ANOMALY: u32 = 0x0000000B;
30
31pub const TELEMETRY_WATER_LEVEL_MM: u16 = 0x0001;
32pub const TELEMETRY_TEMPERATURE_C: u16 = 0x0002;
33pub const TELEMETRY_HUMIDITY_PERCENT: u16 = 0x0003;
34pub const TELEMETRY_PRESSURE_PA: u16 = 0x0004;
35pub const TELEMETRY_PRECIPITATION_MM: u16 = 0x0005;
36
37pub const HEADER_VERIFIED: u16 = 0x8000;
38pub const HEADER_SIGNED: u16 = 0x4000;
39pub const HEADER_ENCRYPTED: u16 = 0x2000;
40pub const HEADER_RAW_DATA: u16 = 0x0001;
41
42pub const TAG_HYDROLOGICAL: u32 = 0x000001;
43pub const TAG_METEOROLOGICAL: u32 = 0x000002;
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47#[repr(C)]
48pub struct SemanticAtom {
49    pub entity_id: u32,
50    pub telemetry_info: u32,
51    pub predicate_id: u32,
52    pub value_mm: u32,
53    pub timestamp_us: u64,
54    pub tag_trust: u32,
55    pub pqc_anchor: u32,
56}
57
58impl SemanticAtom {
59    #[inline]
60    pub fn new(
61        entity_id: u32,
62        telemetry_type: u16,
63        predicate_id: u32,
64        value_mm: u32,
65        timestamp_us: u64,
66        tag_id: u32,
67        trust_level: u8,
68    ) -> Self {
69        let telemetry_info = (telemetry_type as u32) << 16;
70        let tag_trust = ((tag_id & 0x00FFFFFF) << 8) | (trust_level as u32);
71
72        Self {
73            entity_id,
74            telemetry_info,
75            predicate_id,
76            value_mm,
77            timestamp_us,
78            tag_trust,
79            pqc_anchor: 0,
80        }
81    }
82
83    #[inline]
84    pub fn telemetry_type(&self) -> u16 {
85        (self.telemetry_info >> 16) as u16
86    }
87    #[inline]
88    pub fn tag_id(&self) -> u32 {
89        self.tag_trust >> 8
90    }
91    #[inline]
92    pub fn trust_level(&self) -> u8 {
93        (self.tag_trust & 0xFF) as u8
94    }
95    #[inline]
96    pub fn set_pqc_anchor(&mut self, anchor: u32) {
97        self.pqc_anchor = anchor;
98    }
99
100    #[inline]
101    pub fn is_critical_or_warning(&self) -> bool {
102        matches!(
103            self.predicate_id,
104            PREDICATE_WARNING
105                | PREDICATE_CRITICAL
106                | PREDICATE_API_DATA_INCONSISTENCY
107                | PREDICATE_POTENTIAL_DATA_ANOMALY
108        )
109    }
110
111    #[inline]
112    pub fn get_value(&self) -> f64 {
113        self.value_mm as f64 / 100.0
114    }
115
116    #[inline]
117    pub fn to_bytes(&self) -> [u8; 32] {
118        let mut bytes = [0u8; 32];
119        bytes[0..4].copy_from_slice(&self.entity_id.to_le_bytes());
120        bytes[4..8].copy_from_slice(&self.telemetry_info.to_le_bytes());
121        bytes[8..12].copy_from_slice(&self.predicate_id.to_le_bytes());
122        bytes[12..16].copy_from_slice(&self.value_mm.to_le_bytes());
123        bytes[16..24].copy_from_slice(&self.timestamp_us.to_le_bytes());
124        bytes[24..28].copy_from_slice(&self.tag_trust.to_le_bytes());
125        bytes[28..32].copy_from_slice(&self.pqc_anchor.to_le_bytes());
126        bytes
127    }
128
129    pub fn from_bytes(bytes: &[u8]) -> Result<Self, &'static str> {
130        if bytes.len() != 32 {
131            return Err("Invalid length");
132        }
133        Ok(Self {
134            entity_id: u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
135            telemetry_info: u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
136            predicate_id: u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
137            value_mm: u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
138            timestamp_us: u64::from_le_bytes([
139                bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22],
140                bytes[23],
141            ]),
142            tag_trust: u32::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]),
143            pqc_anchor: u32::from_le_bytes([bytes[28], bytes[29], bytes[30], bytes[31]]),
144        })
145    }
146
147    #[cfg(feature = "pqc")]
148    pub fn compute_hash(&self) -> [u8; 32] {
149        use sha2::{Digest, Sha256};
150        let mut hasher = Sha256::new();
151        hasher.update(self.to_bytes());
152        hasher.finalize().into()
153    }
154}
155
156// --- [Error Handling - Fixed for no_std] ---
157
158#[derive(Debug, Clone, PartialEq)]
159#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
160pub enum AtomError {
161    InvalidAtom(&'static str),
162    InvalidEntity(u32),
163    InvalidPredicate(u32),
164    PhysicsViolation(&'static str),
165    InvalidTimestamp,
166    CryptographicError(&'static str),
167    InvalidLength(usize),
168}
169
170impl core::fmt::Display for AtomError {
171    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
172        match self {
173            AtomError::InvalidAtom(msg) => write!(f, "Invalid atom: {}", msg),
174            AtomError::InvalidEntity(id) => write!(f, "Invalid entity ID: 0x{:08X}", id),
175            AtomError::InvalidPredicate(id) => write!(f, "Invalid predicate ID: 0x{:08X}", id),
176            AtomError::PhysicsViolation(msg) => write!(f, "Physics violation: {}", msg),
177            AtomError::InvalidTimestamp => write!(f, "Invalid timestamp"),
178            AtomError::CryptographicError(msg) => write!(f, "Cryptographic error: {}", msg),
179            AtomError::InvalidLength(len) => write!(f, "Invalid length: {} (expected 32)", len),
180        }
181    }
182}
183
184#[cfg(feature = "std")]
185impl std::error::Error for AtomError {}
186
187pub type BsaResult<T> = Result<T, AtomError>;
188
189// --- [Optional Helper Structures - Fixed for no_std/serde] ---
190
191#[cfg(feature = "serde")]
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct Entity {
194    pub id: u32,
195    pub name: String,
196    pub description: String,
197    pub source: Option<String>,
198}
199
200#[cfg(feature = "serde")]
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct Predicate {
203    pub id: u32,
204    pub name: String,
205    pub description: String,
206    pub tag: String,
207}
208
209#[cfg(feature = "serde")]
210#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct Config {
212    pub entities: Vec<Entity>,
213    pub predicates: Vec<Predicate>,
214}