Skip to content

Commit

Permalink
Sendable wrappers for pointer types
Browse files Browse the repository at this point in the history
  • Loading branch information
johnfairh committed Apr 26, 2024
1 parent 1654de1 commit 788f76e
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 18 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
# - name: Give up and run in docker
# run: 'docker run -v `pwd`:`pwd` -w `pwd` --name steamworks --rm swift:5.9 /bin/bash -c "apt-get update; apt-get install make; (cd sdk && make install); swift test -Xswiftc -cxx-interoperability-mode=default"'
- name: Set up SDK
run: cd sdk && sudo make install
- name: Run tests
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ clean:

# Random flags here to get around crap Linux C++ support
test_linux:
docker run -v `pwd`:`pwd` -w `pwd` --name steamworks --rm swiftlang/swift:nightly-5.9-focal /bin/bash -c "apt-get update; apt-get install make; (cd sdk && make install); swift test -Xswiftc -cxx-interoperability-mode=default"
docker run -v `pwd`:`pwd` -w `pwd` --name steamworks --rm swift:5.10 /bin/bash -c "apt-get update; apt-get install make; (cd sdk && make install); swift test -Xswiftc -cxx-interoperability-mode=default"

shell_linux:
docker run -it -v `pwd`:`pwd` -w `pwd` --name steamworks --rm swiftlang/swift:nightly-5.9-focal /bin/bash
docker run -it -v `pwd`:`pwd` -w `pwd` --name steamworks --rm swift:5.10 /bin/bash
8 changes: 6 additions & 2 deletions Sources/LibGenerate/Interfaces.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,14 @@ extension MetadataDB.Interface.Access {

switch self {
case .instance:
let sendableSwiftType = "Steam\(swiftType)"
decl = """
private let interface: \(swiftType)
private let _interface: \(sendableSwiftType)
private var interface: \(swiftType) {
_interface.base
}
init(_ interface: \(swiftType)) {
self.interface = interface
self._interface = .init(interface)
}
"""
case .user(let accessor), .gameserver(let accessor), .global(let accessor):
Expand Down
12 changes: 12 additions & 0 deletions Sources/LibGenerate/SteamSwiftTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ extension SteamType {
return SwiftType(name1.replacingOccurrences(of: "_", with: ""))
}

var sendableSwiftType: SwiftType {
let base = swiftType
if base.isSendable {
return base
}
return SwiftType("Steam\(base.name)")
}

/// Does this C++ type look like a pointer but is actually something else?
/// Mostly for `const char *` -> `String`
fileprivate var isPointerTypePassedByValue: Bool {
Expand Down Expand Up @@ -409,6 +417,10 @@ extension SwiftTypeUtils {
var isOptional: Bool {
name.hasSuffix("?")
}

var isSendable: Bool {
!name.re_isMatch("^Unsafe.*Pointer$")
}
}

// MARK: SwiftExpr
Expand Down
4 changes: 2 additions & 2 deletions Sources/LibGenerate/Structs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ extension MetadataDB.Struct.Field {
/// Swift structure declaration field
var declLine: [String] {[
"/// Steamworks `\(name)`",
"public let \(name.swiftName): \(type.swiftType)"
"public let \(name.swiftName): \(type.sendableSwiftType)"
]}

/// Swift structure initializer lines
Expand Down Expand Up @@ -130,7 +130,7 @@ extension MetadataDB.Struct.Field {
/// Default value setup for memberwise initializer
var memberwiseParameter: String {
let initClause = type.swiftTypeInstance.flatMap { " = \($0)"} ?? ""
return "\(name.swiftName): \(type.swiftType)\(initClause)"
return "\(name.swiftName): \(type.sendableSwiftType)\(initClause)"
}

/// Initializer line for memberwise initializer
Expand Down
24 changes: 20 additions & 4 deletions Sources/LibGenerate/Typedefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,28 @@ extension MetadataDB.Typedef {
var decl = """
/// Steamworks `\(typedef)`
public struct \(swiftType): Hashable, Sendable {
public let value: \(swiftNativeType)
public init(_ value: \(swiftNativeType)) { self.value = value }
}
extension \(swiftType): SteamTypeAlias, SteamCreatable {}
"""
if swiftNativeType.isSendable {
decl += """
public let value: \(swiftNativeType)
public init(_ value: \(swiftNativeType)) { self.value = value }
}
"""
} else {
decl += """
private let _value: Steam\(swiftNativeType)
public var value: \(swiftNativeType) { _value.base }
public init(_ value: \(swiftNativeType)) { self._value = .init(value) }
}
"""
}
decl += """
extension \(swiftType): SteamTypeAlias, SteamCreatable {}
"""

if swiftNativeType.isInteger {
decl += """
Expand Down
7 changes: 5 additions & 2 deletions Sources/Steamworks/Generated/SteamNetworkingFakeUDPPort.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
///
/// Access via ``SteamNetworkingSockets/createFakeUDPPort(fakeServerPort:)``.
public final class SteamNetworkingFakeUDPPort: Sendable {
private let interface: UnsafeMutablePointer<ISteamNetworkingFakeUDPPort>
private let _interface: SteamUnsafeMutablePointer<ISteamNetworkingFakeUDPPort>
private var interface: UnsafeMutablePointer<ISteamNetworkingFakeUDPPort> {
_interface.base
}
init(_ interface: UnsafeMutablePointer<ISteamNetworkingFakeUDPPort>) {
self.interface = interface
self._interface = .init(interface)
}

/// Steamworks `ISteamNetworkingFakeUDPPort::DestroyFakeUDPPort()`
Expand Down
4 changes: 2 additions & 2 deletions Sources/Steamworks/Generated/Structs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,7 @@ public struct HTMLNeedsPaint: Sendable {
/// Steamworks `unBrowserHandle`
public let browserHandle: HHTMLBrowser
/// Steamworks `pBGRA`
public let bgra: UnsafeRawPointer
public let bgra: SteamUnsafeRawPointer
/// Steamworks `unWide`
public let wide: Int
/// Steamworks `unTall`
Expand All @@ -1898,7 +1898,7 @@ public struct HTMLNeedsPaint: Sendable {
public let pageSerial: Int

/// Create a customized `HTMLNeedsPaint`
public init(browserHandle: HHTMLBrowser = 0, bgra: UnsafeRawPointer, wide: Int = 0, tall: Int = 0, updateX: Int = 0, updateY: Int = 0, updateWide: Int = 0, updateTall: Int = 0, scrollX: Int = 0, scrollY: Int = 0, pageScale: Float = 0, pageSerial: Int = 0) {
public init(browserHandle: HHTMLBrowser = 0, bgra: SteamUnsafeRawPointer, wide: Int = 0, tall: Int = 0, updateX: Int = 0, updateY: Int = 0, updateWide: Int = 0, updateTall: Int = 0, scrollX: Int = 0, scrollY: Int = 0, pageScale: Float = 0, pageSerial: Int = 0) {
self.browserHandle = browserHandle
self.bgra = bgra
self.wide = wide
Expand Down
5 changes: 3 additions & 2 deletions Sources/Steamworks/Generated/Typedefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ extension HHTMLBrowser: ExpressibleByIntegerLiteral {

/// Steamworks `HServerListRequest`
public struct HServerListRequest: Hashable, Sendable {
public let value: UnsafeMutableRawPointer
public init(_ value: UnsafeMutableRawPointer) { self.value = value }
private let _value: SteamUnsafeMutableRawPointer
public var value: UnsafeMutableRawPointer { _value.base }
public init(_ value: UnsafeMutableRawPointer) { self._value = .init(value) }
}

extension HServerListRequest: SteamTypeAlias, SteamCreatable {}
Expand Down
38 changes: 38 additions & 0 deletions Sources/Steamworks/TypeUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,44 @@ extension Optional where Wrapped == UnsafeMutablePointer<UnsafeMutablePointer<Ma
}
}

// MARK: Sendable

/// An unsafe `Sendable` wrapper.
///
/// This is used to wrap pointers that the Steam API uses in a potentially-sendable context.
/// Typically these pointers are read-only, whether or not the Steam API has marked them `const`,
/// so there is no real risk to them, but the Steam API client code is responsible for serializing any
/// write action that is required.
public struct SteamUncheckedSendable<Base>: @unchecked Sendable {
let base: Base
init(_ base: Base) {
self.base = base
}
}

extension SteamUncheckedSendable: Equatable where Base: Equatable {
/// :nodoc:
public static func == (lhs: SteamUncheckedSendable<Base>, rhs: SteamUncheckedSendable<Base>) -> Bool {
lhs.base == rhs.base
}
}

extension SteamUncheckedSendable: Hashable where Base: Hashable {
/// :nodoc:
public func hash(into hasher: inout Hasher) {
base.hash(into: &hasher)
}
}

/// A `Sendable` wrapper of `UnsafeMutableRawPointer`.
public typealias SteamUnsafeMutableRawPointer = SteamUncheckedSendable<UnsafeMutableRawPointer>

/// A `Sendable` wrapper of `UnsafeRawPointer`.
public typealias SteamUnsafeRawPointer = SteamUncheckedSendable<UnsafeRawPointer>

/// A `Sendable` wrapper of `UnsafeMutablePointer`.
public typealias SteamUnsafeMutablePointer<T> = SteamUncheckedSendable<UnsafeMutablePointer<T>>

// MARK: Typedefs

/// Conversion of Swift Types to Steam types, for passing in typedefs to Steamworks
Expand Down

0 comments on commit 788f76e

Please sign in to comment.