Skip to content

Commit

Permalink
refactor(sys): add Error and MaybeError
Browse files Browse the repository at this point in the history
  • Loading branch information
qevolg committed Dec 31, 2024
1 parent ea10bc1 commit 1777767
Show file tree
Hide file tree
Showing 2 changed files with 292 additions and 70 deletions.
272 changes: 254 additions & 18 deletions taos-ws-sys/src/native/error.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
use std::cell::RefCell;
use std::ffi::{c_char, c_int, CStr};
use std::ffi::{c_char, c_int, CStr, CString};

use taos_error::Error;
use taos_error::Code;
use tracing::trace;

use super::TAOS_RES;

#[no_mangle]
pub extern "C" fn taos_errno(res: *mut TAOS_RES) -> c_int {
pub unsafe extern "C" fn taos_errno(res: *mut TAOS_RES) -> c_int {
if res.is_null() {
return errno();
}
todo!()

match (res as *mut MaybeError<()>)
.as_ref()
.and_then(MaybeError::errno)
{
Some(errno) => format_errno(errno),
_ => Code::SUCCESS.into(),
}
}

#[no_mangle]
pub extern "C" fn taos_errstr(res: *mut TAOS_RES) -> *const c_char {
pub unsafe extern "C" fn taos_errstr(res: *mut TAOS_RES) -> *const c_char {
if res.is_null() {
if errno() == 0 {
return EMPTY.as_ptr();
}
return errstr();
}
todo!()

match (res as *mut MaybeError<()>)
.as_ref()
.and_then(MaybeError::errstr)
{
Some(err) => err,
_ => EMPTY.as_ptr(),
}
}

const EMPTY: &CStr = c"";
Expand All @@ -34,12 +49,12 @@ thread_local! {

pub fn set_err_and_get_code(err: Error) -> i32 {
ERRNO.with(|errno| {
let code: u32 = err.code().into();
let code: u32 = err.code.into();
*errno.borrow_mut() = (code | 0x80000000) as i32;
});

ERRSTR.with(|errstr| {
let bytes = err.message().into_bytes();
let bytes = err.message.into_bytes();
let len = bytes.len().min(MAX_ERRSTR_LEN - 1);
let mut errstr = errstr.borrow_mut();
errstr[..len].copy_from_slice(&bytes[..len]);
Expand All @@ -57,26 +72,247 @@ pub fn errstr() -> *const c_char {
ERRSTR.with(|errstr| errstr.borrow().as_ptr() as _)
}

pub fn format_errno(errno: i32) -> i32 {
if errno >= 0 {
return (errno as u32 | 0x80000000) as i32;
}
errno
}

#[derive(Debug)]
pub struct MaybeError<T> {
err: Option<Error>,
data: *mut T,
type_id: &'static str,
}

impl<T> MaybeError<T> {
pub fn errno(&self) -> Option<i32> {
self.err.as_ref().map(|err| err.code.into())
}

pub fn errstr(&self) -> Option<*const c_char> {
self.err.as_ref().map(|err| err.message.as_ptr())
}

pub fn deref(&self) -> Option<&T> {
unsafe { self.data.as_ref() }
}

pub fn deref_mut(&self) -> Option<&mut T> {
unsafe { self.data.as_mut() }
}
}

impl<T> Drop for MaybeError<T> {
fn drop(&mut self) {
if !self.data.is_null() {
trace!("Dropping MaybeError, type_id: {}", self.type_id);
let _ = unsafe { Box::from_raw(self.data) };
}
}
}

impl<T> From<T> for MaybeError<T> {
fn from(value: T) -> Self {
Self {
err: None,
data: Box::into_raw(Box::new(value)),
type_id: std::any::type_name::<T>(),
}
}
}

impl<T> From<Box<T>> for MaybeError<T> {
fn from(value: Box<T>) -> Self {
Self {
err: None,
data: Box::into_raw(value),
type_id: std::any::type_name::<T>(),
}
}
}

impl<T, E> From<Result<T, E>> for MaybeError<T>
where
E: Into<Error>,
{
fn from(value: Result<T, E>) -> Self {
match value {
Ok(val) => Self {
err: None,
data: Box::into_raw(Box::new(val)),
type_id: std::any::type_name::<T>(),
},
Err(err) => Self {
err: Some(err.into()),
data: std::ptr::null_mut(),
type_id: std::any::type_name::<T>(),
},
}
}
}

impl<T, E> From<Result<Box<T>, E>> for MaybeError<T>
where
E: Into<Error>,
{
fn from(value: Result<Box<T>, E>) -> Self {
match value {
Ok(val) => Self {
err: None,
data: Box::into_raw(val),
type_id: std::any::type_name::<T>(),
},
Err(err) => Self {
err: Some(err.into()),
data: std::ptr::null_mut(),
type_id: std::any::type_name::<T>(),
},
}
}
}

#[derive(Debug)]
pub struct Error {
code: Code,
message: CString,
source: Option<Box<dyn std::error::Error>>,
}

impl Error {
pub fn new(code: Code, message: &str) -> Self {
Self {
code,
message: CString::new(message).unwrap(),
source: None,
}
}
}

impl From<&Error> for Error {
fn from(err: &Error) -> Self {
Self {
code: err.code,
message: err.message.clone(),
source: None,
}
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{:#06X}] {}", self.code, self.message.to_str().unwrap())
}
}

impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source.as_ref().map(|e| e.as_ref())
}
}

impl From<Box<dyn std::error::Error>> for Error {
fn from(err: Box<dyn std::error::Error>) -> Self {
Self {
code: Code::FAILED,
message: CString::new(err.to_string()).unwrap(),
source: Some(err),
}
}
}

impl From<std::str::Utf8Error> for Error {
fn from(err: std::str::Utf8Error) -> Self {
Self {
code: Code::FAILED,
message: CString::new(err.to_string()).unwrap(),
source: Some(Box::new(err)),
}
}
}

impl From<std::string::FromUtf8Error> for Error {
fn from(err: std::string::FromUtf8Error) -> Self {
Self {
code: Code::FAILED,
message: CString::new(err.to_string()).unwrap(),
source: Some(Box::new(err)),
}
}
}

impl From<taos_query::DsnError> for Error {
fn from(err: taos_query::DsnError) -> Self {
use taos_ws::query::asyn::WS_ERROR_NO;
Self {
code: WS_ERROR_NO::DSN_ERROR.as_code(),
message: CString::new(err.to_string()).unwrap(),
source: None,
}
}
}

impl From<taos_query::common::SmlDataBuilderError> for Error {
fn from(err: taos_query::common::SmlDataBuilderError) -> Self {
Self {
code: Code::FAILED,
message: CString::new(err.to_string()).unwrap(),
source: Some(Box::new(err)),
}
}
}

impl From<taos_ws::Error> for Error {
fn from(e: taos_ws::Error) -> Self {
Self {
code: e.errno(),
message: CString::new(e.errstr()).unwrap(),
source: None,
}
}
}

impl From<taos_ws::query::Error> for Error {
fn from(err: taos_ws::query::Error) -> Self {
Self {
code: err.errno(),
message: CString::new(err.errstr()).unwrap(),
source: None,
}
}
}

impl From<taos_error::Error> for Error {
fn from(err: taos_error::Error) -> Self {
Self {
code: err.code(),
message: CString::new(err.to_string()).unwrap(),
source: None,
}
}
}

#[cfg(test)]
mod tests {
use std::ffi::CStr;
use std::ptr::null_mut;

use taos_error::Error;

use super::*;

#[test]
fn test_set_err_and_get_code() {
let err = Error::new(1, "test error");
let code = set_err_and_get_code(err);
assert_eq!(code as u32, 0x80000001);
unsafe {
let err = Error::new(Code::SUCCESS, "test error");
let code = set_err_and_get_code(err);
assert_eq!(code as u32, 0x80000000);

let code = taos_errno(null_mut());
assert_eq!(code as u32, 0x80000001);
let code = taos_errno(null_mut());
assert_eq!(code as u32, 0x80000000);

let errstr_ptr = taos_errstr(null_mut());
let errstr = unsafe { CStr::from_ptr(errstr_ptr) };
assert_eq!(errstr, c"Internal error: `test error`"); // todo
let errstr_ptr = taos_errstr(null_mut());
let errstr = CStr::from_ptr(errstr_ptr);
assert_eq!(errstr, c"test error");
}
}
}
Loading

0 comments on commit 1777767

Please sign in to comment.