use crate::errors::Error;
use crate::ffi::Slice;
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Status {
Ok = 0,
Closed = 1,
Protocol = 2,
Limit = 3,
Stream = 4,
Timeout = 5,
Tls = 6,
Version = 7,
Io = 8,
Invalid = 9,
Runtime = 10,
}
impl Status {
pub fn of(error: &Error) -> Self {
match error {
Error::Closed => Self::Closed,
Error::Protocol(_) => Self::Protocol,
Error::Limit(_) => Self::Limit,
Error::Stream { .. } => Self::Stream,
Error::Timeout(_) => Self::Timeout,
Error::Tls(_) => Self::Tls,
Error::Version(_) => Self::Version,
Error::Io(_) => Self::Io,
}
}
pub fn message(&self) -> &'static str {
match self {
Self::Ok => "ok",
Self::Closed => "connection closed",
Self::Protocol => "protocol violation",
Self::Limit => "limit exceeded",
Self::Stream => "stream failed",
Self::Timeout => "timed out",
Self::Tls => "tls error",
Self::Version => "version negotiation failed",
Self::Io => "io error",
Self::Invalid => "invalid argument",
Self::Runtime => "runtime unavailable",
}
}
}
pub struct ErrorHandle {
pub status: Status,
pub message: String,
pub stream_id: Option<crate::models::StreamID>,
pub code: Option<u64>,
}
impl ErrorHandle {
pub fn new(error: &Error) -> Self {
let (stream_id, code) = match error {
Error::Stream { id, code, .. } => (Some(*id), Some(*code)),
_ => (None, None),
};
Self { status: Status::of(error), message: error.to_string(), stream_id, code }
}
pub unsafe fn report(out: *mut *mut ErrorHandle, error: &Error) -> Status {
let status = Status::of(error);
if !out.is_null() {
unsafe { *out = Box::into_raw(Box::new(Self::new(error))) };
}
status
}
pub unsafe fn raise(out: *mut *mut ErrorHandle, status: Status) -> Status {
if !out.is_null() {
let handle = Self { status, message: status.message().to_owned(), stream_id: None, code: None };
unsafe { *out = Box::into_raw(Box::new(handle)) };
}
status
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_error_free(error: *mut ErrorHandle) {
if !error.is_null() {
drop(unsafe { Box::from_raw(error) });
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_error_status(error: *const ErrorHandle) -> Status {
match unsafe { error.as_ref() } {
Some(error) => error.status,
None => Status::Invalid,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_error_message(error: *const ErrorHandle) -> Slice {
match unsafe { error.as_ref() } {
Some(error) => Slice::text(&error.message),
None => Slice::ABSENT,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_error_stream_id(error: *const ErrorHandle) -> i64 {
match unsafe { error.as_ref() }.and_then(|error| error.stream_id) {
Some(stream_id) => stream_id.0 as i64,
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_error_code(error: *const ErrorHandle) -> i64 {
match unsafe { error.as_ref() }.and_then(|error| error.code) {
Some(code) => code as i64,
None => -1,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_status_message(status: Status) -> Slice {
Slice::text(status.message())
}