Skip to content

Commit 689390f

Browse files
authored
Implement FileDescriptor.Pipe() (#58)
Adds support for pipe(2)
1 parent ce8b491 commit 689390f

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

Sources/System/FileOperations.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,4 +370,27 @@ extension FileDescriptor {
370370
public func dup2() throws -> FileDescriptor {
371371
fatalError("Not implemented")
372372
}
373+
374+
#if !os(Windows)
375+
/// Create a pipe, a unidirectional data channel which can be used for interprocess communication.
376+
///
377+
/// - Returns: The pair of file descriptors.
378+
///
379+
/// The corresponding C function is `pipe`.
380+
@_alwaysEmitIntoClient
381+
// @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
382+
public static func pipe() throws -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) {
383+
try _pipe().get()
384+
}
385+
386+
@usableFromInline
387+
internal static func _pipe() -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> {
388+
var fds: (Int32, Int32) = (-1, -1)
389+
return withUnsafeMutablePointer(to: &fds) { pointer in
390+
valueOrErrno(retryOnInterrupt: false) {
391+
system_pipe(UnsafeMutableRawPointer(pointer).assumingMemoryBound(to: Int32.self))
392+
}
393+
}.map { _ in (.init(rawValue: fds.0), .init(rawValue: fds.1)) }
394+
}
395+
#endif
373396
}

Sources/System/Internals/Syscalls.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,11 @@ internal func system_dup2(_ fd: Int32, _ fd2: Int32) -> Int32 {
115115
#endif
116116
return dup2(fd, fd2)
117117
}
118+
#if !os(Windows)
119+
internal func system_pipe(_ fds: UnsafeMutablePointer<Int32>) -> CInt {
120+
#if ENABLE_MOCKING
121+
if mockingEnabled { return _mock(fds) }
122+
#endif
123+
return pipe(fds)
124+
}
125+
#endif

Tests/SystemTests/FileOperationsTest.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,27 @@ final class FileOperationsTest: XCTestCase {
8989
func testHelpers() {
9090
// TODO: Test writeAll, writeAll(toAbsoluteOffset), closeAfter
9191
}
92+
93+
#if !os(Windows)
94+
func testAdHocPipe() throws {
95+
// Ad-hoc test testing `Pipe` functionality.
96+
// We cannot test `Pipe` using `MockTestCase` because it calls `pipe` with a pointer to an array local to the `Pipe`, the address of which we do not know prior to invoking `Pipe`.
97+
let pipe = try FileDescriptor.pipe()
98+
try pipe.readEnd.closeAfter {
99+
try pipe.writeEnd.closeAfter {
100+
var abc = "abc"
101+
try abc.withUTF8 {
102+
_ = try pipe.writeEnd.write(UnsafeRawBufferPointer($0))
103+
}
104+
let readLen = 3
105+
let readBytes = try Array<UInt8>(unsafeUninitializedCapacity: readLen) { buf, count in
106+
count = try pipe.readEnd.read(into: UnsafeMutableRawBufferPointer(buf))
107+
}
108+
XCTAssertEqual(readBytes, Array(abc.utf8))
109+
}
110+
}
111+
}
112+
#endif
92113

93114
func testAdHocOpen() {
94115
// Ad-hoc test touching a file system.

0 commit comments

Comments
 (0)