Skip to main content

microscope_memory/
lib.rs

1//! Microscope Memory library interface.
2//! Re-exports core types and functions for integration tests and external use.
3
4pub mod archetype;
5pub mod attention;
6pub mod build;
7#[cfg(not(target_arch = "wasm32"))]
8pub mod cache;
9pub mod config;
10pub mod embedding_index;
11pub mod embeddings;
12pub mod emotional;
13#[cfg(not(target_arch = "wasm32"))]
14pub mod federation;
15pub mod fingerprint;
16pub mod hebbian;
17
18pub mod merkle;
19pub mod mirror;
20pub mod query;
21pub mod reader;
22pub mod resonance;
23pub mod sequential_thinking;
24pub mod snapshot;
25
26pub mod dream;
27pub mod emotional_contagion;
28pub mod multimodal;
29pub mod predictive_cache;
30pub mod temporal_archetype;
31pub mod thought_graph;
32pub mod viz;
33
34#[cfg(target_arch = "wasm32")]
35pub mod wasm;
36
37#[cfg(feature = "python")]
38#[allow(non_local_definitions)]
39pub mod python;
40
41#[cfg(feature = "gpu")]
42pub mod gpu;
43
44pub mod cli;
45
46// Re-export commonly used items
47pub use reader::{
48    read_append_log, store_memory, AppendEntry, BlockHeader, DataStore, MicroscopeReader,
49    RadialResult, ResultSet,
50};
51
52// Re-export CLI
53pub use cli::{Cli, Cmd};
54
55// ─── Shared constants ────────────────────────────────
56pub const DEFAULT_CONFIG_PATH: &str = "config.toml";
57pub const BLOCK_DATA_SIZE: usize = 256;
58pub const HEADER_SIZE: usize = 32;
59pub const META_HEADER_SIZE: usize = 16;
60pub const DEPTH_ENTRY_SIZE: usize = 8;
61pub const LAYER_NAMES: &[&str] = &[
62    "identity",
63    "long_term",
64    "short_term",
65    "associative",
66    "emotional",
67    "relational",
68    "reflections",
69    "crypto_chain",
70    "echo_cache",
71    "rust_state",
72];
73
74// ─── Shared utility functions ────────────────────────
75
76pub fn layer_to_id(name: &str) -> u8 {
77    LAYER_NAMES.iter().position(|&n| n == name).unwrap_or(0) as u8
78}
79
80/// CRC16-CCITT (poly=0x1021, init=0xFFFF) over arbitrary data.
81pub fn crc16_ccitt(data: &[u8]) -> u16 {
82    let mut crc: u16 = 0xFFFF;
83    for &byte in data {
84        crc ^= (byte as u16) << 8;
85        for _ in 0..8 {
86            if crc & 0x8000 != 0 {
87                crc = (crc << 1) ^ 0x1021;
88            } else {
89                crc <<= 1;
90            }
91        }
92    }
93    crc
94}
95
96pub fn content_coords(text: &str, layer: &str) -> (f32, f32, f32) {
97    let mut h: [u64; 3] = [0xcbf29ce484222325, 0x100000001b3, 0xa5a5a5a5a5a5a5a5];
98    for &b in text.as_bytes().iter().take(128) {
99        h[0] = h[0].wrapping_mul(0x100000001b3) ^ b as u64;
100        h[1] = h[1].wrapping_mul(0x100000001b3) ^ b as u64;
101        h[2] = h[2].wrapping_mul(0x1000193) ^ b as u64;
102    }
103    let bx = (h[0] & 0xFFFF) as f32 / 65535.0;
104    let by = (h[1] & 0xFFFF) as f32 / 65535.0;
105    let bz = (h[2] & 0xFFFF) as f32 / 65535.0;
106
107    let (ox, oy, oz) = match layer {
108        "long_term" => (0.0, 0.0, 0.0),
109        "associative" => (0.3, 0.0, 0.0),
110        "emotional" => (0.0, 0.3, 0.0),
111        "relational" => (0.3, 0.3, 0.0),
112        "reflections" => (0.0, 0.0, 0.3),
113        "crypto_chain" => (0.3, 0.0, 0.3),
114        "echo_cache" => (0.0, 0.3, 0.3),
115        "short_term" => (0.15, 0.15, 0.15),
116        "rust_state" => (0.15, 0.0, 0.15),
117        _ => (0.25, 0.25, 0.25),
118    };
119
120    (ox + bx * 0.25, oy + by * 0.25, oz + bz * 0.25)
121}
122
123fn semantic_coords(text: &str, weight: f32) -> Option<(f32, f32, f32)> {
124    if weight <= 0.0 {
125        return None;
126    }
127    use embeddings::{EmbeddingProvider, MockEmbeddingProvider};
128    let provider = MockEmbeddingProvider::new(128);
129    if let Ok(emb) = provider.embed(text) {
130        if emb.len() >= 3 {
131            let sx = (emb[0] + 1.0) / 2.0;
132            let sy = (emb[1] + 1.0) / 2.0;
133            let sz = (emb[2] + 1.0) / 2.0;
134            return Some((sx, sy, sz));
135        }
136    }
137    None
138}
139
140pub fn content_coords_blended(text: &str, layer: &str, weight: f32) -> (f32, f32, f32) {
141    let (hx, hy, hz) = content_coords(text, layer);
142    if weight <= 0.0 {
143        return (hx, hy, hz);
144    }
145    match semantic_coords(text, weight) {
146        Some((sx, sy, sz)) => {
147            let w = weight.clamp(0.0, 1.0);
148            (
149                (1.0 - w) * hx + w * sx,
150                (1.0 - w) * hy + w * sy,
151                (1.0 - w) * hz + w * sz,
152            )
153        }
154        None => (hx, hy, hz),
155    }
156}
157
158pub fn hex_str(bytes: &[u8]) -> String {
159    bytes
160        .iter()
161        .map(|b| format!("{:02x}", b))
162        .collect::<Vec<_>>()
163        .join("")
164}
165
166pub fn safe_truncate(s: &str, max_bytes: usize) -> String {
167    if s.len() <= max_bytes {
168        return s.to_string();
169    }
170    let mut end = max_bytes;
171    while end > 0 && !s.is_char_boundary(end) {
172        end -= 1;
173    }
174    s[..end].to_string()
175}
176
177pub fn to_block(text: &str) -> Vec<u8> {
178    let bytes = text.as_bytes();
179    if bytes.len() <= BLOCK_DATA_SIZE {
180        bytes.to_vec()
181    } else {
182        let mut v = bytes[..BLOCK_DATA_SIZE - 3].to_vec();
183        v.extend_from_slice(b"...");
184        v
185    }
186}
187
188// ─── AUTO ZOOM / AUTO DEPTH ──────────────────────────
189
190pub fn auto_zoom(query: &str) -> (u8, u8) {
191    let stopwords = ["a", "the", "is", "of", "and", "to", "in", "it", "on", "for"];
192    let unique_content_words = query
193        .to_lowercase()
194        .split_whitespace()
195        .filter(|w| !stopwords.contains(w) && w.len() > 2)
196        .count();
197
198    if unique_content_words <= 1 {
199        return (1, 1);
200    }
201    if unique_content_words <= 3 {
202        return (2, 1);
203    }
204    if unique_content_words <= 6 {
205        return (3, 1);
206    }
207    if unique_content_words <= 10 {
208        return (4, 1);
209    }
210    (5, 1)
211}
212
213pub fn auto_depth(text: &str) -> u8 {
214    let len = text.len();
215    if len >= 100 {
216        3
217    } else if len >= 40 {
218        4
219    } else if len >= 15 {
220        5
221    } else {
222        6
223    }
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229
230    #[test]
231    fn test_crc16_ccitt_known_vector() {
232        let data = b"123456789";
233        assert_eq!(crc16_ccitt(data), 0x29B1);
234    }
235
236    #[test]
237    fn test_crc16_empty() {
238        assert_eq!(crc16_ccitt(b""), 0xFFFF);
239    }
240
241    #[test]
242    fn test_crc16_deterministic() {
243        let a = crc16_ccitt(b"hello world");
244        let b = crc16_ccitt(b"hello world");
245        assert_eq!(a, b);
246        assert_ne!(a, crc16_ccitt(b"hello worl!"));
247    }
248}