microscope_memory/
types.rs1use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use std::fmt;
5use std::str::FromStr;
6
7#[repr(C)]
10#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
11pub struct ProjectId(pub [u8; 16]);
12
13impl ProjectId {
14 pub const GLOBAL: Self = ProjectId([0u8; 16]);
16
17 pub fn from_path(path: &str) -> Self {
19 let hash = blake3::hash(path.as_bytes());
20 let mut bytes = [0u8; 16];
21 bytes.copy_from_slice(&hash.as_bytes()[..16]);
22 ProjectId(bytes)
23 }
24
25 pub fn is_global(&self) -> bool {
27 self.0 == [0u8; 16]
28 }
29}
30
31impl fmt::Display for ProjectId {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 for b in &self.0 {
34 write!(f, "{:02x}", b)?;
35 }
36 Ok(())
37 }
38}
39
40impl FromStr for ProjectId {
41 type Err = String;
42
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 if s.eq_ignore_ascii_case("global") {
45 return Ok(ProjectId::GLOBAL);
46 }
47 let s = s.trim_start_matches("0x");
48 if s.len() != 32 {
49 return Err(format!("ProjectId must be 32 hex chars, got {}", s.len()));
50 }
51 let mut bytes = [0u8; 16];
52 for (i, chunk) in s.as_bytes().chunks(2).enumerate() {
53 let chunk =
54 std::str::from_utf8(chunk).map_err(|_| "invalid utf-8 in hex".to_string())?;
55 bytes[i] = u8::from_str_radix(chunk, 16).map_err(|e| format!("invalid hex: {}", e))?;
56 }
57 Ok(ProjectId(bytes))
58 }
59}
60
61impl Serialize for ProjectId {
62 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63 serializer.serialize_str(&self.to_string())
64 }
65}
66
67impl<'de> Deserialize<'de> for ProjectId {
68 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
69 let s = String::deserialize(deserializer)?;
70 ProjectId::from_str(&s).map_err(serde::de::Error::custom)
71 }
72}
73
74#[repr(C, packed)]
80#[derive(Clone, Copy, Debug)]
81pub struct BlockHeader {
82 pub x: f32,
83 pub y: f32,
84 pub z: f32,
85 pub zoom: f32,
86 pub depth: u8,
87 pub layer_id: u8,
88 pub data_offset: u32,
89 pub data_len: u16,
90 pub parent_idx: u32,
91 pub child_count: u16,
92 pub crc16: [u8; 2],
93 pub project_id: ProjectId,
94 pub importance: u8,
95 pub flags: u8,
96}
97
98pub type MemoryBlockHeader = BlockHeader;
100
101impl BlockHeader {
102 #[inline(always)]
104 pub fn is_visible_to(&self, active: ProjectId, include_global: bool) -> bool {
105 self.project_id == active || (include_global && self.project_id.is_global())
106 }
107}
108
109#[derive(Clone)]
111pub struct MemoryQueryOptions {
112 pub active_project: ProjectId,
113 pub include_global: bool,
114 pub min_importance: u8,
115 pub max_results: usize,
116}
117
118impl Default for MemoryQueryOptions {
119 fn default() -> Self {
120 Self {
121 active_project: ProjectId::GLOBAL,
122 include_global: true,
123 min_importance: 0,
124 max_results: usize::MAX,
125 }
126 }
127}
128
129#[repr(C, packed)]
131#[derive(Clone, Copy)]
132#[allow(dead_code)]
133pub struct MetaHeader {
134 pub magic: [u8; 4],
135 pub version: u32,
136 pub block_count: u32,
137 pub depth_count: u32,
138}
139
140pub struct AppendEntry {
142 pub text: String,
143 pub layer_id: u8,
144 pub importance: u8,
145 pub depth: u8,
146 pub x: f32,
147 pub y: f32,
148 pub z: f32,
149 pub emotion: [f32; 21],
150 pub project_id: ProjectId,
151}