Skip to content

Commit

Permalink
Add linux support (#6)
Browse files Browse the repository at this point in the history
With lots of workarounds for the fact that AnyHashable is broken in
the linux Swift port.
  • Loading branch information
tomsci authored Nov 8, 2024
1 parent dfa65ef commit b3a49ba
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 14 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,36 @@ jobs:
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v2

build-linux:

runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: recursive
- uses: swift-actions/setup-swift@v2
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v

build-oss:

runs-on: macos-13

steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: recursive
- uses: swift-actions/setup-swift@v2
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v

deploy:
needs: build
if: ${{ github.ref == 'refs/heads/main' }}
Expand Down
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ let package = Package(
resources: [],
swiftSettings: [
// .define("LUASWIFT_NO_FOUNDATION")
.define("LUASWIFT_ANYHASHABLE_BROKEN", .when(platforms: [.linux]))
]
),
.target(
Expand Down Expand Up @@ -82,6 +83,7 @@ let package = Package(
],
swiftSettings: [
// .define("LUASWIFT_NO_FOUNDATION")
.define("LUASWIFT_ANYHASHABLE_BROKEN", .when(platforms: [.linux]))
],
plugins: [
.plugin(name: "EmbedLuaPlugin")
Expand Down
1 change: 1 addition & 0 deletions Sources/Lua/LuaFoundation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#if !LUASWIFT_NO_FOUNDATION // canImport(Foundation)

import Foundation
import CoreFoundation
import CLua

/// Represents all the String encodings that this framework can convert strings to and from.
Expand Down
46 changes: 46 additions & 0 deletions Sources/Lua/LuaState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -935,9 +935,13 @@ extension UnsafeMutablePointer where Pointee == lua_State {
return ptr
case .number:
if let intVal = tointeger(index) {
#if LUASWIFT_ANYHASHABLE_BROKEN
return intVal
#else
// Integers are returned type-erased (thanks to AnyHashable) meaning fewer cast restrictions in
// eg tovalue()
return AnyHashable(intVal)
#endif
} else {
return tonumber(index)
}
Expand Down Expand Up @@ -1117,6 +1121,48 @@ extension UnsafeMutablePointer where Pointee == lua_State {
}
}

#if LUASWIFT_ANYHASHABLE_BROKEN
// Then the directCast clause above won't have worked, and we need to try every integer type
if t == .number, let intVal = value as? lua_Integer {
if let intSubType = Int(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = Int8(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = Int16(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = Int32(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = Int64(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = UInt(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = UInt8(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = UInt16(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = UInt32(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let intSubType = UInt64(exactly: intVal), let ret = intSubType as? T {
return ret
}
if let dbl = Double(exactly: intVal), let ret = dbl as? T {
return ret
}
if let flt = Float(exactly: intVal), let ret = flt as? T {
return ret
}
}
#endif

return nil
}

Expand Down
142 changes: 132 additions & 10 deletions Sources/Lua/LuaTableRef.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public struct LuaTableRef {
}
}

// ElementType will only ever be Any or AnyHashable (needed when resolving Dictionary keys)
private func doResolveArray<ElementType>(test: (Array<ElementType>) -> Bool) -> Array<ElementType>? {
var testArray = Array<ElementType>()
func good(_ val: Any) -> Bool {
Expand Down Expand Up @@ -119,7 +120,11 @@ public struct LuaTableRef {
elementType = .rawpointer
acceptsAny = false
} else {
#if LUASWIFT_ANYHASHABLE_BROKEN
elementType = TypeConstraint(intTest: good)
#else
elementType = nil
#endif
acceptsAny = false
}

Expand Down Expand Up @@ -162,6 +167,10 @@ public struct LuaTableRef {
result.append(ref.guessType()) // as per tovalue() docs
case .dict, .array, .hashableDict, .hashableArray, .direct, .rawpointer: // None of these are applicable for TypeConstraint(stringTest:)
fatalError()
#if LUASWIFT_ANYHASHABLE_BROKEN
case .int, .int8, .int16, .int32, .int64, .uint, .uint8, .uint16, .uint32, .uint64: // Ditto
fatalError()
#endif
case .none: // TypeConstraint(stringTest:) failed to find any compatible type
return nil
}
Expand Down Expand Up @@ -193,10 +202,14 @@ public struct LuaTableRef {
resolvedVal = nil
}
case .string, .bytes, .direct, .rawpointer: // None of these are applicable for TypeConstraint(tableTest:)
return nil
fatalError()
#if LUASWIFT_ANYHASHABLE_BROKEN
case .int, .int8, .int16, .int32, .int64, .uint, .uint8, .uint16, .uint32, .uint64: // Ditto
fatalError()
#endif
#if !LUASWIFT_NO_FOUNDATION
case .data: // ditto
return nil
fatalError()
#endif
case .none: // TypeConstraint(tableTest:) failed to find any compatible type
return nil
Expand All @@ -211,6 +224,19 @@ public struct LuaTableRef {
} else if elementType == .rawpointer, let mut = value as? UnsafeMutableRawPointer {
result.append(UnsafeRawPointer(mut))
} else {
#if LUASWIFT_ANYHASHABLE_BROKEN
if let elementType {
switch elementType {
case .int, .int8, .int16, .int32, .int64, .uint, .uint8, .uint16, .uint32, .uint64:
// Reuse PossibleValue's actualValue cos I'm lazy (L isn't actually used but must be specified...)
result.append(PossibleValue(type: elementType, testValue: value).actualValue(L, 0, value)!)
continue
default:
break
}

}
#endif
// Nothing from toany has made T happy, give up
return nil
}
Expand Down Expand Up @@ -330,6 +356,10 @@ public struct LuaTableRef {
case .data: self.testValue = emptyData
#endif
case .direct: self.testValue = testValue!
#if LUASWIFT_ANYHASHABLE_BROKEN
case .int, .int8, .int16, .int32, .int64, .uint, .uint8, .uint16, .uint32, .uint64:
self.testValue = testValue!
#endif
case .luavalue: self.testValue = LuaValue.nilValue
case .anyhashable: self.testValue = opaqueHashable
case .rawpointer: self.testValue = dummyRawPtr
Expand All @@ -346,6 +376,18 @@ public struct LuaTableRef {
case .array, .hashableArray: fatalError("Can't call actualValue on an array")
case .dict, .hashableDict: fatalError("Can't call actualValue on a dict")
case .direct: return anyVal
#if LUASWIFT_ANYHASHABLE_BROKEN
case .int: return Int(exactly: anyVal as! lua_Integer)
case .int8: return Int8(exactly: anyVal as! lua_Integer)
case .int16: return Int16(exactly: anyVal as! lua_Integer)
case .int32: return Int32(exactly: anyVal as! lua_Integer)
case .int64: return Int64(exactly: anyVal as! lua_Integer)
case .uint: return UInt(exactly: anyVal as! lua_Integer)
case .uint8: return UInt8(exactly: anyVal as! lua_Integer)
case .uint16: return UInt16(exactly: anyVal as! lua_Integer)
case .uint32: return UInt32(exactly: anyVal as! lua_Integer)
case .uint64: return UInt64(exactly: anyVal as! lua_Integer)
#endif
case .luavalue: return L.ref(index: index)
case .anyhashable:
if let stringRef {
Expand Down Expand Up @@ -416,6 +458,46 @@ public struct LuaTableRef {
if type == nil || type == .direct {
result.append(PossibleValue(type: .direct, testValue: value))
}
#if LUASWIFT_ANYHASHABLE_BROKEN
if value is lua_Integer {
if type == nil || type == .int {
result.append(PossibleValue(type: .int, testValue: 0 as Int))
}
if type == nil || type == .int8 {
result.append(PossibleValue(type: .int8, testValue: 0 as Int8))
}
if type == nil || type == .int16 {
result.append(PossibleValue(type: .int16, testValue: 0 as Int16))
}
if type == nil || type == .int16 {
result.append(PossibleValue(type: .int16, testValue: 0 as Int16))
}
if type == nil || type == .int32 {
result.append(PossibleValue(type: .int32, testValue: 0 as Int32))
}
if type == nil || type == .int64 {
result.append(PossibleValue(type: .int64, testValue: 0 as Int64))
}
if type == nil || type == .uint {
result.append(PossibleValue(type: .uint, testValue: 0 as UInt))
}
if type == nil || type == .uint8 {
result.append(PossibleValue(type: .uint8, testValue: 0 as UInt8))
}
if type == nil || type == .uint16 {
result.append(PossibleValue(type: .uint16, testValue: 0 as UInt16))
}
if type == nil || type == .uint16 {
result.append(PossibleValue(type: .uint16, testValue: 0 as UInt16))
}
if type == nil || type == .uint32 {
result.append(PossibleValue(type: .uint32, testValue: 0 as UInt32))
}
if type == nil || type == .uint64 {
result.append(PossibleValue(type: .uint64, testValue: 0 as UInt64))
}
}
#endif
if type == nil || type == .rawpointer {
result.append(PossibleValue(type: .rawpointer))
}
Expand Down Expand Up @@ -462,6 +544,18 @@ enum TypeConstraint {
case anyhashable // AnyHashable (or Any, in some contexts)
case luavalue
case rawpointer // UnsafeRawPointer (relevant when we have UnsafeMutableRawPointer from a [light]userdata)
#if LUASWIFT_ANYHASHABLE_BROKEN
case int
case int8
case int16
case int32
case int64
case uint
case uint8
case uint16
case uint32
case uint64
#endif
}

extension TypeConstraint {
Expand Down Expand Up @@ -495,6 +589,34 @@ extension TypeConstraint {
return nil
}
}

#if LUASWIFT_ANYHASHABLE_BROKEN
init?(intTest test: (Any) -> Bool) {
if test(0 as Int) {
self = .int
} else if test(0 as Int8) {
self = .int8
} else if test(0 as Int16) {
self = .int16
} else if test(0 as Int32) {
self = .int32
} else if test(0 as Int64) {
self = .int64
} else if test(0 as UInt) {
self = .uint
} else if test(0 as UInt8) {
self = .uint8
} else if test(0 as UInt16) {
self = .uint16
} else if test(0 as UInt32) {
self = .uint32
} else if test(0 as UInt64) {
self = .uint64
} else {
return nil
}
}
#endif
}

fileprivate func isArrayType<T>(_: T?) -> Bool {
Expand All @@ -517,9 +639,9 @@ extension Dictionary where Key == AnyHashable, Value == Any {
///
/// This function is also defined on `Dictionary<AnyHashable, AnyHashable>`, see ``luaTableToArray()-3ngmn``.
public func luaTableToArray() -> [Any]? {
var intKeys: [Int] = []
var intKeys: [lua_Integer] = []
for (k, _) in self {
if let intKey = k as? Int, intKey > 0 {
if let intKey = k as? lua_Integer, intKey > 0 {
intKeys.append(intKey)
} else {
// Non integer key found, doom
Expand All @@ -530,9 +652,9 @@ extension Dictionary where Key == AnyHashable, Value == Any {
// Now check all those integer keys are a sequence and build the result
intKeys.sort()
var result: [Any] = []
var i = 1
var i: lua_Integer = 1
while i <= intKeys.count {
if intKeys[i-1] == i {
if intKeys[Int(i-1)] == i {
result.append(self[i]!)
i = i + 1
} else {
Expand All @@ -557,9 +679,9 @@ extension Dictionary where Key == AnyHashable, Value == AnyHashable {
///
/// This function is also defined on `Dictionary<AnyHashable, Any>`, see ``luaTableToArray()-7jqqs``.
public func luaTableToArray() -> [AnyHashable]? {
var intKeys: [Int] = []
var intKeys: [lua_Integer] = []
for (k, _) in self {
if let intKey = k as? Int, intKey > 0 {
if let intKey = k as? lua_Integer, intKey > 0 {
intKeys.append(intKey)
} else {
// Non integer key found, doom
Expand All @@ -570,9 +692,9 @@ extension Dictionary where Key == AnyHashable, Value == AnyHashable {
// Now check all those integer keys are a sequence and build the result
intKeys.sort()
var result: [AnyHashable] = []
var i = 1
var i: lua_Integer = 1
while i <= intKeys.count {
if intKeys[i-1] == i {
if intKeys[Int(i-1)] == i {
result.append(self[i]!)
i = i + 1
} else {
Expand Down
Loading

0 comments on commit b3a49ba

Please sign in to comment.