11import Foundation
22
3+ fileprivate final actor BufferActor {
4+ private let buffer : UnsafeMutableRawBufferPointer
5+
6+ init ( buffer: UnsafeMutableRawBufferPointer ) {
7+ self . buffer = buffer
8+ }
9+ }
10+
311fileprivate final actor IOActor {
4- #if !os(Windows)
12+ #if !os(Windows)
513 fileprivate func read(
614 from fd: Int32 ,
715 into buffer: UnsafeMutableRawBufferPointer
816 ) async throws -> Int {
917 while true {
10- #if canImport(Darwin)
18+ #if canImport(Darwin)
1119 let read = Darwin . read
12- #elseif canImport(Glibc)
20+ #elseif canImport(Glibc)
1321 let read = Glibc . read
14- #else
15- #error("Unsupported platform!")
16- #endif
22+ #else
23+ #error("Unsupported platform!")
24+ #endif
1725 let amount = read ( fd, buffer. baseAddress, buffer. count)
1826 if amount >= 0 {
1927 return amount
@@ -28,44 +36,46 @@ fileprivate final actor IOActor {
2836 }
2937 }
3038 }
31- #endif
39+ #endif
40+
41+ private func _read(
42+ from handle: FileHandle ,
43+ upToCount count: Int
44+ ) async throws -> Data ? {
45+ if #available( macOS 10 . 15 . 4 , * ) {
46+ try ? handle. read ( upToCount: count)
47+ } else {
48+ handle. readData ( ofLength: count)
49+ }
50+ }
3251
3352 fileprivate func read(
3453 from handle: FileHandle ,
35- into buffer : UnsafeMutableRawBufferPointer
36- ) async throws -> Int {
54+ upToCount count : Int
55+ ) async throws -> Data ? {
3756 try await withUnsafeThrowingContinuation { continuation in
3857 handle. readabilityHandler = { handle in
3958 handle. readabilityHandler = nil
4059
41- let data : Data
42- if #available( macOS 10 . 15 . 4 , * ) {
60+ Task . init {
4361 do {
44- guard let _data =
45- try handle. read ( upToCount: buffer. count) else {
46- continuation. resume ( returning: 0 )
47- return
48- }
49-
50- data = _data
62+ continuation. resume (
63+ returning: try await self . _read (
64+ from: handle,
65+ upToCount: count
66+ )
67+ )
5168 } catch {
5269 continuation. resume ( throwing: error)
53- return
5470 }
55- } else {
56- data = handle. readData ( ofLength: buffer. count)
5771 }
58-
59- data. copyBytes ( to: buffer)
60- continuation. resume ( returning: data. count)
6172 }
6273 }
6374 }
6475
6576 fileprivate static let `default` = IOActor ( )
6677}
6778
68-
6979@usableFromInline
7080internal struct _AsyncBytesBuffer {
7181 private struct Header {
@@ -94,9 +104,10 @@ internal struct _AsyncBytesBuffer {
94104 }
95105
96106 fileprivate var baseAddress : UnsafeMutableRawPointer {
97- ( self . storage as! Storage ) . withUnsafeMutablePointerToElements {
98- . init( $0)
99- }
107+ ( self . storage as! Storage )
108+ . withUnsafeMutablePointerToElements {
109+ . init( $0)
110+ }
100111 }
101112
102113 fileprivate var capacity : Int {
@@ -174,9 +185,9 @@ extension FileHandle {
174185 fileprivate init ( file: FileHandle ) {
175186 self . _buffer = _AsyncBytesBuffer ( _capacity: Self . bufferSize)
176187
177- #if !os(Windows)
188+ #if !os(Windows)
178189 let fileDescriptor = file. fileDescriptor
179- #endif
190+ #endif
180191
181192 self . _buffer. readFunction = { buf in
182193 buf. _nextPointer = buf. baseAddress
@@ -188,25 +199,34 @@ extension FileHandle {
188199 count: capacity
189200 )
190201
191- #if os(Windows)
192- let readSize = try await IOActor . default. read (
202+ #if os(Windows)
203+ let readSize : Int
204+ if let data = try await IOActor . default. read (
193205 from: file,
194- into: bufPtr
195- )
196- #else
206+ upToCount: bufPtr. count
207+ ) {
208+ data. copyBytes ( to: bufPtr)
209+ readSize = data. count
210+ } else {
211+ readSize = 0
212+ }
213+ #else
197214 let readSize : Int
198215 if fileDescriptor >= 0 {
199216 readSize = try await IOActor . default. read (
200217 from: fileDescriptor,
201218 into: bufPtr
202219 )
220+ } else if let data = try await IOActor . default. read (
221+ from: file,
222+ upToCount: bufPtr. count
223+ ) {
224+ data. copyBytes ( to: bufPtr)
225+ readSize = data. count
203226 } else {
204- readSize = try await IOActor . default. read (
205- from: file,
206- into: bufPtr
207- )
227+ readSize = 0
208228 }
209- #endif
229+ #endif
210230
211231 buf. _endPointer = buf. _nextPointer + readSize
212232 return readSize
0 commit comments