1#![allow(non_camel_case_types)]
17
18use std::marker::{PhantomData, PhantomPinned};
19use std::os::raw::{c_char, c_int};
20
21pub const SEMQ_FILE_VERSION: u32 = 2;
27pub const SEMQ_RULE_REVISION: u32 = 0;
29pub const SEMQ_CONFIG_BYTES: u32 = 13;
31pub const SEMQ_DIGEST_BYTES: u32 = 32;
33pub const SEMQ_MAX_DIM: u32 = 65536;
35pub const SEMQ_ID_MAX_BYTES: u32 = 4096;
37pub const SEMQ_MANIFEST_MAX_PAIRS: u32 = 4096;
39pub const SEMQ_MANIFEST_KEY_MAX: u32 = 256;
40pub const SEMQ_MANIFEST_VALUE_MAX: u32 = 65536;
41pub const SEMQ_MANIFEST_SECTION_MAX: u32 = 16 * 1024 * 1024;
42pub const SEMQ_NONE: u64 = u64::MAX;
44
45pub type semq_operator_t = u32;
47pub const SEMQ_ORBIT: semq_operator_t = 0;
48pub const SEMQ_PHASE: semq_operator_t = 1;
49pub const SEMQ_QUANT: semq_operator_t = 2;
50
51pub type semq_id_kind_t = u32;
53pub const SEMQ_ID_U64: semq_id_kind_t = 0;
54pub const SEMQ_ID_UTF8: semq_id_kind_t = 1;
55
56pub type semq_status_t = u32;
58pub const SEMQ_OK: semq_status_t = 0;
59pub const SEMQ_ERR_INVALID_INPUT: semq_status_t = 1;
61pub const SEMQ_ERR_INCOMPATIBLE: semq_status_t = 2;
63pub const SEMQ_ERR_FORMAT: semq_status_t = 3;
65pub const SEMQ_ERR_INTEGRITY: semq_status_t = 4;
67pub const SEMQ_ERR_UNSUPPORTED: semq_status_t = 5;
69pub const SEMQ_ERR_NOMEM: semq_status_t = 6;
71pub const SEMQ_ERR_INTERNAL: semq_status_t = 7;
73
74pub type semq_which_t = u32;
76pub const SEMQ_WHICH_NONE: semq_which_t = 0;
77pub const SEMQ_WHICH_CONTENT: semq_which_t = 1;
78pub const SEMQ_WHICH_STATE: semq_which_t = 2;
79
80pub type semq_section_t = u32;
82pub const SEMQ_SECTION_FRAMING: semq_section_t = 0;
83pub const SEMQ_SECTION_CONFIG: semq_section_t = 1;
84pub const SEMQ_SECTION_SIZES: semq_section_t = 2;
85pub const SEMQ_SECTION_IDS: semq_section_t = 3;
86pub const SEMQ_SECTION_MANIFEST: semq_section_t = 4;
87pub const SEMQ_SECTION_FOOTER: semq_section_t = 5;
88pub const SEMQ_SECTION_ROWS: semq_section_t = 6;
89
90pub type semq_config_field_t = u32;
93pub const SEMQ_FIELD_OPERATOR: semq_config_field_t = 0;
94pub const SEMQ_FIELD_DIM: semq_config_field_t = 1;
95pub const SEMQ_FIELD_P1: semq_config_field_t = 2;
97pub const SEMQ_FIELD_P2: semq_config_field_t = 3;
98
99pub type semq_list_t = u32;
101pub const SEMQ_LIST_ADDED: semq_list_t = 0;
102pub const SEMQ_LIST_REMOVED: semq_list_t = 1;
103pub const SEMQ_LIST_CHANGED: semq_list_t = 2;
104
105#[repr(C)]
114#[derive(Debug, Clone, Copy)]
115pub struct semq_error_t {
116 pub status: u32,
117 pub which: u32,
118 pub row: u64,
119 pub field: u64,
120 pub message: [c_char; 128],
121}
122
123#[repr(C)]
126#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
127pub struct semq_config_t {
128 pub op: u32,
129 pub dim: u32,
130 pub p1: u32,
131 pub p2: u32,
132}
133
134#[repr(C)]
136#[derive(Debug, Clone, Copy)]
137pub struct semq_pair_t {
138 pub key: *const u8,
139 pub key_len: u32,
140 pub value: *const u8,
141 pub value_len: u32,
142}
143
144#[repr(C)]
149#[derive(Debug, Clone, Copy)]
150pub struct semq_ids_t {
151 pub kind: u32,
152 pub n: u64,
153 pub u64: *const u64,
154 pub utf8_offsets: *const u64,
155 pub utf8_bytes: *const u8,
156}
157
158#[repr(C)]
160#[derive(Debug, Clone, Copy)]
161pub struct semq_part_t {
162 pub ptr: *const u8,
163 pub len: u64,
164}
165
166#[repr(C)]
169#[derive(Debug, Clone, Copy)]
170pub struct semq_manifest_change_t {
171 pub key: *const u8,
172 pub key_len: u32,
173 pub has_before: c_int,
174 pub before: *const u8,
175 pub before_len: u32,
176 pub has_after: c_int,
177 pub after: *const u8,
178 pub after_len: u32,
179}
180
181#[repr(C)]
187pub struct semq_codec_t {
188 _data: [u8; 0],
189 _marker: PhantomData<(*mut u8, PhantomPinned)>,
190}
191
192#[repr(C)]
194pub struct semq_encoding_t {
195 _data: [u8; 0],
196 _marker: PhantomData<(*mut u8, PhantomPinned)>,
197}
198
199#[repr(C)]
201pub struct semq_diff_t {
202 _data: [u8; 0],
203 _marker: PhantomData<(*mut u8, PhantomPinned)>,
204}
205
206#[repr(C)]
208pub struct semq_floor_t {
209 _data: [u8; 0],
210 _marker: PhantomData<(*mut u8, PhantomPinned)>,
211}
212
213extern "C" {
218 pub fn semq_config_orbit(
220 dim: u32,
221 scale: u32,
222 out: *mut semq_config_t,
223 err: *mut semq_error_t,
224 ) -> semq_status_t;
225 pub fn semq_config_phase(
226 dim: u32,
227 sectors: u32,
228 out: *mut semq_config_t,
229 err: *mut semq_error_t,
230 ) -> semq_status_t;
231 pub fn semq_config_quant(
232 dim: u32,
233 bins: u32,
234 out: *mut semq_config_t,
235 err: *mut semq_error_t,
236 ) -> semq_status_t;
237 pub fn semq_config_validate(cfg: *const semq_config_t, err: *mut semq_error_t)
238 -> semq_status_t;
239 pub fn semq_config_to_bytes(cfg: *const semq_config_t, out: *mut u8);
241 pub fn semq_config_from_bytes(
243 input: *const u8,
244 out: *mut semq_config_t,
245 err: *mut semq_error_t,
246 ) -> semq_status_t;
247 pub fn semq_config_bytes_per_vector(cfg: *const semq_config_t) -> u32;
248 pub fn semq_config_units_per_row(cfg: *const semq_config_t) -> u32;
249 pub fn semq_config_max_magnitude(cfg: *const semq_config_t) -> f32;
251 pub fn semq_config_equal(a: *const semq_config_t, b: *const semq_config_t) -> c_int;
253
254 pub fn semq_codec_create(
256 cfg: *const semq_config_t,
257 out: *mut *mut semq_codec_t,
258 err: *mut semq_error_t,
259 ) -> semq_status_t;
260 pub fn semq_codec_free(codec: *mut semq_codec_t);
261 pub fn semq_codec_config(codec: *const semq_codec_t) -> *const semq_config_t;
262 pub fn semq_codec_backend(codec: *const semq_codec_t) -> *const c_char;
264 pub fn semq_codec_encode(
265 codec: *const semq_codec_t,
266 ids: *const semq_ids_t,
267 vectors: *const f32,
268 manifest: *const semq_pair_t,
269 n_pairs: u32,
270 out: *mut *mut semq_encoding_t,
271 err: *mut semq_error_t,
272 ) -> semq_status_t;
273 pub fn semq_codec_decode(
275 codec: *const semq_codec_t,
276 enc: *const semq_encoding_t,
277 out: *mut f32,
278 err: *mut semq_error_t,
279 ) -> semq_status_t;
280 pub fn semq_codec_unpack(
282 codec: *const semq_codec_t,
283 enc: *const semq_encoding_t,
284 out: *mut u8,
285 err: *mut semq_error_t,
286 ) -> semq_status_t;
287
288 pub fn semq_encoding_create(
290 cfg: *const semq_config_t,
291 ids: *const semq_ids_t,
292 rows: *const u8,
293 manifest: *const semq_pair_t,
294 n_pairs: u32,
295 out: *mut *mut semq_encoding_t,
296 err: *mut semq_error_t,
297 ) -> semq_status_t;
298 pub fn semq_encoding_free(enc: *mut semq_encoding_t);
299 pub fn semq_encoding_config(enc: *const semq_encoding_t) -> *const semq_config_t;
300 pub fn semq_encoding_id_kind(enc: *const semq_encoding_t) -> u32;
301 pub fn semq_encoding_len(enc: *const semq_encoding_t) -> u64;
302 pub fn semq_encoding_rows(enc: *const semq_encoding_t, len: *mut u64) -> *const u8;
304 pub fn semq_encoding_ids_u64(enc: *const semq_encoding_t) -> *const u64;
306 pub fn semq_encoding_ids_utf8_offsets(enc: *const semq_encoding_t) -> *const u64;
308 pub fn semq_encoding_ids_utf8_bytes(enc: *const semq_encoding_t, len: *mut u64) -> *const u8;
310 pub fn semq_encoding_manifest_len(enc: *const semq_encoding_t) -> u32;
312 pub fn semq_encoding_manifest_pair(
313 enc: *const semq_encoding_t,
314 i: u32,
315 out: *mut semq_pair_t,
316 err: *mut semq_error_t,
317 ) -> semq_status_t;
318 pub fn semq_encoding_content_digest(enc: *const semq_encoding_t, out: *mut u8);
319 pub fn semq_encoding_state_id(enc: *const semq_encoding_t, out: *mut u8);
320 pub fn semq_encoding_find_u64(
322 enc: *const semq_encoding_t,
323 id: u64,
324 index: *mut u64,
325 err: *mut semq_error_t,
326 ) -> semq_status_t;
327 pub fn semq_encoding_find_utf8(
328 enc: *const semq_encoding_t,
329 id: *const u8,
330 len: u64,
331 index: *mut u64,
332 err: *mut semq_error_t,
333 ) -> semq_status_t;
334 pub fn semq_encoding_file_size(enc: *const semq_encoding_t) -> u64;
336 pub fn semq_encoding_save_parts(enc: *const semq_encoding_t, parts: *mut semq_part_t) -> u32;
338 pub fn semq_encoding_save(
340 enc: *const semq_encoding_t,
341 out: *mut u8,
342 cap: u64,
343 err: *mut semq_error_t,
344 ) -> semq_status_t;
345 pub fn semq_encoding_load(
347 buf: *const u8,
348 len: u64,
349 out: *mut *mut semq_encoding_t,
350 err: *mut semq_error_t,
351 ) -> semq_status_t;
352 pub fn semq_encoding_concat(
355 parts: *const *const semq_encoding_t,
356 k: u32,
357 out: *mut *mut semq_encoding_t,
358 err: *mut semq_error_t,
359 ) -> semq_status_t;
360 pub fn semq_encoding_diff(
362 reference: *const semq_encoding_t,
363 candidate: *const semq_encoding_t,
364 out: *mut *mut semq_diff_t,
365 err: *mut semq_error_t,
366 ) -> semq_status_t;
367
368 pub fn semq_diff_free(diff: *mut semq_diff_t);
371 pub fn semq_diff_config(diff: *const semq_diff_t) -> *const semq_config_t;
372 pub fn semq_diff_id_kind(diff: *const semq_diff_t) -> u32;
373 pub fn semq_diff_reference_id(diff: *const semq_diff_t, out: *mut u8);
374 pub fn semq_diff_candidate_id(diff: *const semq_diff_t, out: *mut u8);
375 pub fn semq_diff_count(diff: *const semq_diff_t, list: u32) -> u64;
376 pub fn semq_diff_n_unchanged(diff: *const semq_diff_t) -> u64;
377 pub fn semq_diff_id(
380 diff: *const semq_diff_t,
381 list: u32,
382 i: u64,
383 out_u64: *mut u64,
384 bytes: *mut *const u8,
385 len: *mut u64,
386 err: *mut semq_error_t,
387 ) -> semq_status_t;
388 pub fn semq_diff_hamming(
390 diff: *const semq_diff_t,
391 i: u64,
392 out: *mut u64,
393 err: *mut semq_error_t,
394 ) -> semq_status_t;
395 pub fn semq_diff_manifest_changes(diff: *const semq_diff_t) -> u32;
396 pub fn semq_diff_manifest_change(
397 diff: *const semq_diff_t,
398 i: u32,
399 out: *mut semq_manifest_change_t,
400 err: *mut semq_error_t,
401 ) -> semq_status_t;
402 pub fn semq_diff_units_u64(
405 diff: *const semq_diff_t,
406 id: u64,
407 units: *mut u32,
408 ref_symbols: *mut u8,
409 cand_symbols: *mut u8,
410 cap: u64,
411 count: *mut u64,
412 err: *mut semq_error_t,
413 ) -> semq_status_t;
414 pub fn semq_diff_units_utf8(
415 diff: *const semq_diff_t,
416 id: *const u8,
417 len: u64,
418 units: *mut u32,
419 ref_symbols: *mut u8,
420 cand_symbols: *mut u8,
421 cap: u64,
422 count: *mut u64,
423 err: *mut semq_error_t,
424 ) -> semq_status_t;
425
426 pub fn semq_floor_create(
432 config: *const semq_config_t,
433 id_kind: u32,
434 reference_id: *const u8,
435 nulls: u64,
436 changed_rows: u64,
437 total_rows: u64,
438 hamming: u64,
439 out: *mut *mut semq_floor_t,
440 err: *mut semq_error_t,
441 ) -> semq_status_t;
442 pub fn semq_floor_free(floor: *mut semq_floor_t);
443 pub fn semq_floor_measure(
448 nulls: *const *const semq_diff_t,
449 k: u32,
450 out: *mut *mut semq_floor_t,
451 err: *mut semq_error_t,
452 ) -> semq_status_t;
453 pub fn semq_floor_config(floor: *const semq_floor_t) -> *const semq_config_t;
455 pub fn semq_floor_id_kind(floor: *const semq_floor_t) -> u32;
457 pub fn semq_floor_reference_id(floor: *const semq_floor_t, out: *mut u8);
459 pub fn semq_floor_nulls(floor: *const semq_floor_t) -> u64;
460 pub fn semq_floor_changed_rows(floor: *const semq_floor_t) -> u64;
461 pub fn semq_floor_total_rows(floor: *const semq_floor_t) -> u64;
462 pub fn semq_floor_hamming(floor: *const semq_floor_t) -> u64;
463 pub fn semq_diff_within(
467 diff: *const semq_diff_t,
468 floor: *const semq_floor_t,
469 out: *mut c_int,
470 err: *mut semq_error_t,
471 ) -> semq_status_t;
472
473 pub fn semq_core_version() -> *const c_char;
476 pub fn semq_build_id() -> *const c_char;
478 pub fn semq_backend_name(op: u32) -> *const c_char;
480 pub fn semq_status_name(status: u32) -> *const c_char;
482 pub fn semq_sha256(data: *const u8, len: u64, out: *mut u8);
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489 use std::ffi::CStr;
490 use std::mem::{align_of, offset_of, size_of};
491
492 #[test]
494 fn error_layout_matches_the_abi() {
495 assert_eq!(size_of::<semq_error_t>(), 152);
496 assert_eq!(align_of::<semq_error_t>(), 8);
497 assert_eq!(offset_of!(semq_error_t, status), 0);
498 assert_eq!(offset_of!(semq_error_t, which), 4);
499 assert_eq!(offset_of!(semq_error_t, row), 8);
500 assert_eq!(offset_of!(semq_error_t, field), 16);
501 assert_eq!(offset_of!(semq_error_t, message), 24);
502 }
503
504 #[test]
506 fn config_layout_matches_the_abi() {
507 assert_eq!(size_of::<semq_config_t>(), 16);
508 assert_eq!(align_of::<semq_config_t>(), 4);
509 assert_eq!(offset_of!(semq_config_t, op), 0);
510 assert_eq!(offset_of!(semq_config_t, dim), 4);
511 assert_eq!(offset_of!(semq_config_t, p1), 8);
512 assert_eq!(offset_of!(semq_config_t, p2), 12);
513 }
514
515 #[cfg(target_pointer_width = "64")]
517 #[test]
518 fn pointer_struct_layouts_match_the_abi() {
519 assert_eq!(size_of::<semq_pair_t>(), 32);
520 assert_eq!(offset_of!(semq_pair_t, key), 0);
521 assert_eq!(offset_of!(semq_pair_t, key_len), 8);
522 assert_eq!(offset_of!(semq_pair_t, value), 16);
523 assert_eq!(offset_of!(semq_pair_t, value_len), 24);
524
525 assert_eq!(size_of::<semq_ids_t>(), 40);
526 assert_eq!(offset_of!(semq_ids_t, kind), 0);
527 assert_eq!(offset_of!(semq_ids_t, n), 8);
528 assert_eq!(offset_of!(semq_ids_t, u64), 16);
529 assert_eq!(offset_of!(semq_ids_t, utf8_offsets), 24);
530 assert_eq!(offset_of!(semq_ids_t, utf8_bytes), 32);
531
532 assert_eq!(size_of::<semq_part_t>(), 16);
533 assert_eq!(offset_of!(semq_part_t, ptr), 0);
534 assert_eq!(offset_of!(semq_part_t, len), 8);
535
536 assert_eq!(size_of::<semq_manifest_change_t>(), 48);
537 assert_eq!(offset_of!(semq_manifest_change_t, key), 0);
538 assert_eq!(offset_of!(semq_manifest_change_t, key_len), 8);
539 assert_eq!(offset_of!(semq_manifest_change_t, has_before), 12);
540 assert_eq!(offset_of!(semq_manifest_change_t, before), 16);
541 assert_eq!(offset_of!(semq_manifest_change_t, before_len), 24);
542 assert_eq!(offset_of!(semq_manifest_change_t, has_after), 28);
543 assert_eq!(offset_of!(semq_manifest_change_t, after), 32);
544 assert_eq!(offset_of!(semq_manifest_change_t, after_len), 40);
545 }
546
547 #[test]
550 fn core_links_and_answers() {
551 let version = unsafe { CStr::from_ptr(semq_core_version()) };
552 assert!(!version.to_bytes().is_empty());
553
554 let mut cfg = semq_config_t {
555 op: 0,
556 dim: 0,
557 p1: 0,
558 p2: 0,
559 };
560 let status = unsafe { semq_config_quant(4, 4, &mut cfg, std::ptr::null_mut()) };
561 assert_eq!(status, SEMQ_OK);
562 assert_eq!(
563 cfg,
564 semq_config_t {
565 op: SEMQ_QUANT,
566 dim: 4,
567 p1: 4,
568 p2: SEMQ_RULE_REVISION
569 }
570 );
571 let mut bytes = [0u8; 13];
572 unsafe { semq_config_to_bytes(&cfg, bytes.as_mut_ptr()) };
573 assert_eq!(bytes, [2, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
574
575 let name = unsafe { CStr::from_ptr(semq_status_name(SEMQ_ERR_INVALID_INPUT)) };
576 assert_eq!(name.to_str().unwrap(), "invalid_input");
577 }
578}