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

have winrtclass also use the bridge pattern #192

Merged
merged 2 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions swiftwinrt/Resources/Support/Aggregation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public protocol ComposableImpl<Class> : AbiInterfaceBridge where SwiftABI: IInsp
static func makeAbi() -> CABI
}

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

// 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: 68 additions & 51 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,75 @@ 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("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 SwiftProjection = %\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 @@ -2324,8 +2369,7 @@ public init<Composable: ComposableImpl>(

bool use_iinspectable_vtable = type_name(overrides) == type_name(*default_interface);

auto format = R"(^@_spi(WinRTInternal)
public enum % : ComposableImpl {
auto format = R"(public enum % : ComposableImpl {
public typealias CABI = %
public typealias SwiftABI = %
public typealias Class = %
Expand Down Expand Up @@ -2561,7 +2605,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 +2630,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 +2950,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,40 @@ public enum __IMPL_Windows_Foundation {
return handler
}
}
public enum DeferralBridge: AbiBridge {
public typealias SwiftProjection = 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))
}
}

public enum MemoryBufferBridge: AbiBridge {
public typealias SwiftProjection = 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))
}
}

public enum UriBridge: AbiBridge {
public typealias SwiftProjection = 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))
}
}

public enum WwwFormUrlDecoderBridge: AbiBridge {
public typealias SwiftProjection = 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,31 @@ public enum __IMPL_Windows_Foundation_Collections {

}

public enum PropertySetBridge: AbiBridge {
public typealias SwiftProjection = 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))
}
}

public enum StringMapBridge: AbiBridge {
public typealias SwiftProjection = 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))
}
}

public enum ValueSetBridge: AbiBridge {
public typealias SwiftProjection = 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