-
Notifications
You must be signed in to change notification settings - Fork 114
Added socket support #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/* | ||
This source file is part of the Swift System open source project | ||
|
||
Copyright (c) 2020 - 2021 Apple Inc. and the Swift System project authors | ||
Licensed under Apache License v2.0 with Runtime Library Exception | ||
|
||
See https://swift.org/LICENSE.txt for license information | ||
*/ | ||
|
||
public extension FileDescriptor { | ||
|
||
/// Set of file descriptors | ||
@frozen | ||
struct Set { | ||
|
||
@_alwaysEmitIntoClient | ||
internal private(set) var bytes: CInterop.FileDescriptorSet | ||
|
||
@_alwaysEmitIntoClient | ||
public init(_ bytes: CInterop.FileDescriptorSet) { | ||
self.bytes = bytes | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
public init() { | ||
self.init(CInterop.FileDescriptorSet()) | ||
} | ||
} | ||
} | ||
|
||
public extension FileDescriptor.Set { | ||
|
||
@_alwaysEmitIntoClient | ||
init<S>(_ sequence: S) where S: Sequence, S.Element == FileDescriptor { | ||
self.init() | ||
for element in sequence { | ||
bytes.set(element.rawValue) | ||
} | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
mutating func append(_ element: FileDescriptor) { | ||
bytes.set(element.rawValue) | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
mutating func remove(_ element: FileDescriptor) { | ||
bytes.clear(element.rawValue) | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
mutating func contains(_ element: FileDescriptor) -> Bool { | ||
bytes.isSet(element.rawValue) | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
mutating func removeAll() { | ||
self.bytes.zero() | ||
} | ||
|
||
#if os(Windows) | ||
@_alwaysEmitIntoClient | ||
var count: Int { | ||
return numericCast(bytes.fd_count) | ||
} | ||
#endif | ||
} | ||
|
||
extension FileDescriptor.Set: ExpressibleByArrayLiteral { | ||
|
||
public init(arrayLiteral elements: FileDescriptor...) { | ||
assert(elements.count <= _fd_set_count, | ||
"FileDescriptor.Set can only contain \(_fd_set_count) elements") | ||
self.init(elements) | ||
} | ||
} | ||
|
||
extension FileDescriptor.Set: CustomStringConvertible, CustomDebugStringConvertible { | ||
|
||
@inline(never) | ||
public var description: String { | ||
return "FileDescriptor.Set()" | ||
} | ||
|
||
public var debugDescription: String { | ||
return description | ||
} | ||
} | ||
|
||
public extension FileDescriptor.Set { | ||
|
||
@_alwaysEmitIntoClient | ||
mutating func withUnsafeMutablePointer<T>(_ body: (UnsafeMutablePointer<Int32>) throws -> T) rethrows -> T { | ||
return try bytes.withUnsafeMutablePointer(body) | ||
} | ||
} | ||
|
||
internal extension CInterop.FileDescriptorSet { | ||
|
||
@usableFromInline | ||
mutating func zero() { | ||
withUnsafeMutablePointer { | ||
$0.initialize(repeating: 0, count: _fd_set_count) | ||
} | ||
} | ||
|
||
/// | ||
/// Set an fd in an fd_set | ||
/// | ||
/// - Parameter fd: The fd to add to the fd_set | ||
/// | ||
@usableFromInline | ||
mutating func set(_ fd: CInt) { | ||
let (index, mask) = Self.offset(for: fd) | ||
withUnsafeMutablePointer { $0[index] |= mask } | ||
} | ||
|
||
/// | ||
/// Clear an fd from an fd_set | ||
/// | ||
/// - Parameter fd: The fd to clear from the fd_set | ||
/// | ||
@usableFromInline | ||
mutating func clear(_ fd: CInt) { | ||
let (index, mask) = Self.offset(for: fd) | ||
withUnsafeMutablePointer { $0[index] &= ~mask } | ||
} | ||
|
||
/// | ||
/// Check if an fd is present in an fd_set | ||
/// | ||
/// - Parameter fd: The fd to check | ||
/// | ||
/// - Returns: `True` if present, `false` otherwise. | ||
/// | ||
@usableFromInline | ||
mutating func isSet(_ fd: CInt) -> Bool { | ||
let (index, mask) = Self.offset(for: fd) | ||
return withUnsafeMutablePointer { $0[index] & mask != 0 } | ||
} | ||
|
||
@usableFromInline | ||
static func offset(for fd: CInt) -> (offset: Int, mask: CInt) { | ||
var intOffset = Int(fd) / _fd_set_count | ||
#if _endian(big) | ||
if intOffset % 2 == 0 { | ||
intOffset += 1 | ||
} else { | ||
intOffset -= 1 | ||
} | ||
#endif | ||
let bitOffset = Int(fd) % _fd_set_count | ||
let mask = CInt(bitPattern: UInt32(1 << bitOffset)) | ||
return (intOffset, mask) | ||
} | ||
|
||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) | ||
@usableFromInline | ||
mutating func withUnsafeMutablePointer<T>(_ body: (UnsafeMutablePointer<CInt>) throws -> T) rethrows -> T { | ||
return try Swift.withUnsafeMutablePointer(to: &fds_bits) { | ||
try body(UnsafeMutableRawPointer($0).assumingMemoryBound(to: CInt.self)) | ||
} | ||
} | ||
#elseif os(Linux) || os(FreeBSD) || os(Android) | ||
@usableFromInline | ||
mutating func withUnsafeMutablePointer<T>(_ body: (UnsafeMutablePointer<CInt>) throws -> T) rethrows -> T { | ||
return try Swift.withUnsafeMutablePointer(to: &__fds_bits) { | ||
try body(UnsafeMutableRawPointer($0).assumingMemoryBound(to: CInt.self)) | ||
} | ||
} | ||
#elseif os(Windows) | ||
@usableFromInline | ||
mutating func withUnsafeMutablePointer<T>(_ body: (UnsafeMutablePointer<CInt>) throws -> T) rethrows -> T { | ||
return try Swift.withUnsafeMutablePointer(to: &fds_bits) { | ||
try body(UnsafeMutableRawPointer($0).assumingMemoryBound(to: CInt.self)) | ||
} | ||
} | ||
#endif | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
This source file is part of the Swift System open source project | ||
|
||
Copyright (c) 2021 - 2021 Apple Inc. and the Swift System project authors | ||
Licensed under Apache License v2.0 with Runtime Library Exception | ||
|
||
See https://swift.org/LICENSE.txt for license information | ||
*/ | ||
|
||
/// File Events bitmask | ||
@frozen | ||
// @available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *) | ||
public struct FileEvents: OptionSet, Hashable, Codable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this name is a little misleading: we should probably call it |
||
|
||
/// The raw C file events. | ||
@_alwaysEmitIntoClient | ||
public let rawValue: CInterop.FileEvent | ||
|
||
/// Create a strongly-typed file events from a raw C value. | ||
@_alwaysEmitIntoClient | ||
public init(rawValue: CInterop.FileEvent) { self.rawValue = rawValue } | ||
|
||
@_alwaysEmitIntoClient | ||
private init(_ raw: CInt) { self.init(rawValue: numericCast(raw)) } | ||
} | ||
|
||
public extension FileEvents { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's try to be consistent about where we put extension access modifiers. |
||
|
||
/// There is data to read. | ||
@_alwaysEmitIntoClient | ||
static var read: FileEvents { FileEvents(_POLLIN) } | ||
|
||
/// There is urgent data to read (e.g., out-of-band data on TCP socket; | ||
/// pseudoterminal master in packet mode has seen state change in slave). | ||
@_alwaysEmitIntoClient | ||
static var readUrgent: FileEvents { FileEvents(_POLLPRI) } | ||
|
||
/// Writing now will not block. | ||
@_alwaysEmitIntoClient | ||
static var write: FileEvents { FileEvents(_POLLOUT) } | ||
|
||
/// Error condition. | ||
@_alwaysEmitIntoClient | ||
static var error: FileEvents { FileEvents(_POLLERR) } | ||
|
||
/// Hang up. | ||
@_alwaysEmitIntoClient | ||
static var hangup: FileEvents { FileEvents(_POLLHUP) } | ||
|
||
/// Error condition. | ||
@_alwaysEmitIntoClient | ||
static var invalidRequest: FileEvents { FileEvents(_POLLNVAL) } | ||
} | ||
|
||
|
||
extension FileEvents | ||
: CustomStringConvertible, CustomDebugStringConvertible | ||
{ | ||
/// A textual representation of the file permissions. | ||
@inline(never) | ||
public var description: String { | ||
let descriptions: [(Element, StaticString)] = [ | ||
(.read, ".read"), | ||
(.readUrgent, ".readUrgent"), | ||
(.write, ".write"), | ||
(.error, ".error"), | ||
(.hangup, ".hangup"), | ||
(.invalidRequest, ".invalidRequest") | ||
] | ||
|
||
return _buildDescription(descriptions) | ||
} | ||
|
||
/// A textual representation of the file permissions, suitable for debugging. | ||
public var debugDescription: String { self.description } | ||
} |
Uh oh!
There was an error while loading. Please reload this page.