use crate::support::CxxVTable;
use crate::support::Opaque;
use std::cell::UnsafeCell;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::pin::Pin;
unsafe extern "C" {
fn crdtp__FrontendChannel__BASE__CONSTRUCT(
buf: *mut MaybeUninit<RawFrontendChannel>,
);
fn crdtp__Serializable__DELETE(this: *mut RawSerializable);
fn crdtp__Serializable__AppendSerialized(
this: *const RawSerializable,
out: *mut CppVecU8,
);
fn crdtp__Dispatchable__new(data: *const u8, len: usize)
-> *mut Dispatchable;
fn crdtp__Dispatchable__DELETE(this: *mut Dispatchable);
fn crdtp__Dispatchable__ok(this: *const Dispatchable) -> bool;
fn crdtp__Dispatchable__callId(this: *const Dispatchable) -> i32;
fn crdtp__Dispatchable__hasCallId(this: *const Dispatchable) -> bool;
fn crdtp__Dispatchable__methodLen(this: *const Dispatchable) -> usize;
fn crdtp__Dispatchable__methodCopy(this: *const Dispatchable, out: *mut u8);
fn crdtp__Dispatchable__sessionIdLen(this: *const Dispatchable) -> usize;
fn crdtp__Dispatchable__sessionIdCopy(
this: *const Dispatchable,
out: *mut u8,
);
fn crdtp__Dispatchable__paramsLen(this: *const Dispatchable) -> usize;
fn crdtp__Dispatchable__paramsCopy(this: *const Dispatchable, out: *mut u8);
fn crdtp__DispatchResponse__Success() -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__FallThrough() -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__ParseError(
msg: *const u8,
len: usize,
) -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__InvalidRequest(
msg: *const u8,
len: usize,
) -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__MethodNotFound(
msg: *const u8,
len: usize,
) -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__InvalidParams(
msg: *const u8,
len: usize,
) -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__ServerError(
msg: *const u8,
len: usize,
) -> *mut DispatchResponseWrapper;
fn crdtp__DispatchResponse__DELETE(this: *mut DispatchResponseWrapper);
fn crdtp__DispatchResponse__isSuccess(
this: *const DispatchResponseWrapper,
) -> bool;
fn crdtp__DispatchResponse__isError(
this: *const DispatchResponseWrapper,
) -> bool;
fn crdtp__DispatchResponse__isFallThrough(
this: *const DispatchResponseWrapper,
) -> bool;
fn crdtp__DispatchResponse__code(this: *const DispatchResponseWrapper)
-> i32;
fn crdtp__DispatchResponse__messageLen(
this: *const DispatchResponseWrapper,
) -> usize;
fn crdtp__DispatchResponse__messageCopy(
this: *const DispatchResponseWrapper,
out: *mut u8,
);
fn crdtp__UberDispatcher__new(
channel: *mut RawFrontendChannel,
) -> *mut UberDispatcher;
fn crdtp__UberDispatcher__DELETE(this: *mut UberDispatcher);
fn crdtp__UberDispatcher__channel(
this: *mut UberDispatcher,
) -> *mut RawFrontendChannel;
fn crdtp__UberDispatcher__Dispatch(
this: *mut UberDispatcher,
dispatchable: *const Dispatchable,
) -> *mut DispatchResultWrapper;
fn crdtp__DispatchResult__DELETE(this: *mut DispatchResultWrapper);
fn crdtp__DispatchResult__MethodFound(
this: *const DispatchResultWrapper,
) -> bool;
fn crdtp__DispatchResult__Run(this: *mut DispatchResultWrapper);
fn crdtp__vec_u8__new() -> *mut CppVecU8;
fn crdtp__vec_u8__DELETE(this: *mut CppVecU8);
fn crdtp__vec_u8__size(this: *const CppVecU8) -> usize;
fn crdtp__vec_u8__copy(this: *const CppVecU8, out: *mut u8);
fn crdtp__json__ConvertJSONToCBOR(
json_data: *const u8,
json_len: usize,
cbor_out: *mut CppVecU8,
) -> bool;
fn crdtp__json__ConvertCBORToJSON(
cbor_data: *const u8,
cbor_len: usize,
json_out: *mut CppVecU8,
) -> bool;
fn crdtp__CreateErrorResponse(
call_id: i32,
response: *mut DispatchResponseWrapper,
) -> *mut RawSerializable;
fn crdtp__CreateResponse(
call_id: i32,
params: *mut RawSerializable,
) -> *mut RawSerializable;
fn crdtp__CreateNotification(
method: *const std::ffi::c_char,
params: *mut RawSerializable,
) -> *mut RawSerializable;
fn crdtp__CreateErrorNotification(
response: *mut DispatchResponseWrapper,
) -> *mut RawSerializable;
fn crdtp__DomainDispatcher__new(
channel: *mut RawFrontendChannel,
rust_dispatcher: *mut std::ffi::c_void,
) -> *mut RawDomainDispatcher;
fn crdtp__DomainDispatcher__sendResponse(
this: *mut RawDomainDispatcher,
call_id: i32,
response: *mut DispatchResponseWrapper,
result: *mut RawSerializable,
);
fn crdtp__UberDispatcher__WireBackend(
uber: *mut UberDispatcher,
domain_data: *const u8,
domain_len: usize,
dispatcher: *mut RawDomainDispatcher,
);
}
#[repr(C)]
pub struct Dispatchable(Opaque);
#[repr(C)]
struct DispatchResponseWrapper(Opaque);
#[repr(C)]
pub struct UberDispatcher(Opaque);
#[repr(C)]
struct DispatchResultWrapper(Opaque);
#[repr(C)]
struct CppVecU8(Opaque);
#[repr(C)]
struct RawSerializable(Opaque);
#[repr(C)]
struct RawDomainDispatcher(Opaque);
pub struct Serializable {
ptr: *mut RawSerializable,
}
impl Serializable {
pub fn to_bytes(&self) -> Vec<u8> {
unsafe {
let vec = crdtp__vec_u8__new();
crdtp__Serializable__AppendSerialized(self.ptr, vec);
let len = crdtp__vec_u8__size(vec);
let mut result = vec![0u8; len];
crdtp__vec_u8__copy(vec, result.as_mut_ptr());
crdtp__vec_u8__DELETE(vec);
result
}
}
fn into_raw(self) -> *mut RawSerializable {
let ptr = self.ptr;
std::mem::forget(self);
ptr
}
}
impl Drop for Serializable {
fn drop(&mut self) {
unsafe {
crdtp__Serializable__DELETE(self.ptr);
}
}
}
impl Dispatchable {
pub fn new(cbor_data: &[u8]) -> Box<Self> {
unsafe {
let ptr = crdtp__Dispatchable__new(cbor_data.as_ptr(), cbor_data.len());
Box::from_raw(ptr)
}
}
pub fn ok(&self) -> bool {
unsafe { crdtp__Dispatchable__ok(self) }
}
pub fn call_id(&self) -> i32 {
unsafe { crdtp__Dispatchable__callId(self) }
}
pub fn has_call_id(&self) -> bool {
unsafe { crdtp__Dispatchable__hasCallId(self) }
}
pub fn method(&self) -> Vec<u8> {
unsafe {
let len = crdtp__Dispatchable__methodLen(self);
let mut buf = vec![0u8; len];
crdtp__Dispatchable__methodCopy(self, buf.as_mut_ptr());
buf
}
}
pub fn method_str(&self) -> String {
String::from_utf8_lossy(&self.method()).into_owned()
}
pub fn session_id(&self) -> Vec<u8> {
unsafe {
let len = crdtp__Dispatchable__sessionIdLen(self);
let mut buf = vec![0u8; len];
crdtp__Dispatchable__sessionIdCopy(self, buf.as_mut_ptr());
buf
}
}
pub fn params(&self) -> Vec<u8> {
unsafe {
let len = crdtp__Dispatchable__paramsLen(self);
let mut buf = vec![0u8; len];
crdtp__Dispatchable__paramsCopy(self, buf.as_mut_ptr());
buf
}
}
}
impl Drop for Dispatchable {
fn drop(&mut self) {
unsafe {
crdtp__Dispatchable__DELETE(self);
}
}
}
pub struct DispatchResponse {
ptr: *mut DispatchResponseWrapper,
}
impl DispatchResponse {
pub fn success() -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__Success(),
}
}
}
pub fn fall_through() -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__FallThrough(),
}
}
}
pub fn parse_error(message: &str) -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__ParseError(
message.as_ptr(),
message.len(),
),
}
}
}
pub fn invalid_request(message: &str) -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__InvalidRequest(
message.as_ptr(),
message.len(),
),
}
}
}
pub fn method_not_found(message: &str) -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__MethodNotFound(
message.as_ptr(),
message.len(),
),
}
}
}
pub fn invalid_params(message: &str) -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__InvalidParams(
message.as_ptr(),
message.len(),
),
}
}
}
pub fn server_error(message: &str) -> Self {
unsafe {
Self {
ptr: crdtp__DispatchResponse__ServerError(
message.as_ptr(),
message.len(),
),
}
}
}
pub fn is_success(&self) -> bool {
unsafe { crdtp__DispatchResponse__isSuccess(self.ptr) }
}
pub fn is_error(&self) -> bool {
unsafe { crdtp__DispatchResponse__isError(self.ptr) }
}
pub fn is_fall_through(&self) -> bool {
unsafe { crdtp__DispatchResponse__isFallThrough(self.ptr) }
}
pub fn code(&self) -> i32 {
unsafe { crdtp__DispatchResponse__code(self.ptr) }
}
pub fn message(&self) -> String {
unsafe {
let len = crdtp__DispatchResponse__messageLen(self.ptr);
let mut buf = vec![0u8; len];
crdtp__DispatchResponse__messageCopy(self.ptr, buf.as_mut_ptr());
String::from_utf8_lossy(&buf).into_owned()
}
}
fn into_raw(self) -> *mut DispatchResponseWrapper {
let ptr = self.ptr;
std::mem::forget(self);
ptr
}
}
impl Drop for DispatchResponse {
fn drop(&mut self) {
unsafe {
crdtp__DispatchResponse__DELETE(self.ptr);
}
}
}
pub trait FrontendChannelImpl {
fn send_protocol_response(&mut self, call_id: i32, message: Serializable);
fn send_protocol_notification(&mut self, message: Serializable);
fn fall_through(&mut self, call_id: i32, method: &[u8], message: &[u8]);
fn flush_protocol_notifications(&mut self);
}
#[repr(C)]
struct RawFrontendChannel {
_cxx_vtable: CxxVTable,
}
pub struct FrontendChannel {
raw: UnsafeCell<RawFrontendChannel>,
imp: Box<dyn FrontendChannelImpl>,
}
impl FrontendChannel {
pub fn new(imp: Box<dyn FrontendChannelImpl>) -> Pin<Box<Self>> {
let channel = Box::new(Self {
raw: UnsafeCell::new(unsafe { MaybeUninit::zeroed().assume_init() }),
imp,
});
unsafe {
crdtp__FrontendChannel__BASE__CONSTRUCT(
channel.raw.get() as *mut _ as *mut MaybeUninit<RawFrontendChannel>
);
}
Box::into_pin(channel)
}
fn raw_ptr(&self) -> *mut RawFrontendChannel {
self.raw.get()
}
unsafe fn from_raw<'a>(ptr: *mut RawFrontendChannel) -> &'a mut Self {
unsafe {
let channel_ptr = ptr as *mut u8;
let offset = std::mem::offset_of!(FrontendChannel, raw);
let self_ptr = channel_ptr.sub(offset) as *mut Self;
&mut *self_ptr
}
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn crdtp__FrontendChannel__BASE__sendProtocolResponse(
this: *mut RawFrontendChannel,
call_id: i32,
message: *mut RawSerializable,
) {
unsafe {
let channel = FrontendChannel::from_raw(this);
let msg = Serializable { ptr: message };
channel.imp.send_protocol_response(call_id, msg);
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn crdtp__FrontendChannel__BASE__sendProtocolNotification(
this: *mut RawFrontendChannel,
message: *mut RawSerializable,
) {
unsafe {
let channel = FrontendChannel::from_raw(this);
let msg = Serializable { ptr: message };
channel.imp.send_protocol_notification(msg);
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn crdtp__FrontendChannel__BASE__fallThrough(
this: *mut RawFrontendChannel,
call_id: i32,
method_data: *const u8,
method_len: usize,
message_data: *const u8,
message_len: usize,
) {
unsafe {
let channel = FrontendChannel::from_raw(this);
let method = std::slice::from_raw_parts(method_data, method_len);
let message = std::slice::from_raw_parts(message_data, message_len);
channel.imp.fall_through(call_id, method, message);
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn crdtp__FrontendChannel__BASE__flushProtocolNotifications(
this: *mut RawFrontendChannel,
) {
unsafe {
let channel = FrontendChannel::from_raw(this);
channel.imp.flush_protocol_notifications();
}
}
pub struct DispatchResult {
ptr: *mut DispatchResultWrapper,
}
impl DispatchResult {
pub fn method_found(&self) -> bool {
unsafe { crdtp__DispatchResult__MethodFound(self.ptr) }
}
pub fn run(self) {
unsafe {
crdtp__DispatchResult__Run(self.ptr);
}
}
}
impl Drop for DispatchResult {
fn drop(&mut self) {
unsafe {
crdtp__DispatchResult__DELETE(self.ptr);
}
}
}
impl UberDispatcher {
pub fn new(channel: &Pin<Box<FrontendChannel>>) -> Box<Self> {
unsafe {
let ptr = crdtp__UberDispatcher__new(channel.raw_ptr());
Box::from_raw(ptr)
}
}
pub fn dispatch(&mut self, dispatchable: &Dispatchable) -> DispatchResult {
unsafe {
let ptr = crdtp__UberDispatcher__Dispatch(self, dispatchable);
DispatchResult { ptr }
}
}
}
impl Drop for UberDispatcher {
fn drop(&mut self) {
unsafe {
crdtp__UberDispatcher__DELETE(self);
}
}
}
pub fn json_to_cbor(json: &[u8]) -> Option<Vec<u8>> {
unsafe {
let vec = crdtp__vec_u8__new();
let ok = crdtp__json__ConvertJSONToCBOR(json.as_ptr(), json.len(), vec);
if ok {
let len = crdtp__vec_u8__size(vec);
let mut result = vec![0u8; len];
crdtp__vec_u8__copy(vec, result.as_mut_ptr());
crdtp__vec_u8__DELETE(vec);
Some(result)
} else {
crdtp__vec_u8__DELETE(vec);
None
}
}
}
pub fn cbor_to_json(cbor: &[u8]) -> Option<Vec<u8>> {
unsafe {
let vec = crdtp__vec_u8__new();
let ok = crdtp__json__ConvertCBORToJSON(cbor.as_ptr(), cbor.len(), vec);
if ok {
let len = crdtp__vec_u8__size(vec);
let mut result = vec![0u8; len];
crdtp__vec_u8__copy(vec, result.as_mut_ptr());
crdtp__vec_u8__DELETE(vec);
Some(result)
} else {
crdtp__vec_u8__DELETE(vec);
None
}
}
}
pub fn create_error_response(
call_id: i32,
response: DispatchResponse,
) -> Serializable {
unsafe {
let ptr = crdtp__CreateErrorResponse(call_id, response.into_raw());
Serializable { ptr }
}
}
pub fn create_error_notification(response: DispatchResponse) -> Serializable {
unsafe {
let ptr = crdtp__CreateErrorNotification(response.into_raw());
Serializable { ptr }
}
}
pub fn create_response(
call_id: i32,
params: Option<Serializable>,
) -> Serializable {
unsafe {
let params_ptr = match params {
Some(p) => p.into_raw(),
None => std::ptr::null_mut(),
};
let ptr = crdtp__CreateResponse(call_id, params_ptr);
Serializable { ptr }
}
}
pub fn create_notification(
method: &str,
params: Option<Serializable>,
) -> Serializable {
unsafe {
let method_cstr =
CString::new(method).expect("method name must not contain null bytes");
let params_ptr = match params {
Some(p) => p.into_raw(),
None => std::ptr::null_mut(),
};
let ptr = crdtp__CreateNotification(method_cstr.as_ptr(), params_ptr);
Serializable { ptr }
}
}
pub trait DomainDispatcherImpl {
fn dispatch(
&mut self,
command: &[u8],
dispatchable: Option<&Dispatchable>,
handle: &DomainDispatcherHandle,
) -> bool;
}
pub struct DomainDispatcherHandle {
ptr: *mut RawDomainDispatcher,
}
impl DomainDispatcherHandle {
pub fn send_response(
&self,
call_id: i32,
response: DispatchResponse,
result: Option<Serializable>,
) {
unsafe {
let result_ptr = match result {
Some(r) => r.into_raw(),
None => std::ptr::null_mut(),
};
crdtp__DomainDispatcher__sendResponse(
self.ptr,
call_id,
response.into_raw(),
result_ptr,
);
}
}
}
struct DomainDispatcherData {
ptr: *mut RawDomainDispatcher,
imp: Box<dyn DomainDispatcherImpl>,
domain_bytes: Vec<u8>,
}
pub struct DomainDispatcher;
impl DomainDispatcher {
pub fn wire(
uber: &mut UberDispatcher,
domain: &str,
imp: Box<dyn DomainDispatcherImpl>,
) {
let domain_bytes = domain.as_bytes().to_vec();
let mut dd = Box::new(DomainDispatcherData {
ptr: std::ptr::null_mut(),
imp,
domain_bytes,
});
unsafe {
let rust_ptr =
&mut *dd as *mut DomainDispatcherData as *mut std::ffi::c_void;
let channel = crdtp__UberDispatcher__channel(uber);
let raw = crdtp__DomainDispatcher__new(channel, rust_ptr);
dd.ptr = raw;
crdtp__UberDispatcher__WireBackend(
uber,
dd.domain_bytes.as_ptr(),
dd.domain_bytes.len(),
raw,
);
}
let _ = Box::into_raw(dd);
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn crdtp__DomainDispatcher__BASE__Dispatch(
rust_dispatcher: *mut std::ffi::c_void,
command_data: *const u8,
command_len: usize,
dispatchable: *const Dispatchable,
) -> bool {
unsafe {
let dd = &mut *(rust_dispatcher as *mut DomainDispatcherData);
let command = std::slice::from_raw_parts(command_data, command_len);
let handle = DomainDispatcherHandle { ptr: dd.ptr };
let dispatchable_ref = if dispatchable.is_null() {
None
} else {
Some(&*dispatchable)
};
dd.imp.dispatch(command, dispatchable_ref, &handle)
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn crdtp__DomainDispatcher__BASE__Drop(
rust_dispatcher: *mut std::ffi::c_void,
) {
unsafe {
drop(Box::from_raw(rust_dispatcher as *mut DomainDispatcherData));
}
}