Skip to content
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

add support for array input #194

Merged
merged 13 commits into from
Dec 23, 2024
50 changes: 50 additions & 0 deletions swiftwinrt/Resources/Support/Array+FromAbi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import C_BINDINGS_MODULE
import Foundation

@_spi(WinRTInternal)
public typealias WinRTArrayAbi<T> = (count: UInt32, start: UnsafeMutablePointer<T>?)

@_spi(WinRTInternal)
extension Array where Element: FromAbi {
public static func from(abi: WinRTArrayAbi<Element.ABI>) -> [Element] {
UnsafeBufferPointer(start: abi.start, count: Int(abi.count)).map { .from(abi: $0) }
}
}

@_spi(WinRTInternal)
extension Array where Element: Numeric {
public static func from(abi: WinRTArrayAbi<Element>) -> [Element] {
Array(UnsafeBufferPointer(start: abi.start, count: Int(abi.count)))
}
}

// RawRepresentable covers Enums, which are simply numberic types, but the where Element: Numeric doesn't
// cover them. These particular cases are written to ensure no accidental conversion of types that can't
// be simply cast to a C-style Array accidentally sneak in
@_spi(WinRTInternal)
extension Array where Element: RawRepresentable, Element.RawValue: Numeric {
public static func from(abi: WinRTArrayAbi<Element>) -> [Element] {
Array(UnsafeBufferPointer(start: abi.start, count: Int(abi.count)))
}
}

@_spi(WinRTInternal)
extension Array {
public static func from<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, abi: WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) -> [Element] where Element == Bridge.SwiftProjection? {
UnsafeBufferPointer(start: abi.start, count: Int(abi.count)).map { InterfaceWrapperBase<Bridge>.unwrapFrom(abi: ComPtr($0)) }
}
}

@_spi(WinRTInternal)
extension Array {
public static func from<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, start: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?, count: UInt32) -> [Element] where Element == Bridge.SwiftProjection? {
UnsafeBufferPointer(start: start, count: Int(count)).map { InterfaceWrapperBase<Bridge>.unwrapFrom(abi: ComPtr($0)) }
}
}

@_spi(WinRTInternal)
extension Array {
public static func from<Bridge: AbiBridge>(abiBridge: Bridge.Type, abi: WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) -> [Element] where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
UnsafeBufferPointer(start: abi.1, count: Int(abi.0)).map { Bridge.from(abi: ComPtr($0)) }
}
}
57 changes: 57 additions & 0 deletions swiftwinrt/Resources/Support/Array+ToAbi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import C_BINDINGS_MODULE
import Foundation

@_spi(WinRTInternal)
extension Array where Element: ToAbi {
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element.ABI>?) throws -> Void) throws {
let abiArray: [Element.ABI] = try map { try $0.toABI() }
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.ABI.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
}
}
}

@_spi(WinRTInternal)
extension Array where Element: Numeric {
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element>?) throws -> Void) throws {
try withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
}
}
}

@_spi(WinRTInternal)
extension Array where Element: RawRepresentable, Element.RawValue: Numeric {
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element>?) throws -> Void) throws {
try withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
}
}
}

@_spi(WinRTInternal)
extension Array {
public func toABI<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, _ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?) throws -> Void) throws where Element == Bridge.SwiftProjection? {
let abiWrapperArray: [InterfaceWrapperBase<Bridge>?] = map { .init($0) }
let abiArray = try abiWrapperArray.map { try $0?.toABI{ $0 } }
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
}
}
}

@_spi(WinRTInternal)
extension Array {
public func toABI<Bridge: AbiBridge>(abiBridge: Bridge.Type, _ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?) throws -> Void) throws where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
let abiArray: [UnsafeMutablePointer<Bridge.CABI>?] = map { RawPointer($0) }
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
try withAbi(UInt32(count), .init(mutating: bytesPtr))
}
}
}

4 changes: 4 additions & 0 deletions swiftwinrt/Resources/Support/Array+toVector.swift
Original file line number Diff line number Diff line change
@@ -27,6 +27,10 @@ internal class ArrayVector<T> : IVector {
func getView() -> AnyIVectorView<T>? { return ArrayVectorView(storage) }

func first() -> AnyIIterator<T>? { ArrayIterator(storage) }

func replaceAll(_ items: [T]) {
storage = items
}
}

extension ArrayVector where T: Equatable {
23 changes: 22 additions & 1 deletion swiftwinrt/Resources/Support/IInspectable.swift
Original file line number Diff line number Diff line change
@@ -77,7 +77,8 @@ public enum __ABI_ {
return makeFrom(abi: ref) ?? ref
}
public static func tryUnwrapFrom(raw pUnk: UnsafeMutableRawPointer?) -> AnyObject? {
tryUnwrapFromBase(raw: pUnk)
guard let pUnk else { return nil }
return tryUnwrapFromBase(raw: pUnk)
}

internal static func queryInterface(_ pUnk: UnsafeMutablePointer<C_IInspectable>?, _ riid: UnsafePointer<SUPPORT_MODULE.IID>?, _ ppvObject: UnsafeMutablePointer<UnsafeMutableRawPointer?>?) -> HRESULT {
@@ -141,3 +142,23 @@ extension ComposableImpl where CABI == C_IInspectable {
return .init(lpVtbl: vtblPtr)
}
}

@_spi(WinRTInternal)
public enum __IMPL_ {
public enum AnyBridge: AbiInterfaceBridge {
public static func makeAbi() -> CABI {
let vtblPtr = withUnsafeMutablePointer(to: &__ABI_.IInspectableVTable) { $0 }
return .init(lpVtbl: vtblPtr)
}

public static func from(abi: ComPtr<CABI>?) -> SwiftProjection? {
guard let abi else { return nil }
let ref = IInspectable(abi)
return makeFrom(abi: ref) ?? ref
}

public typealias SwiftProjection = Any
public typealias CABI = C_IInspectable
public typealias SwiftABI = SUPPORT_MODULE.IInspectable
}
}
6 changes: 6 additions & 0 deletions swiftwinrt/Resources/Support/RawTyped.swift
Original file line number Diff line number Diff line change
@@ -3,28 +3,34 @@

import WinSDK

@_spi(WinRTInternal)
public func RawPointer<T: IUnknown, U>(_ pUnk: T) -> UnsafeMutablePointer<U> {
return UnsafeMutableRawPointer(pUnk.pUnk.borrow).bindMemory(to: U.self, capacity: 1)
}

@_spi(WinRTInternal)
public func RawPointer<T: IUnknown, U>(_ pUnk: T) -> ComPtr<U> {
return ComPtr(UnsafeMutableRawPointer(pUnk.pUnk.borrow).bindMemory(to: U.self, capacity: 1))
}

@_spi(WinRTInternal)
public func RawPointer<T: IUnknown, U>(_ pUnk: T?) -> UnsafeMutablePointer<U>? {
guard let pUnk else { return nil }
let result: UnsafeMutablePointer<U> = RawPointer(pUnk)
return result
}

@_spi(WinRTInternal)
public func RawPointer<T: WinRTClass, U>(_ obj: T?) -> UnsafeMutablePointer<U>? {
return obj?._getABI()
}

@_spi(WinRTInternal)
public func RawPointer<T: AbiInterfaceImpl, U>(_ obj: T) -> UnsafeMutablePointer<U> {
return RawPointer(obj._default)
}

@_spi(WinRTInternal)
public func RawPointer<T: AbiInterfaceImpl, U>(_ obj: T?) -> UnsafeMutablePointer<U>? {
guard let obj else { return nil}
let result: UnsafeMutablePointer<U> = RawPointer(obj)
113 changes: 84 additions & 29 deletions swiftwinrt/code_writers.h
Original file line number Diff line number Diff line change
@@ -176,21 +176,41 @@ namespace swiftwinrt
s();
w.write("_ %: ", get_swift_name(param));
if (param.out()) w.write("inout ");
write_type(w, *param.type, type_params);
const bool is_array = param.signature.Type().is_array() || param.signature.Type().is_szarray();
if (is_array && type_params.layer == projection_layer::swift)
{
// Can't allow for implicit unwrap in arrays
w.write("[%]", bind<write_type>(*param.type, write_type_params::swift));
}
else
{
write_type(w, *param.type, type_params);
}
}
}
static void write_function_params(writer& w, function_def const& function, write_type_params const& type_params)
{
write_function_params2(w, function.params, type_params);
}

static void write_convert_to_abi_arg(writer& w, std::string_view const& param_name, const metadata_type* type, bool is_out)
template <typename Param>
static void write_convert_to_abi_arg(writer& w, Param const& param)
{
TypeDef signature_type;
auto type = param.type;
auto param_name = param.name;
auto is_out = param.out();

auto category = get_category(type, &signature_type);

auto local_name = local_swift_param_name(param_name);
if (category == param_category::object_type)
if (param.is_array())
{
// Arrays are all converted from the swift array to a c array, so they
// use the local_param_name
w.write("count, %", local_name);
}
else if (category == param_category::object_type)
{
if (is_out) throw std::exception("out parameters of reference types should not be converted directly to abi types");

@@ -286,7 +306,7 @@ namespace swiftwinrt
s();
if (param.in())
{
write_convert_to_abi_arg(w, param_name, param.type, false);
write_convert_to_abi_arg(w, param);
}
else
{
@@ -702,43 +722,59 @@ typealias % = InterfaceWrapperBase<%>

for (auto& param : signature.params)
{
if (param.signature.Type().is_szarray())
{
// TODO: WIN-32 swiftwinrt: add support for arrays
w.write("**TODO: implement szarray in write_convert_vtable_params**");
}
else
std::string param_name = "$" + std::to_string(param_number);


if (param.in())
{
std::string param_name = "$" + std::to_string(param_number);
assert(!param.out());

if (param.in())
if (is_delegate(param.type))
{
assert(!param.out());

if (is_delegate(param.type))
w.write("guard let % = % else { return E_INVALIDARG }\n",
get_swift_name(param),
bind<write_consume_type>(param.type, param_name, false));
}
else if (param.is_array())
{
auto array_param_name = "$" + std::to_string(param_number + 1);
auto count_param_name = param_name;
if (is_reference_type(param.type))
{
w.write("guard let % = % else { return E_INVALIDARG }\n",
w.write("let %: [%] = .from(abiBridge: %.self, abi: (count: %, start: %))\n",
get_swift_name(param),
bind<write_consume_type>(param.type, param_name, false));
bind<write_type>(*param.type, write_type_params::swift),
bind_bridge_fullname(*param.type),
count_param_name,
array_param_name);
}
else
{
w.write("let %: % = %\n",
w.write("let %: [%] = .from(abi: (count: %, start: %))\n",
get_swift_name(param),
bind<write_type>(*param.type, write_type_params::swift),
bind<write_consume_type>(param.type, param_name, false));
count_param_name,
array_param_name);
}
++param_number;
}
else
{
assert(!param.in());
assert(param.out());
w.write("var %: %%\n",
w.write("let %: % = %\n",
get_swift_name(param),
bind<write_type>(*param.type, write_type_params::swift),
bind<write_default_init_assignment>(*param.type, projection_layer::swift));
bind<write_consume_type>(param.type, param_name, false));
}
}
else
{
assert(!param.in());
assert(param.out());
w.write("var %: %%\n",
get_swift_name(param),
bind<write_type>(*param.type, write_type_params::swift),
bind<write_default_init_assignment>(*param.type, projection_layer::swift));
}
++param_number;
}
}
@@ -1628,7 +1664,21 @@ vtable);

if (param.in())
{
if (category == param_category::string_type)
if (param.is_array())
{
if (is_reference_type(param.type))
{
w.write("try %.toABI(abiBridge: %.self) { (count, %) in\n", param_name, bind_bridge_name(*param.type), local_param_name);
}
else
{
w.write("try %.toABI { (count, %) in\n", param_name, local_param_name);
}

guard.push_indent();
guard.push("}\n");
}
else if (category == param_category::string_type)
{
w.write("let % = try! HString(%)\n",
local_param_name,
@@ -2418,7 +2468,7 @@ public init<Composable: ComposableImpl>(
}));

if (compose)
{
{
w.write("@_spi(WinRTInternal)\n");
w.write("public typealias Composable = %\n", composableName);
}
@@ -2736,8 +2786,11 @@ override % func _getABI<T>() -> UnsafeMutablePointer<T>? {
}

// assigns return or out parameters in vtable methods
static void do_write_abi_val_assignment(writer& w, const metadata_type* type, std::string_view const& param_name, std::string_view const& return_param_name)
template<typename T>
static void do_write_abi_val_assignment(writer& w, T const& return_type, std::string_view return_param_name)
{
auto type = return_type.type;
auto param_name = get_swift_member_name(return_type.name);
TypeDef signature_type{};
auto category = get_category(type, &signature_type);

@@ -2768,7 +2821,9 @@ override % func _getABI<T>() -> UnsafeMutablePointer<T>? {

w.write("%?.initialize(to: %)\n",
return_param_name,
bind<write_convert_to_abi_arg>(param_name, type, true)
bind([&](writer& w) {
write_convert_to_abi_arg(w, return_type);
})
);
}

@@ -2781,15 +2836,15 @@ override % func _getABI<T>() -> UnsafeMutablePointer<T>? {
{
auto return_param_name = "$" + std::to_string(param_number);
auto param_name = get_swift_name(param);
do_write_abi_val_assignment(w, param.type, std::string_view(param_name), return_param_name);
do_write_abi_val_assignment(w, param, return_param_name);
}
param_number++;
}

if (signature.return_type)
{
auto return_param_name = "$" + std::to_string(signature.params.size() + 1);
do_write_abi_val_assignment(w, signature.return_type.value().type, signature.return_type.value().name, return_param_name);
do_write_abi_val_assignment(w, signature.return_type.value(), return_param_name);
}
}

Loading