1use crc32fast::Hasher;
26use std::os::raw::c_char;
27use std::slice;
28
29#[repr(C)]
31pub struct HasherHandle(*mut Hasher);
32
33#[no_mangle]
35pub extern "C" fn hasher_new() -> *mut HasherHandle {
36 let hasher = Box::new(Hasher::new());
37 let handle = Box::new(HasherHandle(Box::into_raw(hasher)));
38 Box::into_raw(handle)
39}
40
41#[no_mangle]
47pub unsafe extern "C" fn hasher_write(handle: *mut HasherHandle, data: *const c_char, len: usize) {
48 if handle.is_null() || data.is_null() {
49 return;
50 }
51
52 let hasher = &mut *(*handle).0;
53 let bytes = slice::from_raw_parts(data as *const u8, len);
54 hasher.update(bytes);
55}
56
57#[no_mangle]
63pub unsafe extern "C" fn hasher_finalize(handle: *mut HasherHandle) -> u32 {
64 if handle.is_null() {
65 return 0;
66 }
67
68 let handle = Box::from_raw(handle);
69 let hasher = Box::from_raw(handle.0);
70 hasher.finalize()
71}
72
73#[no_mangle]
75pub extern "C" fn crc32_hash(data: *const c_char, len: usize) -> u32 {
76 if data.is_null() {
77 return 0;
78 }
79
80 unsafe {
81 let bytes = slice::from_raw_parts(data as *const u8, len);
82 crc32fast::hash(bytes)
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use std::ptr;
90
91 #[test]
92 fn test_hasher_lifecycle() {
93 unsafe {
94 let handle = hasher_new();
95 assert!(!handle.is_null(), "Hasher creation failed");
96
97 let data = b"123456789";
98 hasher_write(handle, data.as_ptr() as *const c_char, data.len());
99
100 let sum = hasher_finalize(handle);
101 assert_eq!(sum, 0xCBF43926, "CRC32 calculation incorrect");
102 }
103 }
104
105 #[test]
106 fn test_simple_hash() {
107 let data = b"123456789";
108 let sum = crc32_hash(data.as_ptr() as *const c_char, data.len());
109 assert_eq!(sum, 0xCBF43926, "Direct hash calculation incorrect");
110 }
111
112 #[test]
113 fn test_null_handling() {
114 unsafe {
115 hasher_write(ptr::null_mut(), b"test".as_ptr() as *const c_char, 4);
116 assert_eq!(
117 hasher_finalize(ptr::null_mut()),
118 0,
119 "Null handle should return 0"
120 );
121 assert_eq!(crc32_hash(ptr::null(), 0), 0, "Null data should return 0");
122 }
123 }
124
125 #[test]
126 fn test_empty_data() {
127 let sum = crc32_hash(b"".as_ptr() as *const c_char, 0);
128 assert_eq!(sum, 0, "Empty data should produce 0");
129 }
130
131 #[test]
132 fn test_incremental_update() {
133 unsafe {
134 let handle = hasher_new();
135
136 let data = "hello world";
138 for byte in data.bytes() {
139 hasher_write(handle, &byte as *const u8 as *const c_char, 1);
140 }
141
142 let sum = hasher_finalize(handle);
143 let direct_sum = crc32_hash(data.as_ptr() as *const c_char, data.len());
144 assert_eq!(sum, direct_sum, "Incremental update failed");
145 }
146 }
147}