use crate::context::frame::Basis;
use crate::error::StorageError;
use crate::types::{FrameID, Hash};
use blake3::Hasher;
pub fn compute_frame_id(
basis: &Basis,
content: &[u8],
frame_type: &str,
agent_id: &str,
) -> Result<FrameID, StorageError> {
let basis_hash = compute_basis_hash(basis)?;
let mut hasher = Hasher::new();
hasher.update(&basis_hash);
hasher.update(b"agent:");
hasher.update(agent_id.as_bytes());
hasher.update(b"type:");
hasher.update(frame_type.as_bytes());
hasher.update(b"content:");
hasher.update(content);
Ok(*hasher.finalize().as_bytes())
}
pub fn compute_basis_hash(basis: &Basis) -> Result<Hash, StorageError> {
let mut hasher = Hasher::new();
match basis {
Basis::Node(node_id) => {
hasher.update(b"node:");
hasher.update(node_id);
}
Basis::Frame(frame_id) => {
hasher.update(b"frame:");
hasher.update(frame_id);
}
Basis::Both { node, frame } => {
hasher.update(b"both:");
hasher.update(node);
hasher.update(frame);
}
}
Ok(*hasher.finalize().as_bytes())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_id_deterministic() {
let basis = Basis::Node([1u8; 32]);
let content = b"test content";
let frame_type = "analysis";
let agent_id = "test-agent";
let frame_id1 = compute_frame_id(&basis, content, frame_type, agent_id).unwrap();
let frame_id2 = compute_frame_id(&basis, content, frame_type, agent_id).unwrap();
assert_eq!(frame_id1, frame_id2);
}
#[test]
fn test_frame_id_different_content_different_id() {
let basis = Basis::Node([1u8; 32]);
let content1 = b"test content";
let content2 = b"different content";
let frame_type = "analysis";
let agent_id = "test-agent";
let frame_id1 = compute_frame_id(&basis, content1, frame_type, agent_id).unwrap();
let frame_id2 = compute_frame_id(&basis, content2, frame_type, agent_id).unwrap();
assert_ne!(frame_id1, frame_id2);
}
#[test]
fn test_frame_id_different_basis_different_id() {
let basis1 = Basis::Node([1u8; 32]);
let basis2 = Basis::Node([2u8; 32]);
let content = b"test content";
let frame_type = "analysis";
let agent_id = "test-agent";
let frame_id1 = compute_frame_id(&basis1, content, frame_type, agent_id).unwrap();
let frame_id2 = compute_frame_id(&basis2, content, frame_type, agent_id).unwrap();
assert_ne!(frame_id1, frame_id2);
}
#[test]
fn test_frame_id_different_agent_different_id() {
let basis = Basis::Node([1u8; 32]);
let content = b"test content";
let frame_type = "analysis";
let agent_id1 = "agent-1";
let agent_id2 = "agent-2";
let frame_id1 = compute_frame_id(&basis, content, frame_type, agent_id1).unwrap();
let frame_id2 = compute_frame_id(&basis, content, frame_type, agent_id2).unwrap();
assert_ne!(frame_id1, frame_id2);
}
#[test]
fn test_frame_id_both_basis() {
let basis = Basis::Both {
node: [1u8; 32],
frame: [2u8; 32],
};
let content = b"test content";
let frame_type = "analysis";
let agent_id = "test-agent";
let frame_id = compute_frame_id(&basis, content, frame_type, agent_id).unwrap();
let node_basis = Basis::Node([1u8; 32]);
let node_frame_id = compute_frame_id(&node_basis, content, frame_type, agent_id).unwrap();
assert_ne!(frame_id, node_frame_id);
}
}