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
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use crate::Config;
use interoptopus::lang::c::{
    CType, CompositeType, Constant, ConstantValue, EnumType, FnPointerType, Function, OpaqueType, Parameter, PrimitiveType, PrimitiveValue, Variant,
};
use interoptopus::util::safe_name;

/// Implements [`CTypeConverter`].
#[derive(Clone)]
pub struct Converter {
    pub(crate) config: Config,
}

/// Converts Interoptopus types to C types.
pub trait CTypeConverter {
    fn config(&self) -> &Config;

    /// Converts a primitive (Rust) type to a native C# type name, e.g., `f32` to `float`.
    fn primitive_to_typename(&self, x: &PrimitiveType) -> String;

    /// Converts a Rust enum name such as `Error` to a C# enum name `Error`.
    fn enum_to_typename(&self, x: &EnumType) -> String;

    fn enum_variant_to_name(&self, x: &Variant) -> String;

    /// TODO Converts an opaque Rust struct `Context` to a C# struct ``.
    fn opaque_to_typename(&self, opaque: &OpaqueType) -> String;

    /// Converts an Rust struct name `Vec2` to a C# struct name `Vec2`.
    fn composite_to_typename(&self, x: &CompositeType) -> String;

    /// Converts an Rust `fn()` to a C# delegate name such as `InteropDelegate`.
    fn fnpointer_to_typename(&self, x: &FnPointerType) -> String;

    /// Converts the `u32` part in a Rust paramter `x: u32` to a C# equivalent. Might convert pointers to `out X` or `ref X`.
    fn to_type_specifier(&self, x: &CType) -> String;

    fn const_name_to_name(&self, x: &Constant) -> String;

    fn constant_value_to_value(&self, value: &ConstantValue) -> String;

    fn function_parameter_to_csharp_typename(&self, x: &Parameter, _function: &Function) -> String;

    fn function_name_to_c_name(&self, function: &Function) -> String;
}

impl CTypeConverter for Converter {
    fn config(&self) -> &Config {
        &self.config
    }

    fn primitive_to_typename(&self, x: &PrimitiveType) -> String {
        match x {
            PrimitiveType::Void => "void".to_string(),
            PrimitiveType::Bool => "bool".to_string(),
            PrimitiveType::U8 => "uint8_t".to_string(),
            PrimitiveType::U16 => "uint16_t".to_string(),
            PrimitiveType::U32 => "uint32_t".to_string(),
            PrimitiveType::U64 => "uint64_t".to_string(),
            PrimitiveType::I8 => "int8_t".to_string(),
            PrimitiveType::I16 => "int16_t".to_string(),
            PrimitiveType::I32 => "int32_t".to_string(),
            PrimitiveType::I64 => "int64_t".to_string(),
            PrimitiveType::F32 => "float".to_string(),
            PrimitiveType::F64 => "double".to_string(),
        }
    }

    fn enum_to_typename(&self, x: &EnumType) -> String {
        format!("{}{}", self.config().prefix, x.rust_name().to_string()).to_lowercase()
    }

    fn enum_variant_to_name(&self, x: &Variant) -> String {
        format!("{}{}", self.config().prefix, x.name().to_string()).to_uppercase()
    }

    fn opaque_to_typename(&self, x: &OpaqueType) -> String {
        format!("{}{}", self.config().prefix, x.rust_name().to_string()).to_lowercase()
    }

    fn composite_to_typename(&self, x: &CompositeType) -> String {
        format!("{}{}", self.config().prefix, x.rust_name().to_string()).to_lowercase()
    }

    fn fnpointer_to_typename(&self, x: &FnPointerType) -> String {
        let prefixed = format!("{}fptr", self.config().prefix);
        vec![prefixed, safe_name(&x.internal_name())].join("_")
    }

    fn to_type_specifier(&self, x: &CType) -> String {
        match x {
            CType::Primitive(x) => self.primitive_to_typename(x),
            CType::Enum(x) => self.enum_to_typename(x),
            CType::Opaque(x) => self.opaque_to_typename(x),
            CType::Composite(x) => self.composite_to_typename(x),
            CType::ReadPointer(x) => format!("{}*", self.to_type_specifier(x)),
            CType::ReadWritePointer(x) => format!("{}*", self.to_type_specifier(x)),
            CType::FnPointer(x) => self.fnpointer_to_typename(x),
            CType::Pattern(x) => self.to_type_specifier(&x.fallback_type()),
        }
    }

    fn const_name_to_name(&self, x: &Constant) -> String {
        format!("{}{}", self.config().prefix, x.name().to_string()).to_uppercase()
    }

    fn constant_value_to_value(&self, value: &ConstantValue) -> String {
        match value {
            ConstantValue::Primitive(x) => match x {
                PrimitiveValue::Bool(x) => format!("{}", x),
                PrimitiveValue::U8(x) => format!("{}", x),
                PrimitiveValue::U16(x) => format!("{}", x),
                PrimitiveValue::U32(x) => format!("{}", x),
                PrimitiveValue::U64(x) => format!("{}", x),
                PrimitiveValue::I8(x) => format!("{}", x),
                PrimitiveValue::I16(x) => format!("{}", x),
                PrimitiveValue::I32(x) => format!("{}", x),
                PrimitiveValue::I64(x) => format!("{}", x),
                PrimitiveValue::F32(x) => format!("{}", x),
                PrimitiveValue::F64(x) => format!("{}", x),
            },
        }
    }

    fn function_parameter_to_csharp_typename(&self, x: &Parameter, _function: &Function) -> String {
        self.to_type_specifier(x.the_type())
    }

    fn function_name_to_c_name(&self, function: &Function) -> String {
        function.name().to_string()
    }
}