14
14
15
15
#if swift(>=6.0)
16
16
public import SwiftSyntaxMacros
17
- private import Foundation
18
17
@_spi ( PluginMessage) private import SwiftCompilerPluginMessageHandling
18
+ #if canImport(Darwin)
19
+ private import Darwin
20
+ #elseif canImport(Glibc)
21
+ private import Glibc
22
+ #elseif canImport(ucrt)
23
+ private import ucrt
24
+ #endif
19
25
#else
20
26
import SwiftSyntaxMacros
21
- import Foundation
22
27
@_spi ( PluginMessage) import SwiftCompilerPluginMessageHandling
23
- #endif
24
-
25
- #if os(Windows)
26
- #if swift(>=6.0)
27
- private import ucrt
28
- #else
28
+ #if canImport(Darwin)
29
+ import Darwin
30
+ #elseif canImport(Glibc)
31
+ import Glibc
32
+ #elseif canImport(ucrt)
29
33
import ucrt
30
34
#endif
31
35
#endif
@@ -86,7 +90,7 @@ extension CompilerPlugin {
86
90
}
87
91
}
88
92
89
- let pluginPath = CommandLine . arguments. first ?? Bundle . main . executablePath ?? ProcessInfo . processInfo . processName
93
+ let pluginPath = CommandLine . arguments. first ?? " <unknown> "
90
94
throw CompilerPluginError (
91
95
message:
92
96
" macro implementation type ' \( moduleName) . \( typeName) ' could not be found in executable plugin ' \( pluginPath) ' "
@@ -149,8 +153,8 @@ extension CompilerPlugin {
149
153
150
154
// Open a message channel for communicating with the plugin host.
151
155
let connection = PluginHostConnection (
152
- inputStream: FileHandle ( fileDescriptor : inputFD) ,
153
- outputStream: FileHandle ( fileDescriptor : outputFD)
156
+ inputStream: inputFD,
157
+ outputStream: outputFD
154
158
)
155
159
156
160
// Handle messages from the host until the input stream is closed,
@@ -180,56 +184,40 @@ extension CompilerPlugin {
180
184
}
181
185
182
186
internal struct PluginHostConnection : MessageConnection {
183
- fileprivate let inputStream : FileHandle
184
- fileprivate let outputStream : FileHandle
187
+ fileprivate let inputStream : CInt
188
+ fileprivate let outputStream : CInt
185
189
186
190
func sendMessage< TX: Encodable > ( _ message: TX ) throws {
187
191
// Encode the message as JSON.
188
- let payload = try PluginMessageJSON . encode ( message) . withUnsafeBufferPointer { buffer in
189
- Data ( buffer: buffer)
190
- }
192
+ let payload = try PluginMessageJSON . encode ( message)
191
193
192
194
// Write the header (a 64-bit length field in little endian byte order).
193
- var count = UInt64 ( payload. count) . littleEndian
194
- let header = Swift . withUnsafeBytes ( of: & count) { Data ( $0) }
195
- precondition ( header. count == 8 )
195
+ let count = payload. count
196
+ var header = UInt64 ( count) . littleEndian
197
+
198
+ try withUnsafeBytes ( of: & header) { buffer in
199
+ precondition ( buffer. count == 8 )
200
+ try _write ( outputStream, contentsOf: buffer)
201
+ }
196
202
197
- // Write the header and payload.
198
- try outputStream . _write ( contentsOf: header )
199
- try outputStream . _write ( contentsOf : payload )
203
+ try payload . withUnsafeBytes { buffer in
204
+ try _write ( outputStream , contentsOf: buffer )
205
+ }
200
206
}
201
207
202
208
func waitForNextMessage< RX: Decodable > ( _ ty: RX . Type ) throws -> RX ? {
203
209
// Read the header (a 64-bit length field in little endian byte order).
204
- guard
205
- let header = try inputStream. _read ( upToCount: 8 ) ,
206
- header. count != 0
207
- else {
208
- return nil
209
- }
210
- guard header. count == 8 else {
211
- throw PluginMessageError . truncatedHeader
212
- }
213
-
214
- // Decode the count.
215
- let count = header. withUnsafeBytes {
216
- UInt64 ( littleEndian: $0. loadUnaligned ( as: UInt64 . self) )
210
+ let count = try _reading ( inputStream, count: 8 ) { buffer in
211
+ UInt64 ( littleEndian: buffer. loadUnaligned ( as: UInt64 . self) )
217
212
}
218
213
guard count >= 2 else {
219
214
throw PluginMessageError . invalidPayloadSize
220
215
}
221
216
222
217
// Read the JSON payload.
223
- guard
224
- let payload = try inputStream. _read ( upToCount: Int ( count) ) ,
225
- payload. count == count
226
- else {
227
- throw PluginMessageError . truncatedPayload
228
- }
229
-
230
- // Decode and return the message.
231
- return try payload. withUnsafeBytes { buffer in
232
- return try PluginMessageJSON . decode ( RX . self, from: buffer. bindMemory ( to: UInt8 . self) )
218
+ return try _reading ( inputStream, count: Int ( count) ) { buffer in
219
+ // Decode and return the message.
220
+ try PluginMessageJSON . decode ( RX . self, from: buffer. bindMemory ( to: UInt8 . self) )
233
221
}
234
222
}
235
223
@@ -240,22 +228,45 @@ internal struct PluginHostConnection: MessageConnection {
240
228
}
241
229
}
242
230
243
- private extension FileHandle {
244
- func _write( contentsOf data: Data ) throws {
245
- if #available( macOS 10 . 15 . 4 , iOS 13 . 4 , watchOS 6 . 2 , tvOS 13 . 4 , * ) {
246
- return try self . write ( contentsOf: data)
247
- } else {
248
- return self . write ( data)
231
+ func _write( _ fd: CInt , contentsOf buffer: UnsafeRawBufferPointer ) throws {
232
+ var ptr = buffer. baseAddress!
233
+ var remaining = buffer. count
234
+ while remaining > 0 {
235
+ switch write ( fd, ptr, remaining) {
236
+ case 0 :
237
+ throw CompilerPluginError ( message: " write(2) closed " )
238
+ case - 1 :
239
+ let err = String ( cString: strerror ( errno) )
240
+ throw CompilerPluginError ( message: " read(2) failed: \( err) " )
241
+ case let result:
242
+ ptr += Int ( result)
243
+ remaining -= Int ( result)
249
244
}
250
245
}
246
+ }
247
+
248
+ func _reading< T> ( _ fd: CInt , count: Int , _ fn: ( UnsafeRawBufferPointer ) throws -> T ) throws -> T {
249
+ guard count > 0 else {
250
+ return try fn ( UnsafeRawBufferPointer ( start: nil , count: 0 ) )
251
+ }
252
+ let buffer = UnsafeMutableRawBufferPointer . allocate ( byteCount: count, alignment: 1 )
253
+ defer { buffer. deallocate ( ) }
251
254
252
- func _read( upToCount count: Int ) throws -> Data ? {
253
- if #available( macOS 10 . 15 . 4 , iOS 13 . 4 , watchOS 6 . 2 , tvOS 13 . 4 , * ) {
254
- return try self . read ( upToCount: count)
255
- } else {
256
- return self . readData ( ofLength: 8 )
255
+ var ptr = buffer. baseAddress!
256
+ var remaining = buffer. count
257
+ while remaining > 0 {
258
+ switch read ( fd, ptr, remaining) {
259
+ case 0 :
260
+ throw CompilerPluginError ( message: " read(2) closed " )
261
+ case - 1 :
262
+ let err = String ( cString: strerror ( errno) )
263
+ throw CompilerPluginError ( message: " read(2) failed: \( err) " )
264
+ case let result:
265
+ ptr += Int ( result)
266
+ remaining -= Int ( result)
257
267
}
258
268
}
269
+ return try fn ( UnsafeRawBufferPointer ( buffer) )
259
270
}
260
271
261
272
struct CompilerPluginError : Error , CustomStringConvertible {
0 commit comments