Skip to content

Commit

Permalink
Foundation less impl
Browse files Browse the repository at this point in the history
  • Loading branch information
sidepelican committed Mar 26, 2024
1 parent 6b551cd commit 3dc37fa
Show file tree
Hide file tree
Showing 21 changed files with 153 additions and 154 deletions.
1 change: 0 additions & 1 deletion .swift-version

This file was deleted.

21 changes: 15 additions & 6 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/omochi/CodableToTypeScript",
"state" : {
"revision" : "5a275e389ae179222568fbdd54a105bc16b1d266",
"version" : "2.8.1"
"revision" : "8654d6ff35c9823cff38a6f9dd2aa0e6aed2769b",
"version" : "2.11.0"
}
},
{
Expand All @@ -27,22 +27,31 @@
"version" : "1.0.4"
}
},
{
"identity" : "swift-extras-json",
"kind" : "remoteSourceControl",
"location" : "https://github.com/swift-extras/swift-extras-json.git",
"state" : {
"revision" : "122b9454ef01bf89a4c190b8fd3717ddd0a2fbd0",
"version" : "0.6.0"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax",
"state" : {
"revision" : "cd793adf5680e138bf2bcbaacc292490175d0dcd",
"version" : "508.0.0"
"revision" : "74203046135342e4a4a627476dd6caf8b28fe11b",
"version" : "509.0.0"
}
},
{
"identity" : "swifttypereader",
"kind" : "remoteSourceControl",
"location" : "https://github.com/omochi/SwiftTypeReader",
"state" : {
"revision" : "dca7ae04b1cc71db4fb82ea713982adaa0c0a695",
"version" : "2.5.1"
"revision" : "d21bbe0e0598d1a9a80718f19ea7081053986e1c",
"version" : "2.7.0"
}
},
{
Expand Down
19 changes: 13 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
// swift-tools-version: 5.7
// swift-tools-version: 5.9

import PackageDescription

let package = Package(
name: "WasmCallableKit",
platforms: [.macOS(.v12)],
platforms: [.macOS(.v13)],
products: [
.library(name: "WasmCallableKit", targets: ["WasmCallableKit"]),
.executable(name: "codegen", targets: ["Codegen"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.2"),
.package(url: "https://github.com/omochi/CodableToTypeScript", from: "2.8.1"),
.package(url: "https://github.com/omochi/SwiftTypeReader", from: "2.5.1"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.2"),
.package(url: "https://github.com/omochi/CodableToTypeScript.git", exact: "2.11.0"),
.package(url: "https://github.com/omochi/SwiftTypeReader.git", exact: "2.7.0"),
.package(url: "https://github.com/swift-extras/swift-extras-json.git", .upToNextMajor(from: "0.6.0")),
],
targets: [
.target(name: "WasmCallableKit", dependencies: ["CWasmCallableKit"]),
.target(
name: "WasmCallableKit",
dependencies: [
.product(name: "ExtrasJSON", package: "swift-extras-json"),
"CWasmCallableKit",
]
),
.target(name: "CWasmCallableKit"),
.executableTarget(
name: "Codegen",
Expand Down
32 changes: 12 additions & 20 deletions Sources/Codegen/GenerateSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct GenerateSwift {
var scanResult: ScanResult
var outDirectory: URL

private func buildParamsEntity(params: [ParamDecl]) -> String {
private func buildParamsEntity(params: [FuncParamDecl]) -> String {
return """
struct Params: Decodable {
\(params.enumerated().map({ """
Expand All @@ -16,8 +16,8 @@ struct Params: Decodable {
"""
}

private func buildCallArguments(params: [ParamDecl]) -> String {
return params.enumerated().map { (i, decl: ParamDecl) in
private func buildCallArguments(params: [FuncParamDecl]) -> String {
return params.enumerated().map { (i, decl: FuncParamDecl) in
if let interfaceName = decl.interfaceName {
return "\(interfaceName): args._\(i)"
} else {
Expand All @@ -42,7 +42,7 @@ meta.inits.append { _ in
return """
meta.inits.append { argData in
\(buildParamsEntity(params: decl.parameters).withIndent(1))
let args = try decoder.decode(Params.self, from: argData)
let args = try WasmCallableKit.decodeJSON(Params.self, from: argData)
return \(tryToken)\(className)(
\(buildCallArguments(params: decl.parameters).withIndent(2))
)
Expand All @@ -54,7 +54,7 @@ meta.inits.append { argData in
let methods = classInfo.methods.map { (decl: FuncDecl) in
let tryToken = decl.isThrows ? "try " : ""
let returnReceiver = decl.hasOutput ? "ret" : "_"
let returnStmt = "return \(decl.hasOutput ? "try encoder.encode(ret)" : "Data()")"
let returnStmt = "return \(decl.hasOutput ? "try WasmCallableKit.encodeJSON(ret)" : "[]")"
if decl.parameters.isEmpty {
return """
meta.methods.append { `self`, _ in
Expand All @@ -66,7 +66,7 @@ meta.methods.append { `self`, _ in
return """
meta.methods.append { `self`, argData in
\(buildParamsEntity(params: decl.parameters).withIndent(1))
let args = try decoder.decode(Params.self, from: argData)
let args = try WasmCallableKit.decodeJSON(Params.self, from: argData)
let \(returnReceiver) = \(tryToken)self.\(decl.name)(
\(buildCallArguments(params: decl.parameters).withIndent(2))
)
Expand All @@ -78,10 +78,6 @@ meta.methods.append { `self`, argData in

return """
func build\(className)Metadata() -> ClassMetadata<\(className)> {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .millisecondsSince1970
var meta = ClassMetadata<\(className)>()
\(inits.joined(separator: "\n").withIndent(1))
\(methods.joined(separator: "\n").withIndent(1))
Expand All @@ -90,7 +86,7 @@ func build\(className)Metadata() -> ClassMetadata<\(className)> {
"""
}

let imports = Set(["Foundation", "WasmCallableKit"])
let imports = Set(["WasmCallableKit"])
.union(file.imports.map(\.moduleName))

return """
Expand All @@ -104,7 +100,7 @@ func build\(className)Metadata() -> ClassMetadata<\(className)> {
let methods = globalFuncs.map { (decl: FuncDecl) in
let tryToken = decl.isThrows ? "try " : ""
let returnReceiver = decl.hasOutput ? "ret" : "_"
let returnStmt = "return \(decl.hasOutput ? "try encoder.encode(ret)" : "Data()")"
let returnStmt = "return \(decl.hasOutput ? "try WasmCallableKit.encodeJSON(ret)" : "[]")"
if decl.parameters.isEmpty {
return """
ret.append { _ in
Expand All @@ -116,7 +112,7 @@ ret.append { _ in
return """
ret.append { argData in
\(buildParamsEntity(params: decl.parameters).withIndent(1))
let args = try decoder.decode(Params.self, from: argData)
let args = try WasmCallableKit.decodeJSON(Params.self, from: argData)
let \(returnReceiver) = \(tryToken)\(decl.name)(
\(buildCallArguments(params: decl.parameters).withIndent(2))
)
Expand All @@ -126,18 +122,14 @@ ret.append { argData in
}
}

let imports = Set(["Foundation"])
let imports = Set(["WasmCallableKit"])
.union(allImports.map(\.moduleName))

return """
\(imports.sorted().map { "import \($0)" }.joined(separator: "\n"))
func buildGlobals() -> [(Data) throws -> Data] {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .millisecondsSince1970
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .millisecondsSince1970
var ret: [(Data) throws -> Data] = []
func buildGlobals() -> [([UInt8]) throws -> [UInt8]] {
var ret: [([UInt8]) throws -> [UInt8]] = []
\(methods.joined(separator: "\n").withIndent(1))
return ret
}
Expand Down
12 changes: 6 additions & 6 deletions Sources/Codegen/GenerateTS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ struct GenerateTS {
)
}

private func buildEncodingParam(params: [ParamDecl]) throws -> any TSExpr {
let fields = try params.enumerated().map { (i, decl: ParamDecl) -> TSObjectExpr.Field in
private func buildEncodingParam(params: [FuncParamDecl]) throws -> any TSExpr {
let fields = try params.enumerated().map { (i, decl: FuncParamDecl) -> TSObjectExpr.Field in
let converter = try generator.converter(for: decl.interfaceType)
let hasEncoder = try converter.hasEncode()
let argName = decl.syntaxName!
let argName = decl.syntaxName

return .named(
name: "_\(i)",
Expand Down Expand Up @@ -267,11 +267,11 @@ fileprivate enum DateConvertDecls {
}
}

extension [ParamDecl] {
extension [FuncParamDecl] {
func toTSParams(generator: CodeGenerator) throws -> [TSFunctionType.Param] {
try enumerated().map { i, paramDecl in
try self.map { paramDecl in
TSFunctionType.Param(
name: paramDecl.syntaxName ?? "_\(i)",
name: paramDecl.syntaxName,
type: try generator.converter(for: paramDecl.interfaceType).type(for: .entity)
)
}
Expand Down
30 changes: 11 additions & 19 deletions Sources/WasmCallableKit/ClassCaller.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import CWasmCallableKit
import Foundation

public struct InstanceID: RawRepresentable, Hashable, CustomStringConvertible {
public init(_ value: CInt) {
Expand All @@ -14,17 +13,17 @@ public struct InstanceID: RawRepresentable, Hashable, CustomStringConvertible {

public protocol ClassMetadataProtocol<C> {
associatedtype C: AnyObject
var inits: [(Data) throws -> C] { get }
var methods: [(C, Data) throws -> Data] { get }
func initAndBind(initializerID: Int, argData: Data) throws -> any ClassBindingProtocol
var inits: [([UInt8]) throws -> C] { get }
var methods: [(C, [UInt8]) throws -> [UInt8]] { get }
func initAndBind(initializerID: Int, argData: [UInt8]) throws -> any ClassBindingProtocol
}

public struct ClassMetadata<C: AnyObject>: ClassMetadataProtocol {
public init() {}
public var inits: [(Data) throws -> C] = []
public var methods: [(C, Data) throws -> Data] = []
public var inits: [([UInt8]) throws -> C] = []
public var methods: [(C, [UInt8]) throws -> [UInt8]] = []

public func initAndBind(initializerID: Int, argData: Data) throws -> any ClassBindingProtocol {
public func initAndBind(initializerID: Int, argData: [UInt8]) throws -> any ClassBindingProtocol {
let `init` = inits[initializerID]
return Binding(
instance: try `init`(argData),
Expand All @@ -35,14 +34,14 @@ public struct ClassMetadata<C: AnyObject>: ClassMetadataProtocol {

public protocol ClassBindingProtocol<C> {
associatedtype C: AnyObject
func send(functionID: Int, argData: Data) throws -> Data
func send(functionID: Int, argData: [UInt8]) throws -> [UInt8]
}

private struct Binding<C: AnyObject>: ClassBindingProtocol {
var instance: C
var metadata: ClassMetadata<C>

func send(functionID: Int, argData: Data) throws -> Data {
func send(functionID: Int, argData: [UInt8]) throws -> [UInt8] {
try metadata.methods[functionID](instance, argData)
}
}
Expand All @@ -63,13 +62,9 @@ extension WasmCallableKit {

@_cdecl("ck_class_init_impl")
func ck_class_init_impl(_ classID: CInt, _ initilizerID: CInt, _ argumentBufferLength: CInt) -> CInt {
let metadata = classMetadata[Int(classID)]

let memory = malloc(Int(argumentBufferLength)).assumingMemoryBound(to: UInt8.self)
defer { memory.deallocate() }
receive_arg(memory)
let arg = consumeArgumentBuffer(argumentBufferLength)

let arg = Data(String(decodingCString: memory, as: UTF8.self).utf8)
let metadata = classMetadata[Int(classID)]
do {
let binding = try metadata.initAndBind(initializerID: Int(initilizerID), argData: arg)
let instanceID = takeInstanceID()
Expand All @@ -86,9 +81,7 @@ func ck_class_init_impl(_ classID: CInt, _ initilizerID: CInt, _ argumentBufferL

@_cdecl("ck_class_send_impl")
func ck_class_send_impl(_ instanceID: CInt, _ functionID: CInt, _ argumentBufferLength: CInt) -> CInt {
let memory = malloc(Int(argumentBufferLength)).assumingMemoryBound(to: UInt8.self)
defer { memory.deallocate() }
receive_arg(memory)
let arg = consumeArgumentBuffer(argumentBufferLength)

let instanceID = InstanceID(instanceID)
guard let binding = bindings.first(where: { $0.0 == instanceID })?.1 else {
Expand All @@ -99,7 +92,6 @@ func ck_class_send_impl(_ instanceID: CInt, _ functionID: CInt, _ argumentBuffer
return -1;
}

let arg = Data(String(decodingCString: memory, as: UTF8.self).utf8)
do {
let ret = try binding.send(functionID: Int(functionID), argData: arg)
ret.withUnsafeBytes { (p: UnsafeRawBufferPointer) in
Expand Down
19 changes: 12 additions & 7 deletions Sources/WasmCallableKit/WasmCallableKit.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import CWasmCallableKit
import Foundation

private var functionList: [(Data) throws -> Data]!
private var functionList: [([UInt8]) throws -> [UInt8]]!

public enum WasmCallableKit {
public static func setFunctionList(_ functions: [(Data) throws -> Data]) {
public static func setFunctionList(_ functions: [([UInt8]) throws -> [UInt8]]) {
functionList = functions
}
}

@_cdecl("ck_send_impl")
func ck_send_impl(_ functionID: CInt, _ argumentBufferLength: CInt) -> CInt {
let memory = malloc(Int(argumentBufferLength)).assumingMemoryBound(to: UInt8.self)
defer { memory.deallocate() }
receive_arg(memory)
let arg = consumeArgumentBuffer(argumentBufferLength)

let arg = Data(String(decodingCString: memory, as: UTF8.self).utf8)
do {
let ret = try functionList[Int(functionID)](arg)
ret.withUnsafeBytes { (p: UnsafeRawBufferPointer) in
Expand All @@ -30,3 +26,12 @@ func ck_send_impl(_ functionID: CInt, _ argumentBufferLength: CInt) -> CInt {
return -1;
}
}

func consumeArgumentBuffer(_ argumentBufferLength: CInt) -> [UInt8] {
var arg = Array<UInt8>(repeating: 0, count: Int(argumentBufferLength))
arg.withUnsafeMutableBufferPointer { p in
receive_arg(p.baseAddress!)
}
arg.removeLast() // remove null terminator
return arg
}
13 changes: 13 additions & 0 deletions Sources/WasmCallableKit/json.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ExtrasJSON

extension WasmCallableKit {
@inlinable
public static func encodeJSON(_ object: some Encodable) throws -> [UInt8] {
return try XJSONEncoder().encode(object)
}

@inlinable
public static func decodeJSON<T: Decodable>(_ type: T.Type, from data: some Collection<UInt8>) throws -> T {
return try XJSONDecoder().decode(type, from: data)
}
}
Loading

0 comments on commit 3dc37fa

Please sign in to comment.