1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright (c) 2018-2023, agnos.ai UK Ltd, all rights reserved.
//---------------------------------------------------------------

// extern crate libc;

use {
    crate::rdfox_api::{CException_getExceptionName, CException_what},
    rdf_store_rs::RDFStoreError::{self},
    std::{
        ffi::CStr,
        fmt::{Display, Formatter},
        panic::catch_unwind,
        str::Utf8Error,
    },
};

pub use crate::rdfox_api::CException;

impl CException {
    pub fn handle<F>(action: &str, f: F) -> Result<(), RDFStoreError>
    where F: FnOnce() -> *const CException + std::panic::UnwindSafe {
        unsafe {
            let result = catch_unwind(|| {
                let c_exception = f();
                if c_exception.is_null() {
                    Ok(())
                } else {
                    Err(RDFStoreError::Exception {
                        action:  action.to_string(),
                        message: format!("{:}", *c_exception).replace("RDFoxException: ", ""),
                    })
                }
            });
            match result {
                Ok(res) => {
                    match res {
                        Ok(..) => Ok(()),
                        Err(err) => {
                            // panic!("{err:}")
                            Err(err)
                        },
                    }
                },
                Err(err) => {
                    panic!("RDFox panicked while {action}: {err:?}")
                },
            }
        }
    }

    pub fn name(&self) -> Result<&'static str, Utf8Error> {
        let name = unsafe { CStr::from_ptr(CException_getExceptionName(self)) };
        name.to_str()
    }

    pub fn what(&self) -> Result<&'static str, Utf8Error> {
        let what = unsafe { CStr::from_ptr(CException_what(self)) };
        what.to_str()
    }
}

impl Display for CException {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        if let Ok(name) = self.name() {
            if let Ok(what) = self.what() {
                return writeln!(f, "{:}: {:}", name, what)
            };
        };
        f.write_str("Could not show exception, unicode error")
    }
}

#[macro_export]
macro_rules! database_call {
    ($function:expr) => {{
        $crate::exception::CException::handle(
            "unknown database action",
            core::panic::AssertUnwindSafe(|| unsafe { $function }),
        )
    }};
    ($action:expr, $function:expr) => {{
        // tracing::trace!("{} at line {}", stringify!($function), line!());
        tracing::trace!(
            target: rdf_store_rs::consts::LOG_TARGET_DATABASE,
            "{}",
            $action
        );
        $crate::exception::CException::handle(
            $action,
            core::panic::AssertUnwindSafe(|| unsafe { $function }),
        )
    }};
}