1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crate::model::*;

use crate::backend::c::cpp::conversion::{CoreCppType, ToNative};
use crate::backend::c::cpp::formatting::FriendClass;

pub(crate) trait ToNativeFunctionArgument {
    fn to_native_function_argument(&self, expr: String) -> String;

    // some function arguments cannot be converted at the call site
    // and require a shadow parameter. The shadow parameter itself
    // map require some mapping at the call site.
    fn shadow_parameter_mapping(&self) -> Option<Box<dyn Fn(String) -> String>>;

    fn requires_shadow_parameter(&self) -> bool {
        self.shadow_parameter_mapping().is_some()
    }
}

impl ToNativeFunctionArgument for FunctionArgument {
    fn to_native_function_argument(&self, expr: String) -> String {
        match self {
            FunctionArgument::Basic(x) => x.to_native(expr),
            FunctionArgument::String(x) => x.to_native(expr),
            FunctionArgument::Collection(x) => {
                format!("{}({})", x.collection_class.core_cpp_type(), expr)
            }
            FunctionArgument::Struct(_) => {
                format!("::convert::to_native({expr})")
            }
            FunctionArgument::StructRef(_) => {
                format!("::convert::to_native({expr})")
            }
            FunctionArgument::ClassRef(x) => {
                format!("{}::get({})", x.friend_class(), expr)
            }
            FunctionArgument::Interface(x) => match x.mode {
                InterfaceCategory::Synchronous => {
                    format!("::convert::to_native({expr})")
                }
                InterfaceCategory::Asynchronous => {
                    format!("::convert::to_native(std::move({expr}))")
                }
                InterfaceCategory::Future => {
                    format!("::convert::to_native(std::move({expr}))")
                }
            },
        }
    }

    fn shadow_parameter_mapping(&self) -> Option<Box<dyn Fn(String) -> String>> {
        match self {
            FunctionArgument::Basic(_) => None,
            FunctionArgument::String(_) => None,
            FunctionArgument::Collection(x) => {
                let friend_class = x.collection_class.friend_class();
                Some(Box::new(move |e| format!("{friend_class}::get({e})")))
            }
            FunctionArgument::Struct(_) => None,
            FunctionArgument::StructRef(_) => Some(Box::new(|e| format!("&{e}"))),
            FunctionArgument::ClassRef(_) => None,
            FunctionArgument::Interface(_) => None,
        }
    }
}