use core::ffi::{c_int, c_void};
use crate::socket_group::VTable;
use crate::thunk;
use crate::{ConnectingSocket, us_bun_verify_error_t, us_socket_t};
pub trait Handler: 'static {
type Ext;
const HAS_EXT: bool = true;
const HAS_ON_OPEN: bool = false;
const HAS_ON_DATA: bool = false;
const HAS_ON_FD: bool = false;
const HAS_ON_WRITABLE: bool = false;
const HAS_ON_CLOSE: bool = false;
const HAS_ON_TIMEOUT: bool = false;
const HAS_ON_LONG_TIMEOUT: bool = false;
const HAS_ON_END: bool = false;
const HAS_ON_CONNECT_ERROR: bool = false;
const HAS_ON_CONNECTING_ERROR: bool = false;
const HAS_ON_HANDSHAKE: bool = false;
fn on_open(_ext: &mut Self::Ext, _s: *mut us_socket_t, _is_client: bool, _ip: &[u8]) {
unreachable!()
}
fn on_data(_ext: &mut Self::Ext, _s: *mut us_socket_t, _data: &[u8]) {
unreachable!()
}
fn on_fd(_ext: &mut Self::Ext, _s: *mut us_socket_t, _fd: c_int) {
unreachable!()
}
fn on_writable(_ext: &mut Self::Ext, _s: *mut us_socket_t) {
unreachable!()
}
fn on_close(
_ext: &mut Self::Ext,
_s: *mut us_socket_t,
_code: i32,
_reason: Option<*mut c_void>,
) {
unreachable!()
}
fn on_timeout(_ext: &mut Self::Ext, _s: *mut us_socket_t) {
unreachable!()
}
fn on_long_timeout(_ext: &mut Self::Ext, _s: *mut us_socket_t) {
unreachable!()
}
fn on_end(_ext: &mut Self::Ext, _s: *mut us_socket_t) {
unreachable!()
}
fn on_connect_error(_ext: &mut Self::Ext, _s: *mut us_socket_t, _code: i32) {
unreachable!()
}
fn on_connecting_error(_cs: *mut ConnectingSocket, _code: i32) {
unreachable!()
}
fn on_handshake(
_ext: &mut Self::Ext,
_s: *mut us_socket_t,
_ok: bool,
_err: us_bun_verify_error_t,
) {
unreachable!()
}
fn on_open_no_ext(_s: *mut us_socket_t, _is_client: bool, _ip: &[u8]) {
unreachable!()
}
fn on_data_no_ext(_s: *mut us_socket_t, _data: &[u8]) {
unreachable!()
}
fn on_fd_no_ext(_s: *mut us_socket_t, _fd: c_int) {
unreachable!()
}
fn on_writable_no_ext(_s: *mut us_socket_t) {
unreachable!()
}
fn on_close_no_ext(_s: *mut us_socket_t, _code: i32, _reason: Option<*mut c_void>) {
unreachable!()
}
fn on_timeout_no_ext(_s: *mut us_socket_t) {
unreachable!()
}
fn on_long_timeout_no_ext(_s: *mut us_socket_t) {
unreachable!()
}
fn on_end_no_ext(_s: *mut us_socket_t) {
unreachable!()
}
fn on_connect_error_no_ext(_s: *mut us_socket_t, _code: i32) {
unreachable!()
}
fn on_handshake_no_ext(_s: *mut us_socket_t, _ok: bool, _err: us_bun_verify_error_t) {
unreachable!()
}
}
pub fn make<H: Handler>() -> &'static VTable {
&Make::<H>::VT
}
struct Make<H>(core::marker::PhantomData<H>);
impl<H: Handler> Make<H> {
const VT: VTable = VTable {
on_open: if H::HAS_ON_OPEN {
Some(Trampolines::<H>::on_open)
} else {
None
},
on_data: if H::HAS_ON_DATA {
Some(Trampolines::<H>::on_data)
} else {
None
},
on_fd: if H::HAS_ON_FD {
Some(Trampolines::<H>::on_fd)
} else {
None
},
on_writable: if H::HAS_ON_WRITABLE {
Some(Trampolines::<H>::on_writable)
} else {
None
},
on_close: if H::HAS_ON_CLOSE {
Some(Trampolines::<H>::on_close)
} else {
None
},
on_timeout: if H::HAS_ON_TIMEOUT {
Some(Trampolines::<H>::on_timeout)
} else {
None
},
on_long_timeout: if H::HAS_ON_LONG_TIMEOUT {
Some(Trampolines::<H>::on_long_timeout)
} else {
None
},
on_end: if H::HAS_ON_END {
Some(Trampolines::<H>::on_end)
} else {
None
},
on_connect_error: if H::HAS_ON_CONNECT_ERROR {
Some(Trampolines::<H>::on_connect_error)
} else {
None
},
on_connecting_error: if H::HAS_ON_CONNECTING_ERROR {
Some(Trampolines::<H>::on_connecting_error)
} else {
None
},
on_handshake: if H::HAS_ON_HANDSHAKE {
Some(Trampolines::<H>::on_handshake)
} else {
None
},
};
}
pub(crate) struct Trampolines<H>(core::marker::PhantomData<H>);
impl<H: Handler> Trampolines<H> {
#[inline(always)]
fn ext(s: *mut us_socket_t) -> &'static mut H::Ext {
us_socket_t::opaque_mut(s).ext::<H::Ext>()
}
pub(crate) extern "C" fn on_open(
s: *mut us_socket_t,
is_client: c_int,
ip: *mut u8,
ip_len: c_int,
) -> *mut us_socket_t {
let ip_slice: &[u8] =
unsafe { thunk::c_slice(ip, usize::try_from(ip_len).expect("int cast")) };
if H::HAS_EXT {
H::on_open(Self::ext(s), s, is_client != 0, ip_slice);
} else {
H::on_open_no_ext(s, is_client != 0, ip_slice);
}
s
}
pub(crate) extern "C" fn on_data(
s: *mut us_socket_t,
data: *mut u8,
len: c_int,
) -> *mut us_socket_t {
let data_slice = unsafe { thunk::c_slice(data, usize::try_from(len).expect("int cast")) };
if H::HAS_EXT {
H::on_data(Self::ext(s), s, data_slice);
} else {
H::on_data_no_ext(s, data_slice);
}
s
}
pub(crate) extern "C" fn on_fd(s: *mut us_socket_t, fd: c_int) -> *mut us_socket_t {
if H::HAS_EXT {
H::on_fd(Self::ext(s), s, fd);
} else {
H::on_fd_no_ext(s, fd);
}
s
}
pub(crate) extern "C" fn on_writable(s: *mut us_socket_t) -> *mut us_socket_t {
if H::HAS_EXT {
H::on_writable(Self::ext(s), s);
} else {
H::on_writable_no_ext(s);
}
s
}
pub(crate) extern "C" fn on_close(
s: *mut us_socket_t,
code: c_int,
reason: *mut c_void,
) -> *mut us_socket_t {
let reason = if reason.is_null() { None } else { Some(reason) };
if H::HAS_EXT {
H::on_close(Self::ext(s), s, code, reason);
} else {
H::on_close_no_ext(s, code, reason);
}
s
}
pub(crate) extern "C" fn on_timeout(s: *mut us_socket_t) -> *mut us_socket_t {
if H::HAS_EXT {
H::on_timeout(Self::ext(s), s);
} else {
H::on_timeout_no_ext(s);
}
s
}
pub(crate) extern "C" fn on_long_timeout(s: *mut us_socket_t) -> *mut us_socket_t {
if H::HAS_EXT {
H::on_long_timeout(Self::ext(s), s);
} else {
H::on_long_timeout_no_ext(s);
}
s
}
pub(crate) extern "C" fn on_end(s: *mut us_socket_t) -> *mut us_socket_t {
if H::HAS_EXT {
H::on_end(Self::ext(s), s);
} else {
H::on_end_no_ext(s);
}
s
}
pub(crate) extern "C" fn on_connect_error(
s: *mut us_socket_t,
code: c_int,
) -> *mut us_socket_t {
if H::HAS_EXT {
H::on_connect_error(Self::ext(s), s, code);
} else {
H::on_connect_error_no_ext(s, code);
}
s
}
pub(crate) extern "C" fn on_connecting_error(
cs: *mut ConnectingSocket,
code: c_int,
) -> *mut ConnectingSocket {
H::on_connecting_error(cs, code);
cs
}
pub(crate) extern "C" fn on_handshake(
s: *mut us_socket_t,
ok: c_int,
err: us_bun_verify_error_t,
_user: *mut c_void,
) {
if H::HAS_EXT {
H::on_handshake(Self::ext(s), s, ok != 0, err);
} else {
H::on_handshake_no_ext(s, ok != 0, err);
}
}
}