22//
33// This source file is part of the Swift open source project
44//
5- // Copyright (c) 2022-2023 Apple Inc. and the Swift project authors
5+ // Copyright (c) 2022-2025 Apple Inc. and the Swift project authors
66// Licensed under Apache License v2.0 with Runtime Library Exception
77//
88// See https://swift.org/LICENSE.txt for license information
@@ -19,12 +19,13 @@ import NIO
1919// - Known issues:
2020// - no tests
2121// - most configurations have never run
22- struct FileContentStream : AsyncSequence {
22+ internal typealias FileContentStream = _FileContentStream
23+ public struct _FileContentStream : AsyncSequence & Sendable {
2324 public typealias Element = ByteBuffer
2425 typealias Underlying = AsyncThrowingChannel < Element , Error >
2526
2627 public func makeAsyncIterator( ) -> AsyncIterator {
27- AsyncIterator ( underlying: self . asyncChannel. makeAsyncIterator ( ) )
28+ return AsyncIterator ( underlying: self . asyncChannel. makeAsyncIterator ( ) )
2829 }
2930
3031 public struct AsyncIterator : AsyncIteratorProtocol {
@@ -33,21 +34,31 @@ struct FileContentStream: AsyncSequence {
3334 var underlying : Underlying . AsyncIterator
3435
3536 public mutating func next( ) async throws -> ByteBuffer ? {
36- try await self . underlying. next ( )
37+ return try await self . underlying. next ( )
3738 }
3839 }
3940
4041 public struct IOError : Error {
4142 public var errnoValue : CInt
4243
4344 public static func makeFromErrnoGlobal( ) -> IOError {
44- IOError ( errnoValue: errno)
45+ return IOError ( errnoValue: errno)
4546 }
4647 }
4748
4849 private let asyncChannel : AsyncThrowingChannel < ByteBuffer , Error >
4950
50- public init (
51+ public static func makeReader(
52+ fileDescriptor: CInt ,
53+ eventLoop: EventLoop = MultiThreadedEventLoopGroup . singleton. any ( ) ,
54+ blockingPool: NIOThreadPool = . singleton
55+ ) async throws -> _FileContentStream {
56+ return try await eventLoop. submit {
57+ try FileContentStream ( fileDescriptor: fileDescriptor, eventLoop: eventLoop, blockingPool: blockingPool)
58+ } . get ( )
59+ }
60+
61+ internal init (
5162 fileDescriptor: CInt ,
5263 eventLoop: EventLoop ,
5364 blockingPool: NIOThreadPool ? = nil
@@ -64,7 +75,7 @@ struct FileContentStream: AsyncSequence {
6475
6576 switch statInfo. st_mode & S_IFMT {
6677 case S_IFREG:
67- guard let blockingPool else {
78+ guard let blockingPool = blockingPool else {
6879 throw IOError ( errnoValue: EINVAL)
6980 }
7081 let fileHandle = NIOLoopBound (
@@ -86,7 +97,7 @@ struct FileContentStream: AsyncSequence {
8697 . whenComplete { result in
8798 try ! fileHandle. value. close ( )
8899 switch result {
89- case let . failure( error) :
100+ case . failure( let error) :
90101 asyncChannel. fail ( error)
91102 case . success:
92103 asyncChannel. finish ( )
@@ -140,7 +151,7 @@ private final class ReadIntoAsyncChannelHandler: ChannelDuplexHandler {
140151 return data
141152 case . error:
142153 return nil
143- case var . sending( queue) :
154+ case . sending( var queue) :
144155 queue. append ( data)
145156 self = . sending( queue)
146157 return nil
@@ -153,7 +164,7 @@ private final class ReadIntoAsyncChannelHandler: ChannelDuplexHandler {
153164 preconditionFailure ( " didSendOne during .idle " )
154165 case . error:
155166 return nil
156- case var . sending( queue) :
167+ case . sending( var queue) :
157168 if queue. isEmpty {
158169 self = . idle
159170 return nil
@@ -212,7 +223,7 @@ private final class ReadIntoAsyncChannelHandler: ChannelDuplexHandler {
212223 eventLoop. makeFutureWithTask {
213224 // note: We're _not_ on an EventLoop thread here
214225 switch data {
215- case let . chunk( data) :
226+ case . chunk( let data) :
216227 await sink. send ( data)
217228 case . finish:
218229 sink. finish ( )
@@ -255,18 +266,15 @@ private final class ReadIntoAsyncChannelHandler: ChannelDuplexHandler {
255266
256267extension FileHandle {
257268 func fileContentStream( eventLoop: EventLoop ) throws -> FileContentStream {
258- let asyncBytes = try FileContentStream (
259- fileDescriptor: self . fileDescriptor,
260- eventLoop: eventLoop
261- )
269+ let asyncBytes = try FileContentStream ( fileDescriptor: self . fileDescriptor, eventLoop: eventLoop)
262270 try self . close ( )
263271 return asyncBytes
264272 }
265273}
266274
267275extension FileContentStream {
268276 var lines : AsyncByteBufferLineSequence < FileContentStream > {
269- AsyncByteBufferLineSequence (
277+ return AsyncByteBufferLineSequence (
270278 self ,
271279 dropTerminator: true ,
272280 maximumAllowableBufferSize: 1024 * 1024 ,
@@ -281,7 +289,7 @@ extension AsyncSequence where Element == ByteBuffer, Self: Sendable {
281289 maximumAllowableBufferSize: Int = 1024 * 1024 ,
282290 dropLastChunkIfNoNewline: Bool = false
283291 ) -> AsyncByteBufferLineSequence < Self > {
284- AsyncByteBufferLineSequence (
292+ return AsyncByteBufferLineSequence (
285293 self ,
286294 dropTerminator: dropTerminator,
287295 maximumAllowableBufferSize: maximumAllowableBufferSize,
@@ -290,7 +298,7 @@ extension AsyncSequence where Element == ByteBuffer, Self: Sendable {
290298 }
291299
292300 public var strings : AsyncMapSequence < Self , String > {
293- self . map { String ( buffer: $0) }
301+ return self . map { String ( buffer: $0) }
294302 }
295303}
296304
@@ -312,28 +320,26 @@ where Base: AsyncSequence, Base.Element == ByteBuffer {
312320
313321 struct Buffer {
314322 private var buffer : [ ByteBuffer ] = [ ]
315- private( set) var byteCount : Int = 0
323+ internal private( set) var byteCount : Int = 0
316324
317325 mutating func append( _ buffer: ByteBuffer ) {
318326 self . buffer. append ( buffer)
319327 self . byteCount += buffer. readableBytes
320328 }
321329
322330 func allButLast( ) -> ArraySlice < ByteBuffer > {
323- self . buffer. dropLast ( )
331+ return self . buffer. dropLast ( )
324332 }
325333
326334 var byteCountButLast : Int {
327- self . byteCount - ( self . buffer. last? . readableBytes ?? 0 )
335+ return self . byteCount - ( self . buffer. last? . readableBytes ?? 0 )
328336 }
329337
330338 var lastChunkView : ByteBufferView ? {
331- self . buffer. last? . readableBytesView
339+ return self . buffer. last? . readableBytesView
332340 }
333341
334- mutating func concatenateEverything( upToLastChunkLengthToConsume lastLength: Int )
335- -> ByteBuffer
336- {
342+ mutating func concatenateEverything( upToLastChunkLengthToConsume lastLength: Int ) -> ByteBuffer {
337343 var output = ByteBuffer ( )
338344 output. reserveCapacity ( lastLength + self . byteCountButLast)
339345
@@ -359,7 +365,7 @@ where Base: AsyncSequence, Base.Element == ByteBuffer {
359365 }
360366 }
361367
362- init (
368+ internal init (
363369 underlying: Base . AsyncIterator ,
364370 dropTerminator: Bool ,
365371 maximumAllowableBufferSize: Int ,
@@ -446,7 +452,7 @@ where Base: AsyncSequence, Base.Element == ByteBuffer {
446452 }
447453
448454 public func makeAsyncIterator( ) -> AsyncIterator {
449- AsyncIterator (
455+ return AsyncIterator (
450456 underlying: self . underlying. makeAsyncIterator ( ) ,
451457 dropTerminator: self . dropTerminator,
452458 maximumAllowableBufferSize: self . maximumAllowableBufferSize,
0 commit comments