1use std::ffi::{CStr, NulError};
2use std::io;
3
4use faiss_next_sys;
5
6#[derive(Debug, thiserror::Error)]
7pub enum Error {
8 #[error("Faiss native error (code={code}): {message}")]
9 Native { code: i32, message: String },
10
11 #[error("Invalid index description: {0}")]
12 InvalidDescription(String),
13
14 #[error("Index not trained")]
15 NotTrained,
16
17 #[error("Index is empty")]
18 EmptyIndex,
19
20 #[error("Invalid dimension: expected {expected}, got {actual}")]
21 InvalidDimension { expected: usize, actual: usize },
22
23 #[error("Invalid parameter: {0}")]
24 InvalidParameter(String),
25
26 #[error("Invalid cast to {target}: {reason}")]
27 InvalidCast {
28 target: &'static str,
29 reason: String,
30 },
31
32 #[error("Null pointer encountered")]
33 NullPointer,
34
35 #[error("Index does not support operation: {0}")]
36 UnsupportedOperation(&'static str),
37
38 #[error("IO error: {0}")]
39 Io(#[from] io::Error),
40
41 #[error("UTF-8 error: {0}")]
42 Utf8(#[from] NulError),
43}
44
45pub type Result<T> = std::result::Result<T, Error>;
46
47#[inline]
48pub(crate) fn check_return_code(code: i32) -> Result<()> {
49 if code == faiss_next_sys::FAISS_OK {
50 return Ok(());
51 }
52
53 let message = unsafe {
54 let ptr = faiss_next_sys::faiss_get_last_error();
55 if ptr.is_null() {
56 "unknown error".to_string()
57 } else {
58 CStr::from_ptr(ptr)
59 .to_str()
60 .unwrap_or("invalid error message")
61 .to_string()
62 }
63 };
64
65 Err(Error::Native { code, message })
66}
67
68impl Error {
69 pub fn native(code: i32, message: impl Into<String>) -> Self {
70 Error::Native {
71 code,
72 message: message.into(),
73 }
74 }
75
76 pub fn invalid_cast(target: &'static str, reason: impl Into<String>) -> Self {
77 Error::InvalidCast {
78 target,
79 reason: reason.into(),
80 }
81 }
82
83 pub fn unsupported(operation: &'static str) -> Self {
84 Error::UnsupportedOperation(operation)
85 }
86}