forked from CesiumGS/cesium-unity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CustomArrayGenerator.cs
151 lines (131 loc) · 7.71 KB
/
CustomArrayGenerator.cs
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using Microsoft.CodeAnalysis;
namespace Reinterop
{
internal class CustomArrayGenerator : ICustomGenerator
{
public IEnumerable<TypeToGenerate> GetDependencies(CppGenerationContext context)
{
yield break;
}
public GeneratedResult? Generate(CppGenerationContext context, TypeToGenerate type, GeneratedResult? generated)
{
// This generator only operates on arrays.
if (generated == null || !(type.Type is IArrayTypeSymbol arrayType))
return generated;
GenerateSizeConstructor(context, type, generated, arrayType);
GenerateItemMethod(context, type, generated, arrayType);
return generated;
}
/// <summary>
/// Add a constructor that can be used to create an array of a given size.
/// </summary>
private void GenerateSizeConstructor(CppGenerationContext context, TypeToGenerate item, GeneratedResult result, IArrayTypeSymbol arrayType)
{
GeneratedCppDeclaration declaration = result.CppDeclaration;
GeneratedCppDefinition definition = result.CppDefinition;
GeneratedInit init = result.Init;
string createBySizeName = $"Construct_Size";
declaration.Elements.Add(new(
Content: $"static void* (*{createBySizeName})(std::int32_t size);",
IsPrivate: true
));
declaration.Elements.Add(new(
Content: $"{declaration.Type.Name}(std::int32_t size);",
TypeDeclarationsReferenced: new[] { CppType.Int32 }
));
string templateSpecialization = Interop.GetTemplateSpecialization(declaration.Type);
definition.Elements.Add(new(
Content: $"void* (*{definition.Type.Name}{templateSpecialization}::{createBySizeName})(std::int32_t) = nullptr;"
));
definition.Elements.Add(new(
Content:
$$"""
{{definition.Type.Name}}{{templateSpecialization}}::{{definition.Type.Name}}(std::int32_t size)
: _handle({{createBySizeName}}(size))
{
}
"""
));
CSharpType csType = CSharpType.FromSymbol(context, arrayType);
string baseName = $"{Interop.GetUniqueNameForType(csType)}_Constructor_Size";
init.Functions.Add(new(
CppName: $"{definition.Type.GetFullyQualifiedName()}::{createBySizeName}",
CppTypeSignature: $"void* (*)(std::int32_t size)",
CppTypeDefinitionsReferenced: new[] { definition.Type },
CppTypeDeclarationsReferenced: new[] { CppType.Int32 },
CSharpName: baseName + "Delegate",
CSharpContent:
$$"""
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private unsafe delegate IntPtr {{baseName}}Type(System.Int32 size);
private static unsafe readonly {{baseName}}Type {{baseName}}Delegate = new {{baseName}}Type({{baseName}});
[AOT.MonoPInvokeCallback(typeof({{baseName}}Type))]
private static unsafe IntPtr {{baseName}}(System.Int32 size)
{
var result = new {{arrayType.ElementType.ToDisplayString()}}[size];
return {{csType.GetConversionToInteropType("result")}};
}
"""
));
}
/// <summary>
/// Add a method that can be used to assign a new value to an element of the array.
/// </summary>
private void GenerateItemMethod(CppGenerationContext context, TypeToGenerate item, GeneratedResult result, IArrayTypeSymbol arrayType)
{
// TODO: It would be nice to allow the user to use operator[] to assign a value to an array element.
// But to do that, we would need operator[] to return an object with an implicit conversion
// to the element type and an overloaded operator= to set the value. Here we take the
// simpler approach of adding an Item method instead.
GeneratedCppDeclaration declaration = result.CppDeclaration;
GeneratedCppDefinition definition = result.CppDefinition;
GeneratedInit init = result.Init;
CppType elementType = CppType.FromCSharp(context, arrayType.ElementType);
CppType elementTypeParameter = elementType.AsParameterType();
CppType elementInteropTypeParameter = elementTypeParameter.AsInteropType();
string setItem = $"SetItem";
declaration.Elements.Add(new(
Content: $"static void (*{setItem})(void* thiz, std::int32_t index, {elementInteropTypeParameter.GetFullyQualifiedName()} value);",
IsPrivate: true,
TypeDeclarationsReferenced: new[] { CppType.Int32, elementInteropTypeParameter }
));
declaration.Elements.Add(new(
Content: $"void Item(std::int32_t index, {elementTypeParameter.GetFullyQualifiedName()} value);",
TypeDeclarationsReferenced: new[] { CppType.Int32, elementTypeParameter }
));
string templateSpecialization = Interop.GetTemplateSpecialization(declaration.Type);
definition.Elements.Add(new(
Content: $"void (*{definition.Type.Name}{templateSpecialization}::{setItem})(void* thiz, std::int32_t, {elementInteropTypeParameter.GetFullyQualifiedName()} value) = nullptr;"
));
definition.Elements.Add(new(
Content:
$$"""
void {{definition.Type.Name}}{{templateSpecialization}}::Item(std::int32_t index, {{elementTypeParameter.GetFullyQualifiedName()}} value) {
{{setItem}}({{definition.Type.AsParameterType().GetConversionToInteropType(context, "(*this)")}}, index, {{elementTypeParameter.GetConversionToInteropType(context, "value")}});
}
"""
));
CSharpType csType = CSharpType.FromSymbol(context, arrayType);
CSharpType csElementType = CSharpType.FromSymbol(context, arrayType.ElementType);
CSharpType csElementInteropType = csElementType.AsInteropTypeParameter();
string baseName = $"{Interop.GetUniqueNameForType(csType)}_SetItem";
init.Functions.Add(new(
CppName: $"{definition.Type.GetFullyQualifiedName()}::{setItem}",
CppTypeSignature: $"void (*)(void*, std::int32_t, {elementInteropTypeParameter.GetFullyQualifiedName()})",
CppTypeDefinitionsReferenced: new[] { definition.Type, CppType.Int32, elementInteropTypeParameter },
CSharpName: baseName + "Delegate",
CSharpContent:
$$"""
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private unsafe delegate void {{baseName}}Type(System.IntPtr thiz, System.Int32 index, {{csElementInteropType.GetFullyQualifiedName()}} value);
private static unsafe readonly {{baseName}}Type {{baseName}}Delegate = new {{baseName}}Type({{baseName}});
[AOT.MonoPInvokeCallback(typeof({{baseName}}Type))]
private static unsafe void {{baseName}}(System.IntPtr thiz, System.Int32 index, {{csElementInteropType.GetFullyQualifiedName()}} value)
{
({{csType.GetParameterConversionFromInteropType("thiz")}})[index] = {{csElementType.GetParameterConversionFromInteropType("value")}};
}
"""
));
}
}
}