Skip to content

Commit 9a4be08

Browse files
authored
add support for array input (#194)
* add abihelper and to/from abi * fixing things up * test other types * fix tests * remove unnecessary try * move array tests to their own class * these can't throw * dont use the swift name for abi args * fix array input in debug builds * rename to get_swift_member_name * add comment on RawRepresentable * shouldn't have done this * fix build
1 parent 1095be9 commit 9a4be08

28 files changed

+894
-185
lines changed

Diff for: swiftwinrt/Resources/Support/Array+FromAbi.swift

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import C_BINDINGS_MODULE
2+
import Foundation
3+
4+
@_spi(WinRTInternal)
5+
public typealias WinRTArrayAbi<T> = (count: UInt32, start: UnsafeMutablePointer<T>?)
6+
7+
@_spi(WinRTInternal)
8+
extension Array where Element: FromAbi {
9+
public static func from(abi: WinRTArrayAbi<Element.ABI>) -> [Element] {
10+
UnsafeBufferPointer(start: abi.start, count: Int(abi.count)).map { .from(abi: $0) }
11+
}
12+
}
13+
14+
@_spi(WinRTInternal)
15+
extension Array where Element: Numeric {
16+
public static func from(abi: WinRTArrayAbi<Element>) -> [Element] {
17+
Array(UnsafeBufferPointer(start: abi.start, count: Int(abi.count)))
18+
}
19+
}
20+
21+
// RawRepresentable covers Enums, which are simply numberic types, but the where Element: Numeric doesn't
22+
// cover them. These particular cases are written to ensure no accidental conversion of types that can't
23+
// be simply cast to a C-style Array accidentally sneak in
24+
@_spi(WinRTInternal)
25+
extension Array where Element: RawRepresentable, Element.RawValue: Numeric {
26+
public static func from(abi: WinRTArrayAbi<Element>) -> [Element] {
27+
Array(UnsafeBufferPointer(start: abi.start, count: Int(abi.count)))
28+
}
29+
}
30+
31+
@_spi(WinRTInternal)
32+
extension Array {
33+
public static func from<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, abi: WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) -> [Element] where Element == Bridge.SwiftProjection? {
34+
UnsafeBufferPointer(start: abi.start, count: Int(abi.count)).map { InterfaceWrapperBase<Bridge>.unwrapFrom(abi: ComPtr($0)) }
35+
}
36+
}
37+
38+
@_spi(WinRTInternal)
39+
extension Array {
40+
public static func from<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, start: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?, count: UInt32) -> [Element] where Element == Bridge.SwiftProjection? {
41+
UnsafeBufferPointer(start: start, count: Int(count)).map { InterfaceWrapperBase<Bridge>.unwrapFrom(abi: ComPtr($0)) }
42+
}
43+
}
44+
45+
@_spi(WinRTInternal)
46+
extension Array {
47+
public static func from<Bridge: AbiBridge>(abiBridge: Bridge.Type, abi: WinRTArrayAbi<UnsafeMutablePointer<Bridge.CABI>?>) -> [Element] where Element == Bridge.SwiftProjection?, Bridge.SwiftProjection: WinRTClass {
48+
UnsafeBufferPointer(start: abi.1, count: Int(abi.0)).map { Bridge.from(abi: ComPtr($0)) }
49+
}
50+
}

Diff for: swiftwinrt/Resources/Support/Array+ToAbi.swift

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import C_BINDINGS_MODULE
2+
import Foundation
3+
4+
@_spi(WinRTInternal)
5+
extension Array where Element: ToAbi {
6+
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element.ABI>?) throws -> Void) throws {
7+
let abiArray: [Element.ABI] = try map { try $0.toABI() }
8+
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
9+
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.ABI.self)
10+
try withAbi(UInt32(count), .init(mutating: bytesPtr))
11+
}
12+
}
13+
}
14+
15+
@_spi(WinRTInternal)
16+
extension Array where Element: Numeric {
17+
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element>?) throws -> Void) throws {
18+
try withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
19+
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.self)
20+
try withAbi(UInt32(count), .init(mutating: bytesPtr))
21+
}
22+
}
23+
}
24+
25+
@_spi(WinRTInternal)
26+
extension Array where Element: RawRepresentable, Element.RawValue: Numeric {
27+
public func toABI(_ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<Element>?) throws -> Void) throws {
28+
try withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
29+
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: Element.self)
30+
try withAbi(UInt32(count), .init(mutating: bytesPtr))
31+
}
32+
}
33+
}
34+
35+
@_spi(WinRTInternal)
36+
extension Array {
37+
public func toABI<Bridge: AbiInterfaceBridge>(abiBridge: Bridge.Type, _ withAbi: (_ length: UInt32, _ bytes: UnsafeMutablePointer<UnsafeMutablePointer<Bridge.CABI>?>?) throws -> Void) throws where Element == Bridge.SwiftProjection? {
38+
let abiWrapperArray: [InterfaceWrapperBase<Bridge>?] = map { .init($0) }
39+
let abiArray = try abiWrapperArray.map { try $0?.toABI{ $0 } }
40+
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
41+
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
42+
try withAbi(UInt32(count), .init(mutating: bytesPtr))
43+
}
44+
}
45+
}
46+
47+
@_spi(WinRTInternal)
48+
extension Array {
49+
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 {
50+
let abiArray: [UnsafeMutablePointer<Bridge.CABI>?] = map { RawPointer($0) }
51+
try abiArray.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
52+
let bytesPtr = bytes.baseAddress?.assumingMemoryBound(to: UnsafeMutablePointer<Bridge.CABI>?.self)
53+
try withAbi(UInt32(count), .init(mutating: bytesPtr))
54+
}
55+
}
56+
}
57+

Diff for: swiftwinrt/Resources/Support/Array+toVector.swift

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ internal class ArrayVector<T> : IVector {
2727
func getView() -> AnyIVectorView<T>? { return ArrayVectorView(storage) }
2828

2929
func first() -> AnyIIterator<T>? { ArrayIterator(storage) }
30+
31+
func replaceAll(_ items: [T]) {
32+
storage = items
33+
}
3034
}
3135

3236
extension ArrayVector where T: Equatable {

Diff for: swiftwinrt/Resources/Support/IInspectable.swift

+22-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public enum __ABI_ {
7777
return makeFrom(abi: ref) ?? ref
7878
}
7979
public static func tryUnwrapFrom(raw pUnk: UnsafeMutableRawPointer?) -> AnyObject? {
80-
tryUnwrapFromBase(raw: pUnk)
80+
guard let pUnk else { return nil }
81+
return tryUnwrapFromBase(raw: pUnk)
8182
}
8283

8384
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 {
141142
return .init(lpVtbl: vtblPtr)
142143
}
143144
}
145+
146+
@_spi(WinRTInternal)
147+
public enum __IMPL_ {
148+
public enum AnyBridge: AbiInterfaceBridge {
149+
public static func makeAbi() -> CABI {
150+
let vtblPtr = withUnsafeMutablePointer(to: &__ABI_.IInspectableVTable) { $0 }
151+
return .init(lpVtbl: vtblPtr)
152+
}
153+
154+
public static func from(abi: ComPtr<CABI>?) -> SwiftProjection? {
155+
guard let abi else { return nil }
156+
let ref = IInspectable(abi)
157+
return makeFrom(abi: ref) ?? ref
158+
}
159+
160+
public typealias SwiftProjection = Any
161+
public typealias CABI = C_IInspectable
162+
public typealias SwiftABI = SUPPORT_MODULE.IInspectable
163+
}
164+
}

Diff for: swiftwinrt/Resources/Support/RawTyped.swift

+6
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,34 @@
33

44
import WinSDK
55

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

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

16+
@_spi(WinRTInternal)
1417
public func RawPointer<T: IUnknown, U>(_ pUnk: T?) -> UnsafeMutablePointer<U>? {
1518
guard let pUnk else { return nil }
1619
let result: UnsafeMutablePointer<U> = RawPointer(pUnk)
1720
return result
1821
}
1922

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

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

33+
@_spi(WinRTInternal)
2834
public func RawPointer<T: AbiInterfaceImpl, U>(_ obj: T?) -> UnsafeMutablePointer<U>? {
2935
guard let obj else { return nil}
3036
let result: UnsafeMutablePointer<U> = RawPointer(obj)

Diff for: swiftwinrt/code_writers.h

+84-29
Original file line numberDiff line numberDiff line change
@@ -176,21 +176,41 @@ namespace swiftwinrt
176176
s();
177177
w.write("_ %: ", get_swift_name(param));
178178
if (param.out()) w.write("inout ");
179-
write_type(w, *param.type, type_params);
179+
const bool is_array = param.signature.Type().is_array() || param.signature.Type().is_szarray();
180+
if (is_array && type_params.layer == projection_layer::swift)
181+
{
182+
// Can't allow for implicit unwrap in arrays
183+
w.write("[%]", bind<write_type>(*param.type, write_type_params::swift));
184+
}
185+
else
186+
{
187+
write_type(w, *param.type, type_params);
188+
}
180189
}
181190
}
182191
static void write_function_params(writer& w, function_def const& function, write_type_params const& type_params)
183192
{
184193
write_function_params2(w, function.params, type_params);
185194
}
186195

187-
static void write_convert_to_abi_arg(writer& w, std::string_view const& param_name, const metadata_type* type, bool is_out)
196+
template <typename Param>
197+
static void write_convert_to_abi_arg(writer& w, Param const& param)
188198
{
189199
TypeDef signature_type;
200+
auto type = param.type;
201+
auto param_name = param.name;
202+
auto is_out = param.out();
203+
190204
auto category = get_category(type, &signature_type);
191205

192206
auto local_name = local_swift_param_name(param_name);
193-
if (category == param_category::object_type)
207+
if (param.is_array())
208+
{
209+
// Arrays are all converted from the swift array to a c array, so they
210+
// use the local_param_name
211+
w.write("count, %", local_name);
212+
}
213+
else if (category == param_category::object_type)
194214
{
195215
if (is_out) throw std::exception("out parameters of reference types should not be converted directly to abi types");
196216

@@ -286,7 +306,7 @@ namespace swiftwinrt
286306
s();
287307
if (param.in())
288308
{
289-
write_convert_to_abi_arg(w, param_name, param.type, false);
309+
write_convert_to_abi_arg(w, param);
290310
}
291311
else
292312
{
@@ -702,43 +722,59 @@ typealias % = InterfaceWrapperBase<%>
702722

703723
for (auto& param : signature.params)
704724
{
705-
if (param.signature.Type().is_szarray())
706-
{
707-
// TODO: WIN-32 swiftwinrt: add support for arrays
708-
w.write("**TODO: implement szarray in write_convert_vtable_params**");
709-
}
710-
else
725+
std::string param_name = "$" + std::to_string(param_number);
726+
727+
728+
if (param.in())
711729
{
712-
std::string param_name = "$" + std::to_string(param_number);
730+
assert(!param.out());
713731

714-
if (param.in())
732+
if (is_delegate(param.type))
715733
{
716-
assert(!param.out());
717-
718-
if (is_delegate(param.type))
734+
w.write("guard let % = % else { return E_INVALIDARG }\n",
735+
get_swift_name(param),
736+
bind<write_consume_type>(param.type, param_name, false));
737+
}
738+
else if (param.is_array())
739+
{
740+
auto array_param_name = "$" + std::to_string(param_number + 1);
741+
auto count_param_name = param_name;
742+
if (is_reference_type(param.type))
719743
{
720-
w.write("guard let % = % else { return E_INVALIDARG }\n",
744+
w.write("let %: [%] = .from(abiBridge: %.self, abi: (count: %, start: %))\n",
721745
get_swift_name(param),
722-
bind<write_consume_type>(param.type, param_name, false));
746+
bind<write_type>(*param.type, write_type_params::swift),
747+
bind_bridge_fullname(*param.type),
748+
count_param_name,
749+
array_param_name);
723750
}
724751
else
725752
{
726-
w.write("let %: % = %\n",
753+
w.write("let %: [%] = .from(abi: (count: %, start: %))\n",
727754
get_swift_name(param),
728755
bind<write_type>(*param.type, write_type_params::swift),
729-
bind<write_consume_type>(param.type, param_name, false));
756+
count_param_name,
757+
array_param_name);
730758
}
759+
++param_number;
731760
}
732761
else
733762
{
734-
assert(!param.in());
735-
assert(param.out());
736-
w.write("var %: %%\n",
763+
w.write("let %: % = %\n",
737764
get_swift_name(param),
738765
bind<write_type>(*param.type, write_type_params::swift),
739-
bind<write_default_init_assignment>(*param.type, projection_layer::swift));
766+
bind<write_consume_type>(param.type, param_name, false));
740767
}
741768
}
769+
else
770+
{
771+
assert(!param.in());
772+
assert(param.out());
773+
w.write("var %: %%\n",
774+
get_swift_name(param),
775+
bind<write_type>(*param.type, write_type_params::swift),
776+
bind<write_default_init_assignment>(*param.type, projection_layer::swift));
777+
}
742778
++param_number;
743779
}
744780
}
@@ -1628,7 +1664,21 @@ vtable);
16281664

16291665
if (param.in())
16301666
{
1631-
if (category == param_category::string_type)
1667+
if (param.is_array())
1668+
{
1669+
if (is_reference_type(param.type))
1670+
{
1671+
w.write("try %.toABI(abiBridge: %.self) { (count, %) in\n", param_name, bind_bridge_name(*param.type), local_param_name);
1672+
}
1673+
else
1674+
{
1675+
w.write("try %.toABI { (count, %) in\n", param_name, local_param_name);
1676+
}
1677+
1678+
guard.push_indent();
1679+
guard.push("}\n");
1680+
}
1681+
else if (category == param_category::string_type)
16321682
{
16331683
w.write("let % = try! HString(%)\n",
16341684
local_param_name,
@@ -2418,7 +2468,7 @@ public init<Composable: ComposableImpl>(
24182468
}));
24192469

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

27382788
// assigns return or out parameters in vtable methods
2739-
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)
2789+
template<typename T>
2790+
static void do_write_abi_val_assignment(writer& w, T const& return_type, std::string_view return_param_name)
27402791
{
2792+
auto type = return_type.type;
2793+
auto param_name = get_swift_member_name(return_type.name);
27412794
TypeDef signature_type{};
27422795
auto category = get_category(type, &signature_type);
27432796

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

27692822
w.write("%?.initialize(to: %)\n",
27702823
return_param_name,
2771-
bind<write_convert_to_abi_arg>(param_name, type, true)
2824+
bind([&](writer& w) {
2825+
write_convert_to_abi_arg(w, return_type);
2826+
})
27722827
);
27732828
}
27742829

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

27892844
if (signature.return_type)
27902845
{
27912846
auto return_param_name = "$" + std::to_string(signature.params.size() + 1);
2792-
do_write_abi_val_assignment(w, signature.return_type.value().type, signature.return_type.value().name, return_param_name);
2847+
do_write_abi_val_assignment(w, signature.return_type.value(), return_param_name);
27932848
}
27942849
}
27952850

0 commit comments

Comments
 (0)