rusty_bind_parser/cpp/
templates.rs

1//
2// Wildland Project
3//
4// Copyright © 2022 Golem Foundation,
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License version 3 as published by
8// the Free Software Foundation.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18use std::fmt::Display;
19
20use crate::extern_module_translator::{
21    ExternModuleTranslator,
22    Function,
23    RustWrapperType,
24    WrapperType,
25};
26use crate::{DROP_FUNCTION_SYMBOL_NAME, EXPORTED_SYMBOLS_PREFIX};
27
28pub const RUST_EXCEPTION_BASE_CLASS_NAME: &str = "RustExceptionBase";
29pub const IMPORTS: &str = r#"
30#include <string>
31#include <cstring>
32#include <memory>
33#include <utility>
34#include <stdexcept>
35#include <cstdint>
36"#;
37
38pub const TYPEDEFS: &str = r#"
39using u8 = unsigned char;
40using u16 = unsigned short;
41using u32 = unsigned int;
42using u64 = unsigned long long;
43
44using i8 = char;
45using i16 = short;
46using i32 = int;
47using i64 = long long;
48
49using f32 = float;
50using f64 = double;
51
52using isize = int;
53using usize = unsigned int;
54"#;
55
56pub trait TargetLanguageTypeName {
57    fn get_name(&self) -> String;
58    fn get_name_for_abstract_method(&self) -> String;
59}
60
61impl TargetLanguageTypeName for WrapperType {
62    fn get_name(&self) -> String {
63        match self {
64            WrapperType {
65                rust_type: RustWrapperType::Vector(inner_type),
66                ..
67            } => {
68                let inner_name = inner_type.get_name();
69                format!("RustVec<{inner_name}>")
70            }
71            WrapperType {
72                rust_type: RustWrapperType::Option(inner_type),
73                ..
74            } => {
75                let inner_name = inner_type.get_name();
76                format!("Optional<{inner_name}>")
77            }
78            WrapperType {
79                rust_type: RustWrapperType::Result(ok_type, _),
80                ..
81            } => ok_type.get_name(),
82            _ => self.wrapper_name.clone(),
83        }
84    }
85    fn get_name_for_abstract_method(&self) -> String {
86        match self {
87            WrapperType {
88                rust_type: RustWrapperType::Vector(inner_type),
89                ..
90            } => {
91                let inner_name = inner_type.get_name();
92                format!("RustVec<{inner_name}>")
93            }
94            WrapperType {
95                rust_type: RustWrapperType::Option(inner_type),
96                ..
97            } => {
98                let inner_name = inner_type.get_name();
99                format!("Optional<{inner_name}>")
100            }
101            _ => self.wrapper_name.clone(),
102        }
103    }
104}
105
106/// Predefined C++ classes and primitive types typedefs useful
107/// during the standard work on FFI basic structures. It
108/// consists of a custom RustVector and String implementations
109/// that keep track of some object ownership aspects. Items
110/// returned by `RustVec::at(x)` method should be treated as
111/// references, since the underlying objects are owned by
112/// the vector.
113///
114pub const PREDEFINED: &str = const_format::formatcp!(
115    r#"
116extern "C" {{
117    void {DROP_FUNCTION_SYMBOL_NAME}(void* input) {{
118    }}
119}}
120
121template <typename T>
122class Optional {{
123    void* self = nullptr;
124    bool is_owned = false;
125public:
126    Optional();
127    Optional(T val);
128    Optional(void* self, bool is_owned = true) : self(self), is_owned(is_owned) {{}}
129    Optional(Optional&& a) : self(a.self), is_owned(a.is_owned) {{ a.self = nullptr; a.is_owned = false; }};
130    Optional(const Optional& a);
131    Optional& operator=(const Optional& a);
132    virtual ~Optional();
133    T unwrap();
134    bool is_some();
135    operator void*() {{
136        this->is_owned = false;
137        return this->self;
138    }}
139    void* as_ref() const {{
140        return this->self;
141    }}
142}};
143
144template <typename T>
145class RustVec;
146
147// RustIterator is separated from the RustVec class because SWIG does not fully support nested classes.
148template <typename T>
149struct RustIterator {{
150    RustIterator(T* buf_ptr, size_t index, bool is_primitive, RustVec<T>* vec)
151    : buf_ptr(buf_ptr), is_primitive(is_primitive), index(index), vec(vec)
152    {{}}
153
154    T operator*() const {{
155        return deref();
156    }}
157    T operator->() {{
158        return deref();
159    }}
160
161    RustIterator& operator++() {{
162        index++; return *this;
163    }}
164    RustIterator operator++(int) {{
165        RustIterator tmp = *this; ++(*this); return tmp;
166    }}
167    RustIterator operator+(int advance) {{
168        return RustIterator(buf_ptr, index + advance, is_primitive, vec);
169    }}
170
171    RustIterator& operator--() {{
172        index--; return *this;
173    }}
174    RustIterator operator--(int) {{
175        RustIterator tmp = *this; --(*this); return tmp;
176    }}
177    RustIterator operator-(int advance) {{
178        return RustIterator(buf_ptr, index - advance, is_primitive, vec);
179    }}
180
181    friend bool operator== (const RustIterator& a, const RustIterator& b) {{ return a.buf_ptr == b.buf_ptr && a.index == b.index ; }};
182    friend bool operator!= (const RustIterator& a, const RustIterator& b) {{ return a.buf_ptr != b.buf_ptr || a.index != b.index ; }};
183
184private:
185    T deref() const {{
186        if (is_primitive) {{
187            return *(buf_ptr + index);
188        }} else {{
189            return vec->at(index).unwrap();
190        }}
191    }}
192
193    RustVec<T>* vec;
194    T* buf_ptr;
195    bool is_primitive;
196    size_t index;
197}};
198
199template <typename T>
200class RustVec {{
201    void* self = nullptr;
202    bool is_owned = false;
203
204    T* as_mut_ptr();
205
206public:
207    RustVec();
208    RustVec(RustVec&& a) : self(a.self), is_owned(a.is_owned) {{
209        a.self = nullptr;
210        a.is_owned = false;
211    }};
212    RustVec(const RustVec&);
213    RustVec& operator=(const RustVec&);
214    RustVec(void* self, bool is_owned = true)
215        : self(self), is_owned(is_owned) {{}}
216    virtual ~RustVec();
217    operator void*() {{
218        this->is_owned = false;
219        return this->self;
220    }}
221    void* as_ref() const {{
222        return this->self;
223    }}
224    void push(T item);
225    Optional<T> at(usize index);
226    size_t size();
227
228    RustIterator<T> begin();
229    RustIterator<T> end();
230}};
231
232class RustString {{
233    void* self = nullptr;
234    bool is_owned = false;
235public:
236    RustString() = default;
237    RustString(void* self, bool is_owned = true)
238        : self(self), is_owned(is_owned) {{}}
239    RustString(const char* str) {{
240        this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$from_c_str((void*) str);
241        this->is_owned = true;
242    }}
243    RustString(std::string str) {{
244        this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$from_c_str((void*) str.data());
245        this->is_owned = true;
246    }}
247    RustString(const RustString& a) {{
248        this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$clone(a.self);
249        this->is_owned = true;
250    }}
251    RustString(RustString&& a)
252        : self(a.self),
253          is_owned(a.is_owned) {{
254        a.self = nullptr;
255        a.is_owned = false;
256    }}
257    RustString& operator=(const RustString& a) {{
258        this->self = {EXPORTED_SYMBOLS_PREFIX}$RustString$clone(a.self);
259        this->is_owned = true;
260        return *this;
261    }};
262    RustString& operator=(RustString&& a) {{
263        this->is_owned = true;
264        a.is_owned = false;
265        this->self = a.self;
266        a.self = nullptr;
267        return *this;
268    }}
269    std::string to_string() {{
270        char* str = (char*) {EXPORTED_SYMBOLS_PREFIX}$RustString$as_mut_ptr(this->self);
271        usize length = {EXPORTED_SYMBOLS_PREFIX}$RustString$len(this->self);
272        return std::string(str, length);
273    }}
274    operator void*() {{
275        this->is_owned = false;
276        return this->self;
277    }}
278    void* as_ref() const {{
279        return this->self;
280    }}
281    virtual ~RustString() {{
282        if(is_owned && self != nullptr) {{
283            {EXPORTED_SYMBOLS_PREFIX}$RustString$drop(this->self);
284        }}
285    }}
286}};
287
288using String = RustString;
289"#
290);
291
292/// Creates an implementation of RustVec<T> begin and end implementation.
293/// It should be generated for primitive types only, cause pointer arithmetics for Rust opaque types is not trivial.
294///
295pub fn begin_end_impl(inner_type: &str, rust_type: &RustWrapperType) -> String {
296    let is_primitive = if matches!(rust_type, RustWrapperType::Primitive) {
297        "true"
298    } else {
299        "false"
300    };
301    format!(
302        "
303template<>
304RustIterator<{inner_type}> RustVec<{inner_type}>::begin() {{
305    return RustIterator( as_mut_ptr(), 0, {is_primitive}, this );
306}}
307template<>
308RustIterator<{inner_type}> RustVec<{inner_type}>::end() {{
309    return RustIterator( as_mut_ptr(), size(), {is_primitive}, this );
310}}
311"
312    )
313}
314
315/// Creates an implementation of RustVec<T> for a given T that maps to the Rust Vec<T> object.
316///
317pub fn vector_impl(inner_type: &str, rust_wrapper_name: &str) -> String {
318    format!(
319        "
320template<>
321RustVec<{inner_type}>::~RustVec()
322{{
323    if(this->self && this->is_owned) {{
324        {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$drop(this->self);
325    }}
326}}
327
328template<>
329void RustVec<{inner_type}>::push({inner_type} item) {{
330    {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$push(this->self, item);
331}}
332template<>
333RustVec<{inner_type}>::RustVec(const RustVec& vec) {{
334    this->self = {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$clone(vec.self);
335    this->is_owned = true;
336}}
337template<>
338RustVec<{inner_type}>& RustVec<{inner_type}>::operator=(const RustVec& vec) {{
339    this->self = {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$clone(vec.self);
340    this->is_owned = true;
341    return *this;
342}}
343template<>
344RustVec<{inner_type}>::RustVec() {{
345    this->self = {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$new();
346    this->is_owned = true;
347}}
348template<>
349Optional<{inner_type}> RustVec<{inner_type}>::at(usize index) {{
350    return Optional<{inner_type}>({EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$get(this->self, index));
351}}
352template<>
353{inner_type}* RustVec<{inner_type}>::as_mut_ptr() {{
354    return ({inner_type}*) {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$as_mut_ptr(this->self);
355}}
356template<>
357size_t RustVec<{inner_type}>::size() {{
358    return (size_t) {EXPORTED_SYMBOLS_PREFIX}$Vec{rust_wrapper_name}$len(this->self);
359}}"
360    )
361}
362
363/// Creates a class that maps onto the Rust Option<T> object.
364/// The ownership depends on the source from which the object is created.
365///
366pub fn option_class(inner_type: &str, rust_wrapper_name: &str) -> String {
367    format!(
368        "
369template<>
370Optional<{inner_type}>::Optional() {{
371    this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$default();
372    this->is_owned = true;
373}}
374template<>
375Optional<{inner_type}>::Optional({inner_type} val) {{
376    this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$from(val);
377    this->is_owned = true;
378}}
379template<>
380Optional<{inner_type}>::Optional(const Optional<{inner_type}>& a) {{
381    this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$clone(a.self);
382    this->is_owned = true;
383}}
384template<>
385Optional<{inner_type}>& Optional<{inner_type}>::operator=(const Optional<{inner_type}>& a) {{
386    this->self = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$clone(a.self);
387    this->is_owned = true;
388    return *this;
389}}
390template<>
391Optional<{inner_type}>::~Optional() {{
392    if(this->self && this->is_owned) {{
393        {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$drop(this->self);
394    }}
395}};
396template<>
397{inner_type} Optional<{inner_type}>::unwrap() {{
398    auto cloned = {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$clone(this->self);
399    return {inner_type}({EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$unwrap(cloned));
400}}
401template<>
402bool Optional<{inner_type}>::is_some() {{
403    return {EXPORTED_SYMBOLS_PREFIX}$Optional{rust_wrapper_name}$is_some(this->self);
404}}
405"
406    )
407}
408
409/// Creates a class that maps onto the Rust Result<T, E> object.
410/// The ownership depends on the source from which the object is created.
411///
412pub fn result_class(name: &str, ok_type: &str, err_type: &str) -> String {
413    format!(
414        "
415class {name} {{
416    void* self = nullptr;
417    bool is_owned = false;
418public:
419    {name}() = default;
420    {name}({name}&& a) : self(a.self), is_owned(a.is_owned) {{
421        a.self = nullptr;
422        a.is_owned = false;
423    }};
424    {name}(const {name}& a) {{
425        this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
426        this->is_owned = true;
427    }}
428    {name}& operator=(const {name}& a) {{
429        this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
430        this->is_owned = true;
431        return *this;
432    }}
433    {name}(void* self, bool is_owned = true) : self(self), is_owned(is_owned) {{ }}
434    virtual ~{name}() {{
435        if(this->self && this->is_owned) {{
436            {EXPORTED_SYMBOLS_PREFIX}${name}$drop(this->self);
437        }}
438    }}
439    static {name} from_ok({ok_type} val) {{
440        return {name}({EXPORTED_SYMBOLS_PREFIX}${name}$from_ok(val));
441    }}
442    static {name} from_err({err_type} val) {{
443        return {name}({EXPORTED_SYMBOLS_PREFIX}${name}$from_err(val));
444    }}
445    {ok_type} unwrap() {{
446        auto cloned = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(this->self);
447        return {ok_type}({EXPORTED_SYMBOLS_PREFIX}${name}$unwrap(cloned));
448    }}
449    {err_type} unwrap_err() {{
450        auto cloned = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(this->self);
451        return {err_type}({EXPORTED_SYMBOLS_PREFIX}${name}$unwrap_err_unchecked(cloned));
452    }}
453    bool is_ok() {{
454        return {EXPORTED_SYMBOLS_PREFIX}${name}$is_ok(this->self);
455    }}
456    operator void*() {{
457        this->is_owned = false;
458        return this->self;
459    }}
460    void* as_ref() const {{
461        return this->self;
462    }}
463}};
464"
465    )
466}
467
468/// Creates a class that maps onto the custom structures with methods
469/// that are available in the FFI.
470/// The ownership depends on the source from which the object is created.
471///
472pub fn custom_class_definition(name: impl Display, functions_declaration: impl Display) -> String {
473    format!(
474            "
475class {name} {{
476    void* self = nullptr;
477    bool is_owned = false;
478public:
479    {name}() = default;
480    {name}(void* self, bool is_owned = true) : self(self), is_owned(is_owned) {{ }}
481    {name}({name}&& a) : self(a.self), is_owned(a.is_owned) {{ a.self = nullptr; a.is_owned = false; }};
482    {name}(const {name}& a) {{
483        this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
484        this->is_owned = true;
485    }}
486    {name}& operator=(const {name}& a) {{
487        this->self = {EXPORTED_SYMBOLS_PREFIX}${name}$clone(a.self);
488        this->is_owned = true;
489        return *this;
490    }}
491    {name}& operator=({name}&& a) {{
492        this->is_owned = true;
493        a.is_owned = false;
494        this->self = a.self;
495        a.self = nullptr;
496        return *this;
497    }}
498    virtual ~{name}() {{ if(this->self && this->is_owned) {{ {EXPORTED_SYMBOLS_PREFIX}${name}$drop(this->self); }} }};
499    operator void*() {{
500        this->is_owned = false;
501        return this->self;
502    }}
503    void* raw_self() const {{ return this->self;}}
504    void* as_ref() const {{
505        return this->self;
506    }}
507{functions_declaration}
508}};
509\n")
510}
511
512/// Creates a class that maps onto the custom structures with methods
513/// that are available in the FFI.
514/// The ownership depends on the source from which the object is created.
515///
516pub fn abstract_class_declaration(name: &str, functions_declaration: &str) -> String {
517    format!(
518        "
519class {name} {{
520public:
521    {name}() = default;
522    virtual ~{name}() {{}};
523    operator void*() const {{
524        return (void*) this;
525    }}
526{functions_declaration}}};
527\n"
528    )
529}
530
531/// Creates exception class for an error variant that may be returned from rust
532pub fn create_non_primitive_exception_class<'a>(
533    exception: &impl Display,
534    err_name: &impl Display,
535    custom_methods: impl Iterator<Item = &'a Function>,
536) -> String {
537    let custom_methods =
538        create_non_primitive_enum_exception_custom_methods(custom_methods, err_name);
539    format_exception_class(exception, err_name, &custom_methods)
540}
541
542/// Creates exception class for an error variant of primitive enum that may be returned from rust
543pub fn create_primitive_exception_class<'a>(
544    exception: &impl Display,
545    err_name: &impl Display,
546    custom_methods: impl Iterator<Item = &'a Function>,
547) -> String {
548    let custom_methods = create_primitive_enum_exception_custom_methods(custom_methods, err_name);
549    format_exception_class(exception, err_name, &custom_methods)
550}
551
552pub fn exception_class_name(
553    error_enum_name: impl Display,
554    exception_variant: impl Display,
555) -> String {
556    format!("{error_enum_name}_{exception_variant}Exception")
557}
558
559fn format_exception_class(
560    exception: &impl Display,
561    err_name: &impl Display,
562    custom_methods: &impl Display,
563) -> String {
564    let exception_name = exception_class_name(err_name, exception);
565    format!(
566        "
567class {exception_name} : public {RUST_EXCEPTION_BASE_CLASS_NAME} {{
568    {err_name} err;
569    public:
570        {exception_name}({err_name} err) : err{{err}} {{}}
571
572        virtual const char* what() const throw() override
573        {{
574            return \"{exception_name} thrown from Rust\";
575        }}
576
577        virtual ExceptionClass exception_class() override {{
578            return ExceptionClass::{exception_name};
579        }}
580
581{custom_methods}
582    }};
583"
584    )
585}
586
587fn create_exception_custom_methods<'a>(
588    custom_methods: impl Iterator<Item = &'a Function>,
589    err_name: &impl Display,
590    inner_err_cast: &(impl Display + ?Sized),
591) -> impl Display {
592    custom_methods
593        .map(|fun| {
594            let return_type = fun
595                .return_type
596                .as_ref()
597                .map(|wrapper| wrapper.wrapper_name.as_str())
598                .unwrap_or("");
599            let function_name = &fun.name;
600            let ffi_call = format!("{EXPORTED_SYMBOLS_PREFIX}${err_name}${function_name}");
601            let ffi_call = format!("{ffi_call}({inner_err_cast})");
602            let ffi_call = match &fun.return_type {
603                None
604                | Some(WrapperType {
605                    rust_type: RustWrapperType::Primitive | RustWrapperType::FieldlessEnum,
606                    ..
607                }) => ffi_call,
608                Some(WrapperType { wrapper_name, .. }) => {
609                    format!("{wrapper_name}({ffi_call})")
610                }
611            };
612            format!(
613                "        {return_type} {function_name}() const override {{
614            return {ffi_call};
615        }}"
616            )
617        })
618        .collect::<Vec<_>>()
619        .join("\n")
620}
621
622fn create_primitive_enum_exception_custom_methods<'a>(
623    custom_methods: impl Iterator<Item = &'a Function>,
624    err_name: &impl Display,
625) -> impl Display {
626    create_exception_custom_methods(custom_methods, err_name, "(void*)&err")
627}
628
629fn create_non_primitive_enum_exception_custom_methods<'a>(
630    custom_methods: impl Iterator<Item = &'a Function>,
631    err_name: &impl Display,
632) -> impl Display {
633    create_exception_custom_methods(custom_methods, err_name, "err.raw_self()")
634}
635
636fn base_exception_virtual_method(function: &Function) -> String {
637    let return_type = &function
638        .return_type
639        .as_ref()
640        .map(|t| t.get_name())
641        .unwrap_or_else(|| "".to_string());
642    let name = &function.name;
643    format!(
644        "    virtual {return_type} {name}() const = 0;
645"
646    )
647}
648
649fn wasm_delegated_exception_method(function: &Function) -> String {
650    let return_type = &function
651        .return_type
652        .as_ref()
653        .map(|t| t.get_name())
654        .unwrap_or_else(|| "".to_string());
655    let fun_name = &function.name;
656    format!(
657        "    virtual {return_type} {fun_name}() const {{
658        return rbe->{fun_name}();
659    }};
660"
661    )
662}
663
664pub fn base_exception_class(emt: &ExternModuleTranslator) -> String {
665    let exception_trait_virtual_methods = emt
666        .exception_trait_methods
667        .iter()
668        .map(base_exception_virtual_method)
669        .collect::<Vec<_>>()
670        .join("\n");
671    let wasm_delegated_methods = emt
672        .exception_trait_methods
673        .iter()
674        .map(wasm_delegated_exception_method)
675        .collect::<Vec<_>>()
676        .join("\n");
677    format!(
678        "class {RUST_EXCEPTION_BASE_CLASS_NAME} : public std::exception {{
679public:
680    virtual const char* what() const throw()
681    {{
682        return \"Exception thrown from Rust\";
683    }}
684
685    virtual ExceptionClass exception_class() {{
686        return ExceptionClass::{RUST_EXCEPTION_BASE_CLASS_NAME};
687    }}
688
689{exception_trait_virtual_methods}
690}};
691
692// Exceptions wrapper for WASM
693class WasmException {{
694    std::shared_ptr<{RUST_EXCEPTION_BASE_CLASS_NAME}> rbe;
695public:
696    WasmException(unsigned addr) : rbe{{({RUST_EXCEPTION_BASE_CLASS_NAME}*) addr}} {{}}
697
698    ExceptionClass exception_class() {{
699        return rbe->exception_class();
700    }}
701
702    std::string what() {{
703        return std::string{{rbe->what()}};
704    }}
705
706{wasm_delegated_methods}
707}};
708"
709    )
710}