You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/README.md
+66-42Lines changed: 66 additions & 42 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ This document provides a detailed overview of the .NET Swift interop tooling, fo
4
4
5
5
## Usage
6
6
7
-
The tooling consumes Swift interface files to generate C# bindings. Currently, the tool processes a Swift ABI file, which is generated from a `.swiftinterface`file by the Swift compiler. This ABI file contains a json representation of the abstract syntax tree of the `.swiftinterface` file. The `.swiftinterface` and `.abi.json` files are generated by executing the `swiftc` command with the `-emit-module-interface` option. In upcoming improvements, the ABI aggregator will transition to directly parsing the `.swiftinterface` file and, eventually, a dynamic library to facilitate type-strong parsing.
7
+
The tooling consumes Swift ABI files, which are generated from `.swiftinterface`files by the Swift compiler. This ABI file contains a json representation of the abstract syntax tree of the `.swiftinterface` file. The `.swiftinterface` and `.abi.json` files are generated by executing the `swiftc` command with the `-emit-module-interface` option.
8
8
9
9
```
10
10
Description:
@@ -36,24 +36,57 @@ The table below lists the Swift types and their corresponding C# types.
36
36
37
37
| Swift Type | C# Type |
38
38
| ------------------------------- | -------- |
39
-
|`Swift.Int64`|`long`|
40
-
|`Swift.UInt64`|`ulong`|
41
-
|`Swift.Int32`|`int`|
42
-
|`Swift.UInt32`|`uint`|
43
-
|`Swift.Int16`|`short`|
44
-
|`Swift.UInt16`|`ushort`|
45
-
|`Swift.Int8`|`sbyte`|
46
-
|`Swift.UInt8`|`byte`|
47
-
|`Swift.UnsafeRawPointer`|`void*`|
48
-
|`Swift.UnsafeMutableRawPointer`|`void*`|
49
-
|`Int`|`nint`|
50
-
|`UInt`|`nuint`|
39
+
|`Swift.Int64`|`Int64`|
40
+
|`Swift.UInt64`|`UInt64`|
41
+
|`Swift.Int32`|`Int32`|
42
+
|`Swift.UInt32`|`UInt32`|
43
+
|`Swift.Int16`|`Int16`|
44
+
|`Swift.UInt16`|`UInt16`|
45
+
|`Swift.Int8`|`SByte`|
46
+
|`Swift.UInt8`|`Byte`|
47
+
|`Int`|`IntPtr`|
48
+
|`UInt`|`UIntPtr`|
51
49
|`Bool`|`bool`|
52
-
|`Float`|`float`|
53
-
|`Double`|`double`|
50
+
|`Float`|`Single`|
51
+
|`Double`|`Double`|
54
52
53
+
All C# types mentioned are blittable except for `bool`. To facilitate `P/Invoke`, a lightweight wrapper might be required to convert `bool` to `byte`. Swift primitive types are implemented as frozen structs that conform to Swift-specific lowering processes handled by the runtime. However, such mapping can fit within the underlying calling convention as these types are below the size limit for being passed by reference.
55
54
56
-
All C# types mentioned are blittable except for `bool`. To facilitate `P/Invoke`, a lightweight wrapper is required to convert `bool` to `byte`. Swift primitive types are implemented as frozen structs that conform to Swift-specific lowering processes handled by the runtime. However, such mapping can fit within the underlying calling convention as these types are below the size limit for being passed by reference.
55
+
<details>
56
+
The Swift type database is an XML-based file format used for describing primitive data types with the following structure:
57
+
58
+
```xml
59
+
<?xml version="1.0" encoding="utf-8"?>
60
+
<swifttypedatabaseversion="1.0">
61
+
<entities>
62
+
<!-- Individual entities describing Swift data types with C# projections -->
63
+
</entities>
64
+
</swifttypedatabase>
65
+
```
66
+
#### Elements
67
+
68
+
##### `entities`
69
+
-**Description:** Container for individual data type entities.
70
+
-**Child Elements:**
71
+
-`entity`: Represents a specific data type in Swift.
72
+
- **Attributes:**
73
+
- `managedNameSpace`: Specifies the managed namespace of the data type.
74
+
- `managedTypeName`: Specifies the managed type name of the data type.
75
+
- **Child Elements:**
76
+
- `typedeclaration`: Represents the declaration of the Swift type.
77
+
- **Attributes:**
78
+
- `kind`: Specifies the kind of type declaration.
79
+
- `name`: Specifies the name of the Swift type.
80
+
- `module`: Specifies the module of the Swift type.
81
+
</details>
82
+
83
+
### Pointers
84
+
85
+
Swift provides unsafe pointer types as non-owning views into memory: `UnsafePointer`, `UnsafeMutablePointer`, `UnsafeRawPointer`, and `UnsafeMutableRawPointer`. They are implemented as frozen structs in Swift and are projected as structs into C#. The runtime implements Swift structure lowering algorithm, enabling these structs to be passed correctly. They are defined with `_rawValue` property with surfaced `Pointee` property. Mutable pointers are projected as generic types to address method overload issues.
86
+
87
+
### Buffer pointers
88
+
89
+
Swift provides buffer pointer types as non-owning views into memory: `UnsafeBufferPointer`, `UnsafeMutableBufferPointer`, `UnsafeRawBufferPointer`, and `UnsafeMutableRawBufferPointer`. They are implemented as frozen structs in Swift and are projected as structs into C#. The runtime implements Swift structure lowering algorithm, enabling these structs to be passed correctly. Typed buffer pointers are defined with `_position` and `_count` properties, while raw buffer pointers are defined with `_position` and `_end`. Surfaced properties on C# side are `BaseAddress` and `Count`. Mutable buffer pointers are projected as generic types to address method overload issues.. Since these buffer pointers do not allocate or own the memory they point to, memory management is not encapsulated within the structs.
In the example, the user's code references the `HelloLibraryBindings` namespace and invokes a static method that has the same name as the Swift function. When the Swift function returns a type, the C# wrapper method also returns type, with additional processing if required.
137
+
In the example, the user's code references the `HelloLibraryBindings` namespace and invokes a static method that has the same name as the Swift function. When the Swift function returns a type, the C# wrapper method also returns type, with additional processing if required. The C# wrapper method is generated only when marshalling is required. If marshalling is not needed, only a P/Invoke declaration is generated.
105
138
106
139
## Functional outline
107
140
108
-
The tooling consists of the following components:
141
+
The tooling comprises the following components:
109
142
-**SwiftBindings**: Command-line interface that orchestrates the tooling workflow.
110
-
-**SwiftReflector**: A library provides support for public ABI aggregation. It contains implementation of module declarations and the type system.
111
-
-**SwiftRuntimeLibrary**: Library that provides runtime marshaling support and projections of common Swift types.
112
-
-**SyntaxDynamo**: Library that provides an API for generating C# source code.
143
+
-**Components:**
144
+
- `parser`: Parses a Swift library using ABI or Swiftinterface parser.
145
+
- `marshaller`: Marshals types between C# and Swift.
146
+
- `emitter`: Emits a C# bindings library using string-based or object model-based emitter.
147
+
-**SwiftRuntime**: Library providing projections of common Swift types. It contains a type database for common Swift types and implements Swift runtime constructs in C#.
113
148
114
149
The general workflow for generating C# bindings from Swift code is as follows:
115
-
1. Consume the Swift ABI file (`.abi.json`) and aggregate the public ABI using `ISwiftParser`, which generates a `ModuleDeclaration`.
116
-
2. Generate C# source code based on the `ModuleDeclaration`.
150
+
1. Consume the Swift ABI file (`.abi.json`) and aggregate the public ABI using a parser that generates module declarations.
151
+
2. If needed, generate marshalling information for collected ABI.
152
+
3. Generate C# source code using an emitter and generated declarations.
117
153
118
-
### Public ABI aggregation
154
+

119
155
120
-
The aggregation of the public ABI is managed through the `ISwiftParser` interface. This interface defines the layout for concrete implementations that are responsible for parsing and aggregating API information. There are two implementations: Swift ABI parser and Swift interface parser. The Swift ABI parser aggregates API information based on an ABI json file and doesn't contain metadata information from types. The Swift interface parser is designed to handle `.swiftinterface` file, which contains more information. The `.swiftinterface` file doesn't contain managled names and the parser consumes the dynamic library (`.dylib`) alongside to generate the `ModuleDeclaration`.
The aggregation of the public ABI is done through the `ISwiftParser` interface. This interface defines the layout for concrete implementations responsible for parsing and collecting ABI information. Two implementations exist: Swift ABI parser and Swift interface parser. The Swift ABI parser aggregates ABI information based on an ABI json file. The Swift interface parser is designed to handle `.swiftinterface` files. The `.swiftinterface` file doesn't contain mangled names, and the parser should consume the dynamic library (`.dylib`) to generate declarations. Currently, the tooling only implements the Swift ABI parser.
135
159
136
-
### Module declaration
160
+
### Marshaller
137
161
138
-
The `ModuleDeclaration` serves as a integration point for public ABI aggregation and code generation phases. It contains ABI information for a module, including classes, structs, enums, protocols, functions, properties, extensions, and operators.
162
+
Ideally, marshalling logic should be done between parsing and emitting if possible. The `ModuleDecl`, `MethodDecl`, and `TypeDecl` represents model definition of collected and marshalled Swift ABI that should be projectable into C#.
139
163
140
-
### Code generation
164
+
### Emitter
141
165
142
-
Code generation involves a set compilers that convert `ModuleDeclaration` into C# source code. The `BindingsCompiler` and other specific compilers (i.e. `FunctionCompiler`) facilitating the generation of public-facing APIs using `SyntaxDynamo` library.
166
+
Two different strategies are available for emitting: using an object model or a string-based approach. The object model, like Roslyn API, represents a full set of C# language. Currently, the tooling only implements the string-based emitter.
0 commit comments