@@ -55,6 +55,15 @@ public protocol WritableByteStream: class, TextOutputStream {
5555
5656 /// Flush the stream's buffer.
5757 func flush( )
58+
59+ /// Signal that the byte stream will not be used further and should be closed.
60+ func close( ) throws
61+ }
62+
63+ // Default noop implementation of close to avoid source-breaking downstream dependents with the addition of the close
64+ // API.
65+ public extension WritableByteStream {
66+ func close( ) throws { }
5867}
5968
6069// Public alias to the old name to not introduce API compatibility.
@@ -184,6 +193,14 @@ public class _WritableByteStreamBase: WritableByteStream {
184193 // Do nothing.
185194 }
186195
196+ public final func close( ) throws {
197+ try closeImpl ( )
198+ }
199+
200+ @usableFromInline func closeImpl( ) throws {
201+ fatalError ( " Subclasses must implement this " )
202+ }
203+
187204 @usableFromInline func writeImpl< C: Collection > ( _ bytes: C ) where C. Iterator. Element == UInt8 {
188205 fatalError ( " Subclasses must implement this " )
189206 }
@@ -320,6 +337,12 @@ public final class ThreadSafeOutputByteStream: WritableByteStream {
320337 stream. writeJSONEscaped ( string)
321338 }
322339 }
340+
341+ public func close( ) throws {
342+ try queue. sync {
343+ try stream. close ( )
344+ }
345+ }
323346}
324347
325348/// Define an output stream operator. We need it to be left associative, so we
@@ -625,19 +648,24 @@ public final class BufferedOutputByteStream: _WritableByteStreamBase {
625648 override final func writeImpl( _ bytes: ArraySlice < UInt8 > ) {
626649 contents += bytes
627650 }
651+
652+ override final func closeImpl( ) throws {
653+ // Do nothing. The protocol does not require to stop receiving writes, close only signals that resources could
654+ // be released at this point should we need to.
655+ }
628656}
629657
630658/// Represents a stream which is backed to a file. Not for instantiating.
631659public class FileOutputByteStream : _WritableByteStreamBase {
632660
633- /// Closes the file flushing any buffered data.
634- public final func close( ) throws {
661+ public override final func closeImpl( ) throws {
635662 flush ( )
636- try closeImpl ( )
663+ try fileCloseImpl ( )
637664 }
638665
639- func closeImpl( ) throws {
640- fatalError ( " closeImpl() should be implemented by a subclass " )
666+ /// Closes the file flushing any buffered data.
667+ func fileCloseImpl( ) throws {
668+ fatalError ( " fileCloseImpl() should be implemented by a subclass " )
641669 }
642670}
643671
@@ -726,7 +754,7 @@ public final class LocalFileOutputByteStream: FileOutputByteStream {
726754 fflush ( filePointer)
727755 }
728756
729- override final func closeImpl ( ) throws {
757+ override final func fileCloseImpl ( ) throws {
730758 defer {
731759 fclose ( filePointer)
732760 // If clients called close we shouldn't call fclose again in deinit.
0 commit comments