Skip to main content

superinstance_ffi/
encoding.rs

1/// Quantize a 2D direction to one of 48 evenly-spaced angles (7.5° increments).
2/// Returns a u8 in [0, 47].
3#[no_mangle]
4pub extern "C" fn si_pythagorean48_encode(x: f64, y: f64) -> u8 {
5    let angle = y.atan2(x); // [-π, π]
6    let normalized = if angle < 0.0 { angle + 2.0 * std::f64::consts::PI } else { angle };
7    let index = (normalized / (2.0 * std::f64::consts::PI) * 48.0).round() as u8;
8    index % 48
9}
10
11/// Manhattan distance between two integer vectors.
12#[no_mangle]
13pub extern "C" fn si_manhattan_distance(a: *const i32, b: *const i32, len: usize) -> i64 {
14    if a.is_null() || b.is_null() || len == 0 {
15        return 0;
16    }
17    let sa = unsafe { std::slice::from_raw_parts(a, len) };
18    let sb = unsafe { std::slice::from_raw_parts(b, len) };
19    sa.iter().zip(sb.iter()).map(|(x, y)| (x - y).abs() as i64).sum()
20}
21
22/// Cascade matching: count matching bytes between query and a single codebook entry.
23/// Returns number of matching positions.
24#[no_mangle]
25pub extern "C" fn si_cascade_match(query: *const u8, codebook: *const u8, len: usize) -> i32 {
26    if query.is_null() || codebook.is_null() || len == 0 {
27        return 0;
28    }
29    let sq = unsafe { std::slice::from_raw_parts(query, len) };
30    let sc = unsafe { std::slice::from_raw_parts(codebook, len) };
31    sq.iter().zip(sc.iter()).filter(|(a, b)| a == b).count() as i32
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn test_pythagorean48_zero() {
40        assert_eq!(si_pythagorean48_encode(1.0, 0.0), 0);
41    }
42
43    #[test]
44    fn test_pythagorean48_up() {
45        let idx = si_pythagorean48_encode(0.0, 1.0);
46        assert_eq!(idx, 12); // 90° = 12 * 7.5°
47    }
48
49    #[test]
50    fn test_manhattan_basic() {
51        let a = [1, 2, 3];
52        let b = [4, 0, 3];
53        assert_eq!(si_manhattan_distance(a.as_ptr(), b.as_ptr(), 3), 3 + 2 + 0);
54    }
55
56    #[test]
57    fn test_manhattan_null() {
58        assert_eq!(si_manhattan_distance(std::ptr::null(), std::ptr::null(), 0), 0);
59    }
60
61    #[test]
62    fn test_cascade_match_all() {
63        let q = [1u8, 2, 3, 4];
64        let c = [1u8, 2, 3, 4];
65        assert_eq!(si_cascade_match(q.as_ptr(), c.as_ptr(), 4), 4);
66    }
67
68    #[test]
69    fn test_cascade_match_none() {
70        let q = [1u8, 2, 3, 4];
71        let c = [5u8, 6, 7, 8];
72        assert_eq!(si_cascade_match(q.as_ptr(), c.as_ptr(), 4), 0);
73    }
74
75    #[test]
76    fn test_cascade_match_partial() {
77        let q = [1u8, 2, 3, 4];
78        let c = [1u8, 9, 3, 9];
79        assert_eq!(si_cascade_match(q.as_ptr(), c.as_ptr(), 4), 2);
80    }
81}