Skip to content

Commit

Permalink
have winrtclass also use the bridge pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenbrix committed Dec 17, 2024
1 parent 884061c commit c1a4ea0
Show file tree
Hide file tree
Showing 25 changed files with 756 additions and 565 deletions.
6 changes: 6 additions & 0 deletions swiftwinrt/Resources/Support/Aggregation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public protocol ComposableImpl<Class> : AbiInterfaceBridge where SwiftABI: IInsp
static func makeAbi() -> CABI
}

@_spi(WinRTInternal)
public protocol ComposableBridge<Class>: AbiBridge {
associatedtype Class: WinRTClass
associatedtype Composable: ComposableImpl<Class>
}

// At a high level, aggregation simply requires the WinRT object to have a pointer back to the Swift world, so that it can call
// overridable methods on the class. This Swift pointer is given to the WinRT object during construction. The construction of the
// WinRT object returns us two different pointers:
Expand Down
9 changes: 6 additions & 3 deletions swiftwinrt/Resources/Support/WinRTWrapperBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ public protocol AbiInterface {
public protocol AbiBridge {
associatedtype CABI
associatedtype SwiftProjection
static func makeAbi() -> CABI
static func from(abi: ComPtr<CABI>?) -> SwiftProjection?
}

public protocol ReferenceBridge : AbiBridge, HasIID {
public protocol SwiftImplementableBridge : AbiBridge {
static func makeAbi() -> CABI
}

public protocol ReferenceBridge : SwiftImplementableBridge, HasIID {
}

public protocol AbiInterfaceBridge : AbiBridge & AbiInterface {
public protocol AbiInterfaceBridge : SwiftImplementableBridge & AbiInterface {
}

public protocol AbiInterfaceImpl<Bridge> {
Expand Down
119 changes: 69 additions & 50 deletions swiftwinrt/code_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ namespace swiftwinrt
if (composableFactory)
{
if (params.size() > 0) written_params.append(", ");
written_params.append(w.write_temp("_ baseInterface: UnsealedWinRTClassWrapper<%.Composable>?, _ innerInterface: inout %.IInspectable?", classType, w.support));
written_params.append(w.write_temp("_ baseInterface: UnsealedWinRTClassWrapper<%.Composable>?, _ innerInterface: inout %.IInspectable?", bind_bridge_name(*classType), w.support));
}

w.write("% func %(%) throws% {\n",
Expand Down Expand Up @@ -2015,12 +2015,12 @@ public init<Composable: ComposableImpl>(
{
if (type.base_class)
{
w.write("super.init(composing: Self.Composable.self) { baseInterface, innerInterface in \n");
w.write("super.init(composing: %.Composable.self) { baseInterface, innerInterface in \n", bind_bridge_name(type));
}
else
{
w.write("super.init()\n");
w.write("MakeComposed(composing: Self.Composable.self, self) { baseInterface, innerInterface in \n");
w.write("MakeComposed(composing: %.Composable.self, self) { baseInterface, innerInterface in \n", bind_bridge_name(type));
}
w.write(" try! Self.%.%(%)\n",
get_swift_name(factory_info),
Expand All @@ -2034,30 +2034,76 @@ public init<Composable: ComposableImpl>(
}
}

static void write_default_constructor_declarations(writer& w, class_type const& type, metadata_type const& default_interface)
static void write_composable_impl(writer& w, class_type const& parent, metadata_type const& overrides, bool compose);
static void write_class_bridge(writer& w, class_type const& type)
{
auto [ns, name] = get_type_namespace_and_name(default_interface);
auto base_class = type.base_class;

// We unwrap composable types to try and get to any derived type.
// If not composable, then create a new instance
w.write("@_spi(WinRTInternal)\n");
w.write("public static func from(abi: ComPtr<%>?) -> %? {\n",
bind_type_mangled(default_interface), type);
if (auto default_interface = type.default_interface)
{
auto indent = w.push_indent();
w.write("guard let abi = abi else { return nil }\n");
if (type.is_composable())
{
w.write("return UnsealedWinRTClassWrapper<Composable>.unwrapFrom(base: abi)\n");
}
else
const bool composable = type.is_composable();
w.write("@_spi(WinRTInternal)\n");
w.write("public enum %: % {\n", bind_bridge_name(type), composable ? "ComposableBridge" : "AbiBridge");
{
w.write("return .init(fromAbi: %.IInspectable(abi))\n", w.support);
auto indent = w.push_indent();
w.write("public typealias Swift = %\n", type.swift_type_name());
w.write("public typealias CABI = %\n", bind_type_mangled(default_interface));
// We unwrap composable types to try and get to any derived type.
// If not composable, then create a new instance
w.write("public static func from(abi: ComPtr<%>?) -> %? {\n",
bind_type_mangled(default_interface), type);
{
auto indent = w.push_indent();
w.write("guard let abi = abi else { return nil }\n");
if (type.is_composable())
{
w.write("return UnsealedWinRTClassWrapper<Composable>.unwrapFrom(base: abi)\n");
}
else
{
w.write("return .init(fromAbi: %.IInspectable(abi))\n", w.support);
}
}
w.write("}\n");

if (composable)
{
bool has_overrides = false;
for (const auto& [interface_name, info] : type.required_interfaces)
{
if (!info.overridable || interface_name.empty() || !can_write(w, info.type)) { continue; }

// Generate definitions for how to compose overloads and create wrappers of this type.
if (!info.base)
{
// the very first override is the one we use for composing the class and can respond to QI
// calls for all the other overloads
write_composable_impl(w, type, *info.type, !has_overrides);
has_overrides = true;
}
else if (info.base && !has_overrides)
{
// This unsealed class doesn't have an overridable interface of it's own, so use the first base
// interface we come across for the composable implementation. This is used by the factory method
// when we are creating an aggregated type and enables the app to override the base class methods
// on this type
const bool compose = true;
write_composable_impl(w, type, *info.type, compose);
has_overrides = true;
}
}

if (!has_overrides)
{
write_composable_impl(w, type, *default_interface, true);
}
}
}
w.write("}\n\n");
}
w.write("}\n\n");
}

static void write_default_constructor_declarations(writer& w, class_type const& type, metadata_type const& default_interface)
{
auto base_class = type.base_class;
w.write("@_spi(WinRTInternal)\n");
w.write("%public init(fromAbi: %.IInspectable) {\n",
base_class ? "override " : "",
Expand Down Expand Up @@ -2325,7 +2371,7 @@ public init<Composable: ComposableImpl>(
bool use_iinspectable_vtable = type_name(overrides) == type_name(*default_interface);

auto format = R"(^@_spi(WinRTInternal)
public enum % : ComposableImpl {
public enum % : ComposableImpl {
public typealias CABI = %
public typealias SwiftABI = %
public typealias Class = %
Expand Down Expand Up @@ -2561,7 +2607,6 @@ override % func _getABI<T>() -> UnsafeMutablePointer<T>? {
}
}

bool has_overrides = false;
bool has_collection_conformance = false;
std::vector<std::string> interfaces_to_release;
for (const auto& [interface_name, info] : type.required_interfaces)
Expand All @@ -2587,32 +2632,6 @@ override % func _getABI<T>() -> UnsafeMutablePointer<T>? {
interfaces_to_release.push_back(get_swift_name(info));
write_interface_impl_members(w, info, /* type_definition: */ type);
}

// Generate definitions for how to compose overloads and create wrappers of this type.
if (info.overridable && !info.base)
{
// the very first override is the one we use for composing the class and can respond to QI
// calls for all the other overloads
const bool compose = !has_overrides;
write_composable_impl(w, type, *info.type, compose);
has_overrides = true;
}
else if (info.overridable && info.base && !has_overrides)
{
// This unsealed class doesn't have an overridable interface of it's own, so use the first base
// interface we come across for the composable implementation. This is used by the factory method
// when we are creating an aggregated type and enables the app to override the base class methods
// on this type
const bool compose = true;
write_composable_impl(w, type, *info.type, compose);
has_overrides = true;
}

}

if (composable && !has_overrides && default_interface)
{
write_composable_impl(w, type, *default_interface, true);
}

if (default_interface)
Expand Down Expand Up @@ -2933,7 +2952,7 @@ override % func _getABI<T>() -> UnsafeMutablePointer<T>? {
{
w.write("internal typealias % = UnsealedWinRTClassWrapper<%.%>\n",
bind_wrapper_name(overrides.type),
get_full_swift_type_name(w, type),
bind_bridge_fullname(type),
overrides.type
);
w.write("internal static var %VTable: %Vtbl = .init(\n",
Expand Down
2 changes: 1 addition & 1 deletion swiftwinrt/code_writers/common_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ namespace swiftwinrt
auto ptrVal = isOut ? std::string(name) : w.write_temp("ComPtr(%)", name);
if (is_class(type))
{
w.write(".from(abi: %)", ptrVal);
w.write("%.from(abi: %)", bind_bridge_fullname(*type), ptrVal);
}
else
{
Expand Down
1 change: 1 addition & 0 deletions swiftwinrt/file_writers.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ namespace swiftwinrt
auto impl_names = w.push_impl_names(true);
w.write("%", w.filter.bind_each<write_interface_impl>(members.interfaces));
w.write("%", w.filter.bind_each<write_delegate_implementation>(members.delegates));
w.write("%", w.filter.bind_each<write_class_bridge>(members.classes));
}
w.swap();
write_preamble(w, /* swift_code: */ true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,7 @@ public enum __ABI_Windows_Foundation {
try CHECKED(pThis.pointee.lpVtbl.pointee.get_QueryParsed(pThis, &ppWwwFormUrlDecoderAbi))
}
}
return .from(abi: ppWwwFormUrlDecoder)
return __IMPL_Windows_Foundation.WwwFormUrlDecoderBridge.from(abi: ppWwwFormUrlDecoder)
}

public func get_RawUri() throws -> String {
Expand Down Expand Up @@ -1154,7 +1154,7 @@ public enum __ABI_Windows_Foundation {
try CHECKED(pThis.pointee.lpVtbl.pointee.CombineUri(pThis, _relativeUri.get(), &instanceAbi))
}
}
return .from(abi: instance)
return __IMPL_Windows_Foundation.UriBridge.from(abi: instance)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,44 @@ public enum __IMPL_Windows_Foundation {
return handler
}
}
@_spi(WinRTInternal)
public enum DeferralBridge: AbiBridge {
public typealias Swift = Deferral
public typealias CABI = __x_ABI_CWindows_CFoundation_CIDeferral
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CIDeferral>?) -> Deferral? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

@_spi(WinRTInternal)
public enum MemoryBufferBridge: AbiBridge {
public typealias Swift = MemoryBuffer
public typealias CABI = __x_ABI_CWindows_CFoundation_CIMemoryBuffer
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CIMemoryBuffer>?) -> MemoryBuffer? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

@_spi(WinRTInternal)
public enum UriBridge: AbiBridge {
public typealias Swift = Uri
public typealias CABI = __x_ABI_CWindows_CFoundation_CIUriRuntimeClass
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CIUriRuntimeClass>?) -> Uri? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

@_spi(WinRTInternal)
public enum WwwFormUrlDecoderBridge: AbiBridge {
public typealias Swift = WwwFormUrlDecoder
public typealias CABI = __x_ABI_CWindows_CFoundation_CIWwwFormUrlDecoderRuntimeClass
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CIWwwFormUrlDecoderRuntimeClass>?) -> WwwFormUrlDecoder? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,34 @@ public enum __IMPL_Windows_Foundation_Collections {

}

@_spi(WinRTInternal)
public enum PropertySetBridge: AbiBridge {
public typealias Swift = PropertySet
public typealias CABI = __x_ABI_CWindows_CFoundation_CCollections_CIPropertySet
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CCollections_CIPropertySet>?) -> PropertySet? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

@_spi(WinRTInternal)
public enum StringMapBridge: AbiBridge {
public typealias Swift = StringMap
public typealias CABI = __x_ABI_C__FIMap_2_HSTRING_HSTRING
public static func from(abi: ComPtr<__x_ABI_C__FIMap_2_HSTRING_HSTRING>?) -> StringMap? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

@_spi(WinRTInternal)
public enum ValueSetBridge: AbiBridge {
public typealias Swift = ValueSet
public typealias CABI = __x_ABI_CWindows_CFoundation_CCollections_CIPropertySet
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CCollections_CIPropertySet>?) -> ValueSet? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ public final class PropertySet : WinRTClass, IObservableMap, IMap, IIterable, IP
return super._getABI()
}

@_spi(WinRTInternal)
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CCollections_CIPropertySet>?) -> PropertySet? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}

@_spi(WinRTInternal)
public init(fromAbi: test_component.IInspectable) {
super.init(fromAbi)
Expand Down Expand Up @@ -120,12 +114,6 @@ public final class StringMap : WinRTClass, IMap, IIterable, IObservableMap {
return super._getABI()
}

@_spi(WinRTInternal)
public static func from(abi: ComPtr<__x_ABI_C__FIMap_2_HSTRING_HSTRING>?) -> StringMap? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}

@_spi(WinRTInternal)
public init(fromAbi: test_component.IInspectable) {
super.init(fromAbi)
Expand Down Expand Up @@ -217,12 +205,6 @@ public final class ValueSet : WinRTClass, IObservableMap, IMap, IIterable, IProp
return super._getABI()
}

@_spi(WinRTInternal)
public static func from(abi: ComPtr<__x_ABI_CWindows_CFoundation_CCollections_CIPropertySet>?) -> ValueSet? {
guard let abi = abi else { return nil }
return .init(fromAbi: test_component.IInspectable(abi))
}

@_spi(WinRTInternal)
public init(fromAbi: test_component.IInspectable) {
super.init(fromAbi)
Expand Down
Loading

0 comments on commit c1a4ea0

Please sign in to comment.