use std::fmt::Display;
use crate::extern_module_translator::{
ExternModuleTranslator,
Function,
RustWrapperType,
WrapperType,
};
use crate::{DROP_FUNCTION_SYMBOL_NAME, EXPORTED_SYMBOLS_PREFIX};
pub const RUST_EXCEPTION_BASE_CLASS_NAME: &str = "RustExceptionBase";
pub const IMPORTS: &str = r#"
#include <string>
#include <cstring>
#include <memory>
#include <utility>
#include <stdexcept>
#include <cstdint>
"#;
pub const TYPEDEFS: &str = r#"
using u8 = unsigned char;
using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
using i8 = char;
using i16 = short;
using i32 = int;
using i64 = long long;
using f32 = float;
using f64 = double;
using isize = int;
using usize = unsigned int;
"#;
pub trait TargetLanguageTypeName {
fn get_name(&self) -> String;
fn get_name_for_abstract_method(&self) -> String;
}
impl TargetLanguageTypeName for WrapperType {
fn get_name(&self) -> String {
match self {
WrapperType {
rust_type: RustWrapperType::Vector(inner_type),
..
} => {
let inner_name = inner_type.get_name();
format!("RustVec<{inner_name}>")
}
WrapperType {
rust_type: RustWrapperType::Option(inner_type),
..
} => {
let inner_name = inner_type.get_name();
format!("Optional<{inner_name}>")
}
WrapperType {
rust_type: RustWrapperType::Result(ok_type, _),
..
} => ok_type.get_name(),
_ => self.wrapper_name.clone(),
}
}
fn get_name_for_abstract_method(&self) -> String {
match self {
WrapperType {
rust_type: RustWrapperType::Vector(inner_type),
..
} => {
let inner_name = inner_type.get_name();
format!("RustVec<{inner_name}>")
}
WrapperType {
rust_type: RustWrapperType::Option(inner_type),
..
} => {
let inner_name = inner_type.get_name();
format!("Optional<{inner_name}>")
}
_ => self.wrapper_name.clone(),
}
}
}
pub const PREDEFINED: &str = const_format::formatcp!(
r#"
extern "C" {{
void {DROP_FUNCTION_SYMBOL_NAME}(void* input) {{
}}
}}
template <typename T>
class Optional {{
void* self = nullptr;
bool is_owned = false;
public:
Optional();
Optional(T val);
Optional(void* self, bool is_owned = true) : self(self), is_owned(is_owned) {{}}
Optional(Optional&& a) : self(a.self), is_owned(a.is_owned) {{ a.self = nullptr; a.is_owned = false; }};
Optional(const Optional& a);
Optional& operator=(const Optional& a);
virtual ~Optional();
T unwrap();
bool is_some();
operator void*() {{
this->is_owned = false;
return this->self;
}}
void* as_ref() const {{
return this->self;
}}
}};
template <typename T>
class RustVec;
// RustIterator is separated from the RustVec class because SWIG does not fully support nested classes.
template <typename T>
struct RustIterator {{
RustIterator(T* buf_ptr, size_t index, bool is_primitive, RustVec<T>* vec)
: buf_ptr(buf_ptr), is_primitive(is_primitive), index(index), vec(vec)
{{}}
T operator*() const {{
return deref();
}}
T operator->() {{
return deref();
}}
RustIterator& operator++() {{
index++; return *this;
}}
RustIterator operator++(int) {{
RustIterator tmp = *this; ++(*this); return tmp;
}}
RustIterator operator+(int advance) {{
return RustIterator(buf_ptr, index + advance, is_primitive, vec);
}}
RustIterator& operator--() {{
index--; return *this;
}}
RustIterator operator--(int) {{
RustIterator tmp = *this; --(*this); return tmp;
}}
RustIterator operator-(int advance) {{
return RustIterator(buf_ptr, index - advance, is_primitive, vec);
}}
friend bool operator== (const RustIterator& a, const RustIterator& b) {{ return a.buf_ptr == b.buf_ptr && a.index == b.index ; }};
friend bool operator!= (const RustIterator& a, const RustIterator& b) {{ return a.buf_ptr != b.buf_ptr || a.index != b.index ; }};
private:
T deref() const {{
if (is_primitive) {{
return *(buf_ptr + index);
}} else {{
return vec->at(index).unwrap();
}}
}}
RustVec<T>* vec;
T* buf_ptr;
bool is_primitive;
size_t index;
}};
template <typename T>
class RustVec {{
void* self = nullptr;
bool is_owned = false;
T* as_mut_ptr();
public:
RustVec();
RustVec(RustVec&& a) : self(a.self), is_owned(a.is_owned) {{
a.self = nullptr;
a.is_owned = false;
}};
RustVec(const RustVec&);
RustVec& operator=(const RustVec&);
RustVec(void* self, bool is_owned = true)
: self(self), is_owned(is_owned) {{}}
virtual ~RustVec();
operator void*() {{
this->is_owned = false;
return this->self;
}}
void* as_ref() const {{
return this->self;
}}
void push(T item);
Optional<T> at(usize index);
size_t size();
RustIterator<T> begin();
RustIterator<T> end();
}};
class RustString {{
void* self = nullptr;
bool is_owned = false;
public:
RustString() = default;
RustString(void* self, bool is_owned = true)
: self(self), is_owned(is_owned) {{}}
RustString(const char* str) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$from_c_str((void*) str);
this->is_owned = true;
}}
RustString(std::string str) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$from_c_str((void*) str.data());
this->is_owned = true;
}}
RustString(const RustString& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$clone(a.self);
this->is_owned = true;
}}
RustString(RustString&& a)
: self(a.self),
is_owned(a.is_owned) {{
a.self = nullptr;
a.is_owned = false;
}}
RustString& operator=(const RustString& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$clone(a.self);
this->is_owned = true;
return *this;
}};
RustString& operator=(RustString&& a) {{
this->is_owned = true;
a.is_owned = false;
this->self = a.self;
a.self = nullptr;
return *this;
}}
std::string to_string() {{
char* str = (char*) {EXPORTED_SYMBOLS_PREFIX}$RustString$as_mut_ptr(this->self);
usize length = {EXPORTED_SYMBOLS_PREFIX}$RustString$len(this->self);
return std::string(str, length);
}}
operator void*() {{
this->is_owned = false;
return this->self;
}}
void* as_ref() const {{
return this->self;
}}
virtual ~RustString() {{
if(is_owned && self != nullptr) {{
{EXPORTED_SYMBOLS_PREFIX}$RustString$drop(this->self);
}}
}}
}};
using String = RustString;
"#
);
pub fn begin_end_impl(inner_type: &str, rust_type: &RustWrapperType) -> String {
let is_primitive = if matches!(rust_type, RustWrapperType::Primitive) {
"true"
} else {
"false"
};
format!(
"
template<>
RustIterator<{inner_type}> RustVec<{inner_type}>::begin() {{
return RustIterator( as_mut_ptr(), 0, {is_primitive}, this );
}}
template<>
RustIterator<{inner_type}> RustVec<{inner_type}>::end() {{
return RustIterator( as_mut_ptr(), size(), {is_primitive}, this );
}}
"
)
}
pub fn vector_impl(inner_type: &str, rust_wrapper_name: &str) -> String {
format!(
"
template<>
RustVec<{inner_type}>::~RustVec()
{{
if(this->self && this->is_owned) {{
{EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$drop(this->self);
}}
}}
template<>
void RustVec<{inner_type}>::push({inner_type} item) {{
{EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$push(this->self, item);
}}
template<>
RustVec<{inner_type}>::RustVec(const RustVec& vec) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$clone(vec.self);
this->is_owned = true;
}}
template<>
RustVec<{inner_type}>& RustVec<{inner_type}>::operator=(const RustVec& vec) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$clone(vec.self);
this->is_owned = true;
return *this;
}}
template<>
RustVec<{inner_type}>::RustVec() {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$new();
this->is_owned = true;
}}
template<>
Optional<{inner_type}> RustVec<{inner_type}>::at(usize index) {{
return Optional<{inner_type}>({EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$get(this->self, index));
}}
template<>
{inner_type}* RustVec<{inner_type}>::as_mut_ptr() {{
return ({inner_type}*) {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$as_mut_ptr(this->self);
}}
template<>
size_t RustVec<{inner_type}>::size() {{
return (size_t) {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$len(this->self);
}}"
)
}
pub fn option_class(inner_type: &str, rust_wrapper_name: &str) -> String {
format!(
"
template<>
Optional<{inner_type}>::Optional() {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$default();
this->is_owned = true;
}}
template<>
Optional<{inner_type}>::Optional({inner_type} val) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$from(val);
this->is_owned = true;
}}
template<>
Optional<{inner_type}>::Optional(const Optional<{inner_type}>& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$clone(a.self);
this->is_owned = true;
}}
template<>
Optional<{inner_type}>& Optional<{inner_type}>::operator=(const Optional<{inner_type}>& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$clone(a.self);
this->is_owned = true;
return *this;
}}
template<>
Optional<{inner_type}>::~Optional() {{
if(this->self && this->is_owned) {{
{EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$drop(this->self);
}}
}};
template<>
{inner_type} Optional<{inner_type}>::unwrap() {{
auto cloned = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$clone(this->self);
return {inner_type}({EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$unwrap(cloned));
}}
template<>
bool Optional<{inner_type}>::is_some() {{
return {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$is_some(this->self);
}}
"
)
}
pub fn result_class(name: &str, ok_type: &str, err_type: &str) -> String {
format!(
"
class {name} {{
void* self = nullptr;
bool is_owned = false;
public:
{name}() = default;
{name}({name}&& a) : self(a.self), is_owned(a.is_owned) {{
a.self = nullptr;
a.is_owned = false;
}};
{name}(const {name}& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
this->is_owned = true;
}}
{name}& operator=(const {name}& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
this->is_owned = true;
return *this;
}}
{name}(void* self, bool is_owned = true) : self(self), is_owned(is_owned) {{ }}
virtual ~{name}() {{
if(this->self && this->is_owned) {{
{EXPORTED_SYMBOLS_PREFIX}${name}$drop(this->self);
}}
}}
static {name} from_ok({ok_type} val) {{
return {name}({EXPORTED_SYMBOLS_PREFIX}${name}$from_ok(val));
}}
static {name} from_err({err_type} val) {{
return {name}({EXPORTED_SYMBOLS_PREFIX}${name}$from_err(val));
}}
{ok_type} unwrap() {{
auto cloned = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(this->self);
return {ok_type}({EXPORTED_SYMBOLS_PREFIX}${name}$unwrap(cloned));
}}
{err_type} unwrap_err() {{
auto cloned = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(this->self);
return {err_type}({EXPORTED_SYMBOLS_PREFIX}${name}$unwrap_err_unchecked(cloned));
}}
bool is_ok() {{
return {EXPORTED_SYMBOLS_PREFIX}${name}$is_ok(this->self);
}}
operator void*() {{
this->is_owned = false;
return this->self;
}}
void* as_ref() const {{
return this->self;
}}
}};
"
)
}
pub fn custom_class_definition(name: impl Display, functions_declaration: impl Display) -> String {
format!(
"
class {name} {{
void* self = nullptr;
bool is_owned = false;
public:
{name}() = default;
{name}(void* self, bool is_owned = true) : self(self), is_owned(is_owned) {{ }}
{name}({name}&& a) : self(a.self), is_owned(a.is_owned) {{ a.self = nullptr; a.is_owned = false; }};
{name}(const {name}& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
this->is_owned = true;
}}
{name}& operator=(const {name}& a) {{
this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
this->is_owned = true;
return *this;
}}
{name}& operator=({name}&& a) {{
this->is_owned = true;
a.is_owned = false;
this->self = a.self;
a.self = nullptr;
return *this;
}}
virtual ~{name}() {{ if(this->self && this->is_owned) {{ {EXPORTED_SYMBOLS_PREFIX}${name}$drop(this->self); }} }};
operator void*() {{
this->is_owned = false;
return this->self;
}}
void* raw_self() const {{ return this->self;}}
void* as_ref() const {{
return this->self;
}}
{functions_declaration}
}};
\n")
}
pub fn abstract_class_declaration(name: &str, functions_declaration: &str) -> String {
format!(
"
class {name} {{
public:
{name}() = default;
virtual ~{name}() {{}};
operator void*() const {{
return (void*) this;
}}
{functions_declaration}}};
\n"
)
}
pub fn create_non_primitive_exception_class<'a>(
exception: &impl Display,
err_name: &impl Display,
custom_methods: impl Iterator<Item = &'a Function>,
) -> String {
let custom_methods =
create_non_primitive_enum_exception_custom_methods(custom_methods, err_name);
format_exception_class(exception, err_name, &custom_methods)
}
pub fn create_primitive_exception_class<'a>(
exception: &impl Display,
err_name: &impl Display,
custom_methods: impl Iterator<Item = &'a Function>,
) -> String {
let custom_methods = create_primitive_enum_exception_custom_methods(custom_methods, err_name);
format_exception_class(exception, err_name, &custom_methods)
}
pub fn exception_class_name(
error_enum_name: impl Display,
exception_variant: impl Display,
) -> String {
format!("{error_enum_name}_{exception_variant}Exception")
}
fn format_exception_class(
exception: &impl Display,
err_name: &impl Display,
custom_methods: &impl Display,
) -> String {
let exception_name = exception_class_name(err_name, exception);
format!(
"
class {exception_name} : public {RUST_EXCEPTION_BASE_CLASS_NAME} {{
{err_name} err;
public:
{exception_name}({err_name} err) : err{{err}} {{}}
virtual const char* what() const throw() override
{{
return \"{exception_name} thrown from Rust\";
}}
virtual ExceptionClass exception_class() override {{
return ExceptionClass::{exception_name};
}}
{custom_methods}
}};
"
)
}
fn create_exception_custom_methods<'a>(
custom_methods: impl Iterator<Item = &'a Function>,
err_name: &impl Display,
inner_err_cast: &(impl Display + ?Sized),
) -> impl Display {
custom_methods
.map(|fun| {
let return_type = fun
.return_type
.as_ref()
.map(|wrapper| wrapper.wrapper_name.as_str())
.unwrap_or("");
let function_name = &fun.name;
let ffi_call = format!("{EXPORTED_SYMBOLS_PREFIX}${err_name}${function_name}");
let ffi_call = format!("{ffi_call}({inner_err_cast})");
let ffi_call = match &fun.return_type {
None
| Some(WrapperType {
rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
..
}) => ffi_call,
Some(WrapperType { wrapper_name, .. }) => {
format!("{wrapper_name}({ffi_call})")
}
};
format!(
" {return_type} {function_name}() const override {{
return {ffi_call};
}}"
)
})
.collect::<Vec<_>>()
.join("\n")
}
fn create_primitive_enum_exception_custom_methods<'a>(
custom_methods: impl Iterator<Item = &'a Function>,
err_name: &impl Display,
) -> impl Display {
create_exception_custom_methods(custom_methods, err_name, "(void*)&err")
}
fn create_non_primitive_enum_exception_custom_methods<'a>(
custom_methods: impl Iterator<Item = &'a Function>,
err_name: &impl Display,
) -> impl Display {
create_exception_custom_methods(custom_methods, err_name, "err.raw_self()")
}
fn base_exception_virtual_method(function: &Function) -> String {
let return_type = &function
.return_type
.as_ref()
.map(|t| t.get_name())
.unwrap_or_else(|| "".to_string());
let name = &function.name;
format!(
" virtual {return_type} {name}() const = 0;
"
)
}
fn wasm_delegated_exception_method(function: &Function) -> String {
let return_type = &function
.return_type
.as_ref()
.map(|t| t.get_name())
.unwrap_or_else(|| "".to_string());
let fun_name = &function.name;
format!(
" virtual {return_type} {fun_name}() const {{
return rbe->{fun_name}();
}};
"
)
}
pub fn base_exception_class(emt: &ExternModuleTranslator) -> String {
let exception_trait_virtual_methods = emt
.exception_trait_methods
.iter()
.map(base_exception_virtual_method)
.collect::<Vec<_>>()
.join("\n");
let wasm_delegated_methods = emt
.exception_trait_methods
.iter()
.map(wasm_delegated_exception_method)
.collect::<Vec<_>>()
.join("\n");
format!(
"class {RUST_EXCEPTION_BASE_CLASS_NAME} : public std::exception {{
public:
virtual const char* what() const throw()
{{
return \"Exception thrown from Rust\";
}}
virtual ExceptionClass exception_class() {{
return ExceptionClass::{RUST_EXCEPTION_BASE_CLASS_NAME};
}}
{exception_trait_virtual_methods}
}};
// Exceptions wrapper for WASM
class WasmException {{
std::shared_ptr<{RUST_EXCEPTION_BASE_CLASS_NAME}> rbe;
public:
WasmException(unsigned addr) : rbe{{({RUST_EXCEPTION_BASE_CLASS_NAME}*) addr}} {{}}
ExceptionClass exception_class() {{
return rbe->exception_class();
}}
std::string what() {{
return std::string{{rbe->what()}};
}}
{wasm_delegated_methods}
}};
"
)
}