Skip to content

Commit

Permalink
Finished IRestrictedErrorInfo vtable.
Browse files Browse the repository at this point in the history
Started generating vtables.
  • Loading branch information
tristanlabelle committed Dec 5, 2023
1 parent 77901e6 commit 5d197bc
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ extension SwiftAssemblyModuleFileWriter {
initialValue: try Self.toIIDExpression(WindowsMetadata.getInterfaceID(interfaceOrDelegate)))

if classDefinition == nil {
writer.writeComputedProperty(
visibility: .public, static: true, name: "virtualTablePointer",
type: .identifier("COMVirtualTablePointer"),
get: { writer in writer.writeNotImplemented() })
try writer.writeStoredProperty(
visibility: .public, static: true, declarator: .var, name: "virtualTablePointer",
initializer: { try writeVirtualTable(interfaceOrDelegate: interfaceOrDelegate, to: $0) })
}

let isDelegate = interfaceOrDelegate.definition is DelegateDefinition
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import CodeWriters
import DotNetMetadata
import WindowsMetadata

extension SwiftAssemblyModuleFileWriter {
func writeVirtualTable(interfaceOrDelegate: BoundType, to output: IndentedTextOutputStream) throws {
try output.writeIndentedBlock(header: "COMVirtualTable(", footer: ")") {
// IUnknown methods
output.writeFullLine("QueryInterface: { this, iid, ppvObject in _queryInterface(this, iid, ppvObject) },")
output.writeFullLine("AddRef: { this in _addRef(this) },")
output.write("Release: { this in _release(this) }")

// IInspectable methods (except for delegates)
if interfaceOrDelegate.definition is InterfaceDefinition {
output.write(",", endLine: true)
output.writeFullLine("GetIids: { this, iidCount, iids in _getIids(this, iidCount, iids) },")
output.writeFullLine("GetRuntimeClassName: { this, className in _getRuntimeClassName(this, className) },")
output.write("GetTrustLevel: { this, trustLevel in _getTrustLevel(this, trustLevel) }")
}

// Custom interface/delegate methods
for method in interfaceOrDelegate.definition.methods {
output.write(",", endLine: true)
try writeVirtualTableFunc(method, genericTypeArgs: interfaceOrDelegate.genericArgs, to: output)
}
}
}

fileprivate func writeVirtualTableFunc(_ method: Method, genericTypeArgs: [TypeNode], to output: IndentedTextOutputStream) throws {
// Special case for getters
if try method.params.count == 0 && method.hasReturnValue {
return try writeVirtualTableGetter(method, genericTypeArgs: genericTypeArgs, to: output)
}

try writeVirtualTableFuncImplementation(
name: method.findAttribute(OverloadAttribute.self) ?? method.name,
paramNames: method.params.map { $0.name! },
to: output) {
// Declare Swift values for out params
// Invoke the Swift implementation
// Convert out params to the ABI representation
output.writeFullLine("fatalError(\"Not implemented: \\(#function)\")")
}
}

fileprivate func writeVirtualTableGetter(_ method: Method, genericTypeArgs: [TypeNode], to output: IndentedTextOutputStream) throws {
let memberInvocation: String
if case .special = method.nameKind, method.name.hasPrefix("get_") {
let propertyName = method.name[method.name.index(method.name.startIndex, offsetBy: 4)...]
memberInvocation = Casing.pascalToCamel(String(propertyName))
} else {
let methodName = projection.toMemberName(method)
memberInvocation = "\(methodName)()"
}

let returnTypeProjection = try projection.getTypeProjection(
method.returnType.bindGenericParams(typeArgs: genericTypeArgs))
let abiName = try method.findAttribute(OverloadAttribute.self) ?? method.name
output.write("\(abiName): { this, result in _getter(this, result) { "
+ "try \(returnTypeProjection.projectionType).toABI($0.\(memberInvocation)) } },")
}

fileprivate func writeVirtualTableFuncImplementation(name: String, paramNames: [String], to output: IndentedTextOutputStream, body: () throws -> Void) rethrows {
output.write(name)
output.write(": ")
output.write("{ this")
for paramName in paramNames {
output.write(", \(paramName)")
}
try output.writeIndentedBlock(header: " in _implement(this) { this in", body: body)
output.write("} }")
}
}
17 changes: 16 additions & 1 deletion Support/Sources/WindowsRuntime/IRestrictedErrorInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,22 @@ public enum IRestrictedErrorInfoProjection: COMTwoWayProjection {
QueryInterface: { this, iid, ppvObject in _queryInterface(this, iid, ppvObject) },
AddRef: { this in _addRef(this) },
Release: { this in _release(this) },
GetErrorDetails: { this, _, _, _, _ in fatalError("Not implemented: \(#function)") },
GetErrorDetails: { this, description, error, restrictedDescription, capabilitySid in _implement(this) {
var description_: String? = nil
var error_: HResult = .ok
var restrictedDescription_: String? = nil
var capabilitySid_: String? = nil
try $0.getErrorDetails(description: &description_, error: &error_, restrictedDescription: &restrictedDescription_, capabilitySid: &capabilitySid_)
var _success = false
if let description { description.pointee = try BStrProjection.toABI(description_) }
defer { if !_success, let description { BStrProjection.release(&description.pointee) } }
if let error { error.pointee = HResultProjection.toABI(error_) }
if let restrictedDescription { restrictedDescription.pointee = try BStrProjection.toABI(restrictedDescription_) }
defer { if !_success, let restrictedDescription { BStrProjection.release(&restrictedDescription.pointee) } }
if let capabilitySid { capabilitySid.pointee = try BStrProjection.toABI(capabilitySid_) }
defer { if !_success, let capabilitySid { BStrProjection.release(&capabilitySid.pointee) } }
_success = true
} },
GetReference: { this, reference in _getter(this, reference) { try BStrProjection.toABI($0.reference) } }
)
}
Expand Down

0 comments on commit 5d197bc

Please sign in to comment.