From c72958dd4b2030c22eeae328cae61367f6193fc5 Mon Sep 17 00:00:00 2001 From: Halil Durmus Date: Wed, 19 Jul 2023 10:59:53 +0300 Subject: [PATCH] feat: support (Uri, String) and (Object, Object?) key-value pairs in Map (#319) --- .../lib/src/collections/ikeyvaluepair.dart | 12 +- .../src/collections/ikeyvaluepair_part.dart | 111 +++++++++ .../lib/src/collections/imap.dart | 14 +- .../lib/src/collections/imap_part.dart | 227 ++++++++++++++++++ .../lib/src/collections/imapview.dart | 14 +- .../lib/src/collections/imapview_part.dart | 123 ++++++++++ .../lib/src/constants/generic_types.dart | 119 ++++----- .../winrtgen/lib/src/models/generic_type.dart | 87 ++++++- .../lib/src/models/type_arg_kind.dart | 150 ++++++++---- .../src/projections/generic_interface.dart | 32 ++- .../lib/src/projections/types/object.dart | 32 ++- .../lib/src/projections/types/uri.dart | 21 +- .../extensions/type_identifier_helpers.dart | 2 +- .../winrtgen/lib/src/utilities/helpers.dart | 16 ++ .../winrtgen/test/goldens/imap_part.golden | 227 ++++++++++++++++++ .../projections/generic_interface_test.dart | 61 ++++- .../type_identifier_helpers_test.dart | 2 +- 17 files changed, 1102 insertions(+), 148 deletions(-) diff --git a/packages/windows_foundation/lib/src/collections/ikeyvaluepair.dart b/packages/windows_foundation/lib/src/collections/ikeyvaluepair.dart index e97eb384..f757569f 100644 --- a/packages/windows_foundation/lib/src/collections/ikeyvaluepair.dart +++ b/packages/windows_foundation/lib/src/collections/ikeyvaluepair.dart @@ -23,8 +23,8 @@ abstract interface class IKeyValuePair extends IInspectable { /// Creates an instance of [IKeyValuePair] from the given [ptr]. /// - /// [K] must be of type `Guid`, `int`, `String`, or `WinRTEnum` (e.g. - /// `PedometerStepKind`). + /// [K] must be of type `Guid`, `int`, `Object`, `String`, `Uri`, or + /// `WinRTEnum` (e.g. `PedometerStepKind`). /// /// [V] must be of type `Object?`, `String`, `IInspectable?` (e.g. /// `IJsonValue?`), or `WinRTEnum` (e.g. `ChatMessageStatus`). @@ -130,6 +130,14 @@ abstract interface class IKeyValuePair extends IInspectable { creator: creator, enumKeyCreator: enumKeyCreator); } + if (K == Uri && V == String) { + return _IKeyValuePairUriString.fromPtr(ptr) as IKeyValuePair; + } + + if (K == Object && isNullableObjectType()) { + return _IKeyValuePairObjectObject.fromPtr(ptr) as IKeyValuePair; + } + throw UnsupportedError('Unsupported key-value pair: ($K, $V)'); } diff --git a/packages/windows_foundation/lib/src/collections/ikeyvaluepair_part.dart b/packages/windows_foundation/lib/src/collections/ikeyvaluepair_part.dart index 1dd2cf9d..201335ff 100644 --- a/packages/windows_foundation/lib/src/collections/ikeyvaluepair_part.dart +++ b/packages/windows_foundation/lib/src/collections/ikeyvaluepair_part.dart @@ -307,6 +307,63 @@ final class _IKeyValuePairInt64Inspectable extends IKeyValuePair { } } +final class _IKeyValuePairObjectObject extends IKeyValuePair { + _IKeyValuePairObjectObject.fromPtr(super.ptr); + + @override + Object get key { + final retValuePtr = calloc(); + + final hr = ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, + Pointer retValuePtr)>()(ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) { + free(retValuePtr); + throwWindowsException(hr); + } + + return IPropertyValue.fromPtr(retValuePtr).value as Object; + } + + @override + Object? get value { + final retValuePtr = calloc(); + + final hr = ptr.ref.vtable + .elementAt(7) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, + Pointer retValuePtr)>()(ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) { + free(retValuePtr); + throwWindowsException(hr); + } + + if (retValuePtr.isNull) { + free(retValuePtr); + return null; + } + + return IPropertyValue.fromPtr(retValuePtr).value; + } +} + final class _IKeyValuePairStringInspectable extends IKeyValuePair { _IKeyValuePairStringInspectable.fromPtr(super.ptr, {required this.creator}); @@ -840,6 +897,60 @@ final class _IKeyValuePairUint64Inspectable extends IKeyValuePair { } } +final class _IKeyValuePairUriString extends IKeyValuePair { + _IKeyValuePairUriString.fromPtr(super.ptr); + + @override + Uri get key { + final retValuePtr = calloc(); + + final hr = ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, + Pointer retValuePtr)>()(ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) { + free(retValuePtr); + throwWindowsException(hr); + } + + return retValuePtr.toWinRTUri().toDartUri(); + } + + @override + String get value { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(7) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, + Pointer retValuePtr)>()(ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.toDartString(); + } finally { + WindowsDeleteString(retValuePtr.value); + free(retValuePtr); + } + } +} + final class _IKeyValuePairWinRTEnumInspectable extends IKeyValuePair { _IKeyValuePairWinRTEnumInspectable.fromPtr(super.ptr, diff --git a/packages/windows_foundation/lib/src/collections/imap.dart b/packages/windows_foundation/lib/src/collections/imap.dart index 3caffd39..6dabb6a1 100644 --- a/packages/windows_foundation/lib/src/collections/imap.dart +++ b/packages/windows_foundation/lib/src/collections/imap.dart @@ -93,8 +93,8 @@ abstract interface class IMap extends IInspectable /// [iterableIid] must be the IID of the `IIterable>` /// interface (e.g. `'{fe2f3d47-5d47-5499-8374-430c7cda0204}'`). /// - /// [K] must be of type `Guid`, `int`, `String`, or `WinRTEnum` (e.g. - /// `PedometerStepKind`). + /// [K] must be of type `Guid`, `int`, `Object`, `String`, `Uri`, or + /// `WinRTEnum` (e.g. `PedometerStepKind`). /// /// [V] must be of type `Object?`, `String`, `IInspectable?` (e.g. /// `IJsonValue?`), or `WinRTEnum` (e.g. `ChatMessageStatus`). @@ -202,6 +202,16 @@ abstract interface class IMap extends IInspectable iterableIid: iterableIid); } + if (K == Uri && V == String) { + return _IMapUriString.fromPtr(ptr, iterableIid: iterableIid) + as IMap; + } + + if (K == Object && isNullableObjectType()) { + return _IMapObjectObject.fromPtr(ptr, iterableIid: iterableIid) + as IMap; + } + throw UnsupportedError('Unsupported key-value pair: ($K, $V)'); } diff --git a/packages/windows_foundation/lib/src/collections/imap_part.dart b/packages/windows_foundation/lib/src/collections/imap_part.dart index 42e785cc..ec346819 100644 --- a/packages/windows_foundation/lib/src/collections/imap_part.dart +++ b/packages/windows_foundation/lib/src/collections/imap_part.dart @@ -595,6 +595,119 @@ final class _IMapInt64Inspectable extends IMap { } } +final class _IMapObjectObject extends IMap { + _IMapObjectObject.fromPtr(super.ptr, {required super.iterableIid}); + + @override + Object? lookup(Object key) { + final retValuePtr = calloc(); + + final hr = + ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) { + free(retValuePtr); + throwWindowsException(hr); + } + + if (retValuePtr.isNull) { + free(retValuePtr); + return null; + } + + return IPropertyValue.fromPtr(retValuePtr).value; + } + + @override + bool hasKey(Object key) { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(8) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + bool insert(Object key, Object? value) { + final retValuePtr = calloc(); + + try { + final hr = + ptr.ref.vtable + .elementAt(10) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + VTablePointer value, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + VTablePointer value, Pointer retValuePtr)>()( + ptr.ref.lpVtbl, + key.intoBox().ptr.ref.lpVtbl, + value?.intoBox().ptr.ref.lpVtbl ?? nullptr, + retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + void remove(Object key) { + final hr = ptr.ref.vtable + .elementAt(11) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, VTablePointer key)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl); + + if (FAILED(hr)) throwWindowsException(hr); + } +} + final class _IMapStringInspectable extends IMap { _IMapStringInspectable.fromPtr(super.ptr, {required super.iterableIid, required this.creator}) @@ -1643,6 +1756,120 @@ final class _IMapUint64Inspectable extends IMap { } } +final class _IMapUriString extends IMap { + _IMapUriString.fromPtr(super.ptr, {required super.iterableIid}); + + @override + String lookup(Uri key) { + final retValuePtr = calloc(); + + try { + final hr = + ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.toDartString(); + } finally { + WindowsDeleteString(retValuePtr.value); + free(retValuePtr); + } + } + + @override + bool hasKey(Uri key) { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(8) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + bool insert(Uri key, String value) { + final retValuePtr = calloc(); + + try { + final valueHString = value.toHString(); + + final hr = + ptr.ref.vtable + .elementAt(10) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + IntPtr value, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + int value, Pointer retValuePtr)>()( + ptr.ref.lpVtbl, + key.toWinRTUri().ptr.ref.lpVtbl, + valueHString, + retValuePtr); + + WindowsDeleteString(valueHString); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + void remove(Uri key) { + final hr = ptr.ref.vtable + .elementAt(11) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, VTablePointer key)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl); + + if (FAILED(hr)) throwWindowsException(hr); + } +} + final class _IMapWinRTEnumInspectable extends IMap { _IMapWinRTEnumInspectable.fromPtr(super.ptr, {required super.iterableIid, diff --git a/packages/windows_foundation/lib/src/collections/imapview.dart b/packages/windows_foundation/lib/src/collections/imapview.dart index fe63bf7b..3c9d4ef7 100644 --- a/packages/windows_foundation/lib/src/collections/imapview.dart +++ b/packages/windows_foundation/lib/src/collections/imapview.dart @@ -51,8 +51,8 @@ abstract interface class IMapView extends IInspectable /// [iterableIid] must be the IID of the `IIterable>` /// interface (e.g. `'{dfabb6e1-0411-5a8f-aa87-354e7110f099}'`). /// - /// [K] must be of type `Guid`, `int`, `String`, or `WinRTEnum` (e.g. - /// `PedometerStepKind`). + /// [K] must be of type `Guid`, `int`, `Object`, `String`, `Uri`, or + /// `WinRTEnum` (e.g. `PedometerStepKind`). /// /// [V] must be of type `Object?`, `String`, `IInspectable?` (e.g. /// `IJsonValue?`), or `WinRTEnum` (e.g. `ChatMessageStatus`). @@ -162,6 +162,16 @@ abstract interface class IMapView extends IInspectable iterableIid: iterableIid); } + if (K == Uri && V == String) { + return _IMapViewUriString.fromPtr(ptr, iterableIid: iterableIid) + as IMapView; + } + + if (K == Object && isNullableObjectType()) { + return _IMapViewObjectObject.fromPtr(ptr, iterableIid: iterableIid) + as IMapView; + } + throw UnsupportedError('Unsupported key-value pair: ($K, $V)'); } diff --git a/packages/windows_foundation/lib/src/collections/imapview_part.dart b/packages/windows_foundation/lib/src/collections/imapview_part.dart index e3acec89..f8382291 100644 --- a/packages/windows_foundation/lib/src/collections/imapview_part.dart +++ b/packages/windows_foundation/lib/src/collections/imapview_part.dart @@ -339,6 +339,69 @@ final class _IMapViewInt64Inspectable extends IMapView { } } +final class _IMapViewObjectObject extends IMapView { + _IMapViewObjectObject.fromPtr(super.ptr, {required super.iterableIid}); + + @override + Object? lookup(Object key) { + final retValuePtr = calloc(); + + final hr = + ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) { + free(retValuePtr); + throwWindowsException(hr); + } + + if (retValuePtr.isNull) { + free(retValuePtr); + return null; + } + + return IPropertyValue.fromPtr(retValuePtr).value; + } + + @override + bool hasKey(Object key) { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(8) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } +} + final class _IMapViewStringInspectable extends IMapView { _IMapViewStringInspectable.fromPtr(super.ptr, {required super.iterableIid, required this.creator}) @@ -934,6 +997,66 @@ final class _IMapViewUint64Inspectable extends IMapView { } } +final class _IMapViewUriString extends IMapView { + _IMapViewUriString.fromPtr(super.ptr, {required super.iterableIid}); + + @override + String lookup(Uri key) { + final retValuePtr = calloc(); + + try { + final hr = + ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.toDartString(); + } finally { + WindowsDeleteString(retValuePtr.value); + free(retValuePtr); + } + } + + @override + bool hasKey(Uri key) { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(8) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } +} + final class _IMapViewWinRTEnumInspectable extends IMapView { _IMapViewWinRTEnumInspectable.fromPtr(super.ptr, {required super.iterableIid, diff --git a/packages/winrtgen/lib/src/constants/generic_types.dart b/packages/winrtgen/lib/src/constants/generic_types.dart index 2891edc9..5095d390 100644 --- a/packages/winrtgen/lib/src/constants/generic_types.dart +++ b/packages/winrtgen/lib/src/constants/generic_types.dart @@ -9,42 +9,61 @@ import '../models/models.dart'; /// Used to generate private concrete classes for the abstract WinRT generic /// classes. const genericTypes = [ - GenericTypeWithOneTypeArg( - 'Windows.Foundation.IAsyncOperation`1', _asyncOperationTypeArgKinds), - GenericTypeWithOneTypeArg( - 'Windows.Foundation.IReference`1', _referenceTypeArgKinds), - GenericTypeWithOneTypeArg( - 'Windows.Foundation.Collections.IIterator`1', _vectorTypeArgKinds), - GenericTypeWithTwoTypeArgs( - 'Windows.Foundation.Collections.IKeyValuePair`2', _mapTypeArgKindPairs), - GenericTypeWithTwoTypeArgs( - 'Windows.Foundation.Collections.IMap`2', _mapTypeArgKindPairs), - GenericTypeWithTwoTypeArgs( - 'Windows.Foundation.Collections.IMapView`2', _mapTypeArgKindPairs), - GenericTypeWithOneTypeArg( - 'Windows.Foundation.Collections.IVector`1', _vectorTypeArgKinds), - GenericTypeWithOneTypeArg( - 'Windows.Foundation.Collections.IVectorView`1', _vectorTypeArgKinds), + iasyncOperation, iiterator, ikeyValuePair, imap, imapView, ireference, // + ivector, ivectorView ]; +/// The `IAsyncOperation` generic type. +const iasyncOperation = GenericTypeWithOneTypeArg( + 'Windows.Foundation.IAsyncOperation`1', _asyncOperationTypeArgKinds); + +/// The `IIterator` generic type. +const iiterator = GenericTypeWithOneTypeArg( + 'Windows.Foundation.Collections.IIterator`1', _vectorTypeArgKinds); + +/// The `IKeyValuePair` generic type. +const ikeyValuePair = GenericTypeWithTwoTypeArgs( + 'Windows.Foundation.Collections.IKeyValuePair`2', _mapTypeArgKindPairs); + +/// The `IMap` generic type. +const imap = GenericTypeWithTwoTypeArgs( + 'Windows.Foundation.Collections.IMap`2', _mapTypeArgKindPairs); + +/// The `IMapView` generic type. +const imapView = GenericTypeWithTwoTypeArgs( + 'Windows.Foundation.Collections.IMapView`2', _mapTypeArgKindPairs); + +/// The `IReference` generic type. +const ireference = GenericTypeWithOneTypeArg( + 'Windows.Foundation.IReference`1', _referenceTypeArgKinds); + +/// The `IVector` generic type. +const ivector = GenericTypeWithOneTypeArg( + 'Windows.Foundation.Collections.IVector`1', _vectorTypeArgKinds); + +/// The `IVectorView` generic type. +const ivectorView = GenericTypeWithOneTypeArg( + 'Windows.Foundation.Collections.IVectorView`1', _vectorTypeArgKinds); + /// The type argument kinds for `IAsyncOperation`. -const _asyncOperationTypeArgKinds = [ +const _asyncOperationTypeArgKinds = { TypeArgKind.bool_, TypeArgKind.double, TypeArgKind.float, TypeArgKind.guid, // TypeArgKind.int16, TypeArgKind.int32, TypeArgKind.int64, // TypeArgKind.loadMoreItemsResult, TypeArgKind.nullableInspectable, // TypeArgKind.nullableObject, TypeArgKind.nullableUri, TypeArgKind.string, // TypeArgKind.uint8, TypeArgKind.uint16, TypeArgKind.uint32, // TypeArgKind.uint64, TypeArgKind.winrtEnum, TypeArgKind.winrtFlagsEnum -]; +}; /// The common type argument kind pairs for `IKeyValuePair`, `IMap`, and /// `IMapView`. -const _mapTypeArgKindPairs = <(TypeArgKind, TypeArgKind)>[ +const _mapTypeArgKindPairs = <(TypeArgKind, TypeArgKind)>{ (TypeArgKind.guid, TypeArgKind.nullableInspectable), (TypeArgKind.guid, TypeArgKind.nullableObject), (TypeArgKind.int16, TypeArgKind.nullableInspectable), (TypeArgKind.int32, TypeArgKind.nullableInspectable), (TypeArgKind.int64, TypeArgKind.nullableInspectable), + (TypeArgKind.object, TypeArgKind.nullableObject), (TypeArgKind.string, TypeArgKind.nullableInspectable), (TypeArgKind.string, TypeArgKind.nullableObject), (TypeArgKind.string, TypeArgKind.string), @@ -54,51 +73,37 @@ const _mapTypeArgKindPairs = <(TypeArgKind, TypeArgKind)>[ (TypeArgKind.uint16, TypeArgKind.nullableInspectable), (TypeArgKind.uint32, TypeArgKind.nullableInspectable), (TypeArgKind.uint64, TypeArgKind.nullableInspectable), + (TypeArgKind.uri, TypeArgKind.string), (TypeArgKind.winrtEnum, TypeArgKind.nullableInspectable), (TypeArgKind.winrtFlagsEnum, TypeArgKind.nullableInspectable) -]; +}; /// The type argument kinds for `IReference`. -const _referenceTypeArgKinds = [ - TypeArgKind.nullableBasicGeoposition, - TypeArgKind.nullableBool, - TypeArgKind.nullableColor, - TypeArgKind.nullableDateTime, - TypeArgKind.nullableDisplayPresentationRate, - TypeArgKind.nullableDouble, - TypeArgKind.nullableDuration, - TypeArgKind.nullableFloat, - TypeArgKind.nullableGuid, - TypeArgKind.nullableHolographicStereoTransform, - TypeArgKind.nullableInt16, - TypeArgKind.nullableInt32, - TypeArgKind.nullableInt64, - TypeArgKind.nullableMatrix4x4, - TypeArgKind.nullableMseTimeRange, - TypeArgKind.nullablePoint, - TypeArgKind.nullableQuaternion, - TypeArgKind.nullableRect, - TypeArgKind.nullableSize, - TypeArgKind.nullableSizeInt32, - TypeArgKind.nullableSpatialBoundingBox, - TypeArgKind.nullableSpatialBoundingFrustum, - TypeArgKind.nullableSpatialBoundingOrientedBox, - TypeArgKind.nullableSpatialRay, - TypeArgKind.nullableString, - TypeArgKind.nullableUint8, - TypeArgKind.nullableUint16, - TypeArgKind.nullableUint32, - TypeArgKind.nullableUint64, - TypeArgKind.nullableVector2, - TypeArgKind.nullableVector3, - TypeArgKind.nullableWhiteBalanceGain, - TypeArgKind.winrtEnum, +const _referenceTypeArgKinds = { + TypeArgKind.nullableBasicGeoposition, TypeArgKind.nullableBool, // + TypeArgKind.nullableColor, TypeArgKind.nullableDateTime, // + TypeArgKind.nullableDisplayPresentationRate, TypeArgKind.nullableDouble, // + TypeArgKind.nullableDuration, TypeArgKind.nullableFloat, // + TypeArgKind.nullableGuid, TypeArgKind.nullableHolographicStereoTransform, // + TypeArgKind.nullableInt16, TypeArgKind.nullableInt32, // + TypeArgKind.nullableInt64, TypeArgKind.nullableMatrix4x4, // + TypeArgKind.nullableMseTimeRange, TypeArgKind.nullablePoint, // + TypeArgKind.nullableQuaternion, TypeArgKind.nullableRect, // + TypeArgKind.nullableSize, TypeArgKind.nullableSizeInt32, // + TypeArgKind.nullableSpatialBoundingBox, // + TypeArgKind.nullableSpatialBoundingFrustum, // + TypeArgKind.nullableSpatialBoundingOrientedBox, // + TypeArgKind.nullableSpatialRay, TypeArgKind.nullableString, // + TypeArgKind.nullableUint8, TypeArgKind.nullableUint16, // + TypeArgKind.nullableUint32, TypeArgKind.nullableUint64, // + TypeArgKind.nullableVector2, TypeArgKind.nullableVector3, // + TypeArgKind.nullableWhiteBalanceGain, TypeArgKind.winrtEnum, // TypeArgKind.winrtFlagsEnum -]; +}; /// The common type argument kinds for `IIterator`, `IVector`, and /// `IVectorView`. -const _vectorTypeArgKinds = [ +const _vectorTypeArgKinds = { TypeArgKind.accessListEntry, TypeArgKind.backgroundTransferFileRange, // TypeArgKind.basicGeoposition, TypeArgKind.bool_, TypeArgKind.color, // TypeArgKind.dateTime, TypeArgKind.double, TypeArgKind.duration, // @@ -113,4 +118,4 @@ const _vectorTypeArgKinds = [ TypeArgKind.textRange, TypeArgKind.textSegment, TypeArgKind.uint8, // TypeArgKind.uint16, TypeArgKind.uint32, TypeArgKind.uint64, // TypeArgKind.windowId, TypeArgKind.winrtEnum, TypeArgKind.winrtFlagsEnum -]; +}; diff --git a/packages/winrtgen/lib/src/models/generic_type.dart b/packages/winrtgen/lib/src/models/generic_type.dart index b71150e4..9a6ec889 100644 --- a/packages/winrtgen/lib/src/models/generic_type.dart +++ b/packages/winrtgen/lib/src/models/generic_type.dart @@ -2,6 +2,8 @@ // All rights reserved. Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +import 'package:winmd/winmd.dart'; + import '../utilities/utilities.dart'; import 'type_arg_kind.dart'; @@ -14,25 +16,98 @@ sealed class GenericType { /// The short name of the type (e.g. `IReference`). String get shortName => lastComponent(stripGenerics(fullyQualifiedType)); + + @override + String toString() => shortName; } /// Represents a WinRT generic type with one type argument (e.g. /// Windows.Foundation.IAsyncOperation`1). final class GenericTypeWithOneTypeArg extends GenericType { - const GenericTypeWithOneTypeArg(super.fullyQualifiedType, this.typeArgs); + const GenericTypeWithOneTypeArg(super.fullyQualifiedType, this.typeArgKinds); - /// The type arguments for this generic type (e.g. `TypeArgKind.bool_`, + /// The [TypeArgKind]s for this generic type (e.g. `TypeArgKind.bool_`, /// `TypeArgKind.string`). - final List typeArgs; + final Set typeArgKinds; + + /// The [TypeArgKind]s for this generic type that are found in the Metadata. + Set get typeArgKindsInMetadata { + final typeArgKinds = {}; + + for (final Method(:returnType) in getAllMethodsInMetadata()) { + final Parameter(:isClassVariableType, :isGenericType) = returnType; + if (isClassVariableType) continue; + + final typeIdentifier = + returnType.typeIdentifier.name != fullyQualifiedType && isGenericType + ? dereferenceType(returnType.typeIdentifier) + : returnType.typeIdentifier; + + if (typeIdentifier.name == fullyQualifiedType) { + final typeArg = typeIdentifier.typeArg!; + if (typeArg.isClassVariableType) continue; + + final isNullable = shortName == 'IReference' || + typeArg.isClassType || + typeArg.isGenericType || + typeArg.isObjectType; + final typeArgKind = + TypeArgKind.fromTypeIdentifier(typeArg, isNullable: isNullable); + typeArgKinds.add(typeArgKind); + } + } + + return typeArgKinds; + } } /// Represents a WinRT generic type with two type arguments (e.g. /// Windows.Foundation.Collections.IMap`2). final class GenericTypeWithTwoTypeArgs extends GenericType { - const GenericTypeWithTwoTypeArgs(super.fullyQualifiedType, this.typeArgs); + const GenericTypeWithTwoTypeArgs( + super.fullyQualifiedType, this.typeArgKindPairs); - /// The type argument pairs for this generic type (e.g. + /// The [TypeArgKind] pairs for this generic type (e.g. /// `(TypeArgKind.string, TypeArgKind.string)`, /// `(TypeArgKind.string, TypeArgKind.nullableObject)`). - final List<(TypeArgKind, TypeArgKind)> typeArgs; + final Set<(TypeArgKind, TypeArgKind)> typeArgKindPairs; + + /// The [TypeArgKind] pairs for this generic type that are found in the + /// Metadata. + Set<(TypeArgKind, TypeArgKind)> get typeArgKindPairsInMetadata { + final typeArgKindPairs = <(TypeArgKind, TypeArgKind)>{}; + + for (final method in getAllMethodsInMetadata()) { + final paramsAndReturnType = [...method.parameters, method.returnType]; + + for (final param in paramsAndReturnType) { + if (param.isClassVariableType) continue; + + final typeIdentifier = + param.typeIdentifier.name != fullyQualifiedType && + (param.isGenericType || param.isReferenceType) + ? dereferenceType(param.typeIdentifier) + : param.typeIdentifier; + + if (typeIdentifier.name == fullyQualifiedType) { + final [typeArg1, typeArg2] = typeIdentifier.typeArgs; + if (typeArg1.isClassVariableType || typeArg2.isClassVariableType) { + continue; + } + + final typeArg1IsNullable = false; + final typeArgKind1 = TypeArgKind.fromTypeIdentifier(typeArg1, + isNullable: typeArg1IsNullable); + final typeArg2IsNullable = typeArg2.isClassType || + typeArg2.isGenericType || + typeArg2.isObjectType; + final typeArgKind2 = TypeArgKind.fromTypeIdentifier(typeArg2, + isNullable: typeArg2IsNullable); + typeArgKindPairs.add((typeArgKind1, typeArgKind2)); + } + } + } + + return typeArgKindPairs; + } } diff --git a/packages/winrtgen/lib/src/models/type_arg_kind.dart b/packages/winrtgen/lib/src/models/type_arg_kind.dart index f8a8b91a..7df1c663 100644 --- a/packages/winrtgen/lib/src/models/type_arg_kind.dart +++ b/packages/winrtgen/lib/src/models/type_arg_kind.dart @@ -96,6 +96,54 @@ enum TypeArgKind { orElse: () => throw ArgumentError.value( name, 'name', 'No enum value with that name')); + factory TypeArgKind.fromTypeIdentifier(TypeIdentifier typeIdentifier, + {bool isNullable = false}) { + final TypeIdentifier(:baseType, :name, :type) = typeIdentifier; + return switch (baseType) { + BaseType.booleanType => + isNullable ? TypeArgKind.nullableBool : TypeArgKind.bool_, + BaseType.classTypeModifier when name == 'Windows.Foundation.Uri' => + isNullable ? TypeArgKind.nullableUri : TypeArgKind.uri, + BaseType.classTypeModifier || + BaseType.genericTypeModifier => + isNullable ? TypeArgKind.nullableInspectable : TypeArgKind.inspectable, + BaseType.doubleType => + isNullable ? TypeArgKind.nullableDouble : TypeArgKind.double, + BaseType.floatType => + isNullable ? TypeArgKind.nullableFloat : TypeArgKind.float, + BaseType.int16Type => + isNullable ? TypeArgKind.nullableInt16 : TypeArgKind.int16, + BaseType.int32Type => + isNullable ? TypeArgKind.nullableInt32 : TypeArgKind.int32, + BaseType.int64Type => + isNullable ? TypeArgKind.nullableInt64 : TypeArgKind.int64, + BaseType.objectType => + isNullable ? TypeArgKind.nullableObject : TypeArgKind.object, + BaseType.stringType => + isNullable ? TypeArgKind.nullableString : TypeArgKind.string, + BaseType.uint8Type => + isNullable ? TypeArgKind.nullableUint8 : TypeArgKind.uint8, + BaseType.uint16Type => + isNullable ? TypeArgKind.nullableUint16 : TypeArgKind.uint16, + BaseType.uint32Type => + isNullable ? TypeArgKind.nullableUint32 : TypeArgKind.uint32, + BaseType.uint64Type => + isNullable ? TypeArgKind.nullableUint64 : TypeArgKind.uint64, + BaseType.valueTypeModifier when type?.isEnum ?? false => + isNullable ? TypeArgKind.winrtEnum : TypeArgKind.winrtFlagsEnum, + BaseType.valueTypeModifier => switch (name) { + 'System.Guid' => + isNullable ? TypeArgKind.nullableGuid : TypeArgKind.guid, + 'Windows.Foundation.TimeSpan' => + isNullable ? TypeArgKind.nullableDuration : TypeArgKind.duration, + _ => TypeArgKind.from( + isNullable ? nullable(lastComponent(name)) : lastComponent(name)) + }, + _ => + throw WinRTGenException('Unsupported TypeIdentifier: $typeIdentifier') + }; + } + /// Whether this is [TypeArgKind.double] or [TypeArgKind.float]. bool get isDouble => switch (this) { TypeArgKind.double || TypeArgKind.float => true, @@ -132,37 +180,36 @@ enum TypeArgKind { /// Returns the appropriate [TypeIdentifier] for this [TypeArgKind]. TypeIdentifier get typeIdentifier => switch (this) { - TypeArgKind.accessListEntry => _createClassTypeIdentifier( - 'Windows.Storage.AccessCache.AccessListEntry'), - TypeArgKind.backgroundTransferFileRange => _createClassTypeIdentifier( - 'Windows.Networking.BackgroundTransfer.BackgroundTransferFileRange'), + TypeArgKind.accessListEntry => + 'Windows.Storage.AccessCache.AccessListEntry'.typeIdentifier, + TypeArgKind.backgroundTransferFileRange => + 'Windows.Networking.BackgroundTransfer.BackgroundTransferFileRange' + .typeIdentifier, TypeArgKind.basicGeoposition || TypeArgKind.nullableBasicGeoposition => - _createClassTypeIdentifier( - 'Windows.Devices.Geolocation.BasicGeoposition'), + 'Windows.Devices.Geolocation.BasicGeoposition'.typeIdentifier, TypeArgKind.bool_ || TypeArgKind.nullableBool => const TypeIdentifier(BaseType.booleanType), TypeArgKind.color || TypeArgKind.nullableColor => - _createClassTypeIdentifier('Windows.UI.Color'), + 'Windows.UI.Color'.typeIdentifier, TypeArgKind.dateTime || TypeArgKind.nullableDateTime => - _createClassTypeIdentifier('Windows.Foundation.DateTime'), + 'Windows.Foundation.DateTime'.typeIdentifier, TypeArgKind.nullableDisplayPresentationRate => - _createClassTypeIdentifier( - 'Windows.Devices.Display.Core.DisplayPresentationRate'), + 'Windows.Devices.Display.Core.DisplayPresentationRate'.typeIdentifier, TypeArgKind.double || TypeArgKind.nullableDouble => const TypeIdentifier(BaseType.doubleType), TypeArgKind.duration || TypeArgKind.nullableDuration => - _createClassTypeIdentifier('Windows.Foundation.TimeSpan'), + 'Windows.Foundation.TimeSpan'.typeIdentifier, TypeArgKind.float || TypeArgKind.nullableFloat => const TypeIdentifier(BaseType.floatType), TypeArgKind.gpioChangeRecord => - _createClassTypeIdentifier('Windows.Devices.Gpio.GpioChangeRecord'), + 'Windows.Devices.Gpio.GpioChangeRecord'.typeIdentifier, TypeArgKind.guid || TypeArgKind.nullableGuid => const TypeIdentifier(BaseType.valueTypeModifier, name: 'System.Guid'), @@ -175,69 +222,67 @@ enum TypeArgKind { TypeArgKind.int64 || TypeArgKind.nullableInt64 => const TypeIdentifier(BaseType.int64Type), - TypeArgKind.loadMoreItemsResult => _createClassTypeIdentifier( - 'Windows.UI.Xaml.Data.LoadMoreItemsResult'), + TypeArgKind.loadMoreItemsResult => + 'Windows.UI.Xaml.Data.LoadMoreItemsResult'.typeIdentifier, TypeArgKind.mediaTimeRange => - _createClassTypeIdentifier('Windows.Media.MediaTimeRange'), + 'Windows.Media.MediaTimeRange'.typeIdentifier, TypeArgKind.mseTimeRange || TypeArgKind.nullableMseTimeRange => - _createClassTypeIdentifier('Windows.Media.Core.MseTimeRange'), + 'Windows.Media.Core.MseTimeRange'.typeIdentifier, TypeArgKind.nitRange => - _createClassTypeIdentifier('Windows.Graphics.Display.NitRange'), + 'Windows.Graphics.Display.NitRange'.typeIdentifier, TypeArgKind.nullableHolographicStereoTransform => - _createClassTypeIdentifier( - 'Windows.Graphics.Holographic.HolographicStereoTransform'), + 'Windows.Graphics.Holographic.HolographicStereoTransform' + .typeIdentifier, TypeArgKind.nullableMatrix4x4 => - _createClassTypeIdentifier('Windows.Foundation.Numerics.Matrix4x4'), + 'Windows.Foundation.Numerics.Matrix4x4'.typeIdentifier, TypeArgKind.nullableQuaternion => - _createClassTypeIdentifier('Windows.Foundation.Numerics.Quaternion'), + 'Windows.Foundation.Numerics.Quaternion'.typeIdentifier, TypeArgKind.nullableSizeInt32 => - _createClassTypeIdentifier('Windows.Graphics.SizeInt32'), - TypeArgKind.nullableSpatialBoundingBox => _createClassTypeIdentifier( - 'Windows.Perception.Spatial.SpatialBoundingBox'), + 'Windows.Graphics.SizeInt32'.typeIdentifier, + TypeArgKind.nullableSpatialBoundingBox => + 'Windows.Perception.Spatial.SpatialBoundingBox'.typeIdentifier, TypeArgKind.nullableSpatialBoundingFrustum => - _createClassTypeIdentifier( - 'Windows.Perception.Spatial.SpatialBoundingFrustum'), + 'Windows.Perception.Spatial.SpatialBoundingFrustum'.typeIdentifier, TypeArgKind.nullableSpatialBoundingOrientedBox => - _createClassTypeIdentifier( - 'Windows.Perception.Spatial.SpatialBoundingOrientedBox'), + 'Windows.Perception.Spatial.SpatialBoundingOrientedBox' + .typeIdentifier, TypeArgKind.nullableSpatialRay => - _createClassTypeIdentifier('Windows.Perception.Spatial.SpatialRay'), + 'Windows.Perception.Spatial.SpatialRay'.typeIdentifier, TypeArgKind.nullableVector2 => - _createClassTypeIdentifier('Windows.Foundation.Numerics.Vector2'), + 'Windows.Foundation.Numerics.Vector2'.typeIdentifier, TypeArgKind.nullableVector3 => - _createClassTypeIdentifier('Windows.Foundation.Numerics.Vector3'), + 'Windows.Foundation.Numerics.Vector3'.typeIdentifier, TypeArgKind.nullableWhiteBalanceGain => - _createClassTypeIdentifier('Windows.Media.Capture.WhiteBalanceGain'), + 'Windows.Media.Capture.WhiteBalanceGain'.typeIdentifier, TypeArgKind.object || TypeArgKind.nullableObject => const TypeIdentifier(BaseType.objectType), TypeArgKind.point || TypeArgKind.nullablePoint => - _createClassTypeIdentifier('Windows.Foundation.Point'), - TypeArgKind.pointerDeviceUsage => _createClassTypeIdentifier( - 'Windows.Devices.Input.PointerDeviceUsage'), + 'Windows.Foundation.Point'.typeIdentifier, + TypeArgKind.pointerDeviceUsage => + 'Windows.Devices.Input.PointerDeviceUsage'.typeIdentifier, TypeArgKind.rect || TypeArgKind.nullableRect => - _createClassTypeIdentifier('Windows.Foundation.Rect'), - TypeArgKind.rectInt32 => - _createClassTypeIdentifier('Windows.Graphics.RectInt32'), + 'Windows.Foundation.Rect'.typeIdentifier, + TypeArgKind.rectInt32 => 'Windows.Graphics.RectInt32'.typeIdentifier, TypeArgKind.size || TypeArgKind.nullableSize => - _createClassTypeIdentifier('Windows.Foundation.Size'), - TypeArgKind.sizeUint32 => _createClassTypeIdentifier( - 'Windows.Devices.PointOfService.SizeUInt32'), + 'Windows.Foundation.Size'.typeIdentifier, + TypeArgKind.sizeUint32 => + 'Windows.Devices.PointOfService.SizeUInt32'.typeIdentifier, TypeArgKind.sortEntry => - _createClassTypeIdentifier('Windows.Storage.Search.SortEntry'), - TypeArgKind.storePackageUpdateStatus => _createClassTypeIdentifier( - 'Windows.Services.Store.StorePackageUpdateStatus'), + 'Windows.Storage.Search.SortEntry'.typeIdentifier, + TypeArgKind.storePackageUpdateStatus => + 'Windows.Services.Store.StorePackageUpdateStatus'.typeIdentifier, TypeArgKind.string || TypeArgKind.nullableString => const TypeIdentifier(BaseType.stringType), TypeArgKind.textRange => - _createClassTypeIdentifier('Windows.UI.Xaml.Documents.TextRange'), + 'Windows.UI.Xaml.Documents.TextRange'.typeIdentifier, TypeArgKind.textSegment => - _createClassTypeIdentifier('Windows.Data.Text.TextSegment'), + 'Windows.Data.Text.TextSegment'.typeIdentifier, TypeArgKind.uint8 || TypeArgKind.nullableUint8 => const TypeIdentifier(BaseType.uint8Type), @@ -252,13 +297,14 @@ enum TypeArgKind { const TypeIdentifier(BaseType.uint64Type), TypeArgKind.uri || TypeArgKind.nullableUri => - _createClassTypeIdentifier('Windows.Foundation.Uri'), - TypeArgKind.windowId => - _createClassTypeIdentifier('Windows.UI.WindowId'), + 'Windows.Foundation.Uri'.typeIdentifier, + TypeArgKind.windowId => 'Windows.UI.WindowId'.typeIdentifier, _ => throw WinRTGenException('Unsupported TypeArgKind: $this'), }; } -TypeIdentifier _createClassTypeIdentifier(String type) => - TypeIdentifier(BaseType.classTypeModifier, - name: type, type: getMetadataForType(type)); +extension on String { + TypeIdentifier get typeIdentifier => + TypeIdentifier(BaseType.classTypeModifier, + name: this, type: getMetadataForType(this)); +} diff --git a/packages/winrtgen/lib/src/projections/generic_interface.dart b/packages/winrtgen/lib/src/projections/generic_interface.dart index 6796bd45..debe7f41 100644 --- a/packages/winrtgen/lib/src/projections/generic_interface.dart +++ b/packages/winrtgen/lib/src/projections/generic_interface.dart @@ -25,15 +25,18 @@ final class GenericInterfacePartFileProjection { List get projections => _projections ??= _cacheProjections(); - List _cacheProjections() => switch (genericType) { - GenericTypeWithOneTypeArg(:final typeArgs) => typeArgs.map((typeArg) => - GenericInterfaceProjection.from( - genericType.fullyQualifiedType, typeArg)), - GenericTypeWithTwoTypeArgs(:final typeArgs) => typeArgs.map( - (typeArgs) => GenericInterfaceProjection.from( - genericType.fullyQualifiedType, typeArgs.$1, typeArgs.$2)), - } - .toList(); + List _cacheProjections() { + final fullyQualifiedType = genericType.fullyQualifiedType; + return switch (genericType) { + GenericTypeWithOneTypeArg(:final typeArgKinds) => typeArgKinds.map( + (typeArgKind) => + GenericInterfaceProjection.from(fullyQualifiedType, typeArgKind)), + GenericTypeWithTwoTypeArgs(:final typeArgKindPairs) => typeArgKindPairs + .map((typeArgKindPair) => GenericInterfaceProjection.from( + fullyQualifiedType, typeArgKindPair.$1, typeArgKindPair.$2)), + } + .toList(); + } @override String toString() => ''' @@ -220,7 +223,8 @@ final class GenericInterfaceProjection extends InterfaceProjection { method.returnType.typeIdentifier.copyWith(name: arg.name); } else { // Otherwise, replace TypeIdentifier with an appropriate one for arg. - method.returnType.typeIdentifier = arg.typeIdentifier; + method.returnType.typeIdentifier = arg.typeIdentifier + .copyWith(genericParameterSequence: genericParamSequence); } } @@ -234,7 +238,8 @@ final class GenericInterfaceProjection extends InterfaceProjection { param.typeIdentifier = param.typeIdentifier.copyWith(name: arg.name); method.parameters[paramIndex] = param; } else { - param.typeIdentifier = arg.typeIdentifier; + param.typeIdentifier = arg.typeIdentifier + .copyWith(genericParameterSequence: genericParamSequence); method.parameters[paramIndex] = param; } } @@ -250,8 +255,9 @@ final class GenericInterfaceProjection extends InterfaceProjection { .copyWith(typeArg: typeArg.copyWith(name: arg.name)); method.parameters[paramIndex] = param; } else { - param.typeIdentifier = - param.typeIdentifier.copyWith(typeArg: arg.typeIdentifier); + param.typeIdentifier = param.typeIdentifier.copyWith( + typeArg: arg.typeIdentifier + .copyWith(genericParameterSequence: genericParamSequence)); method.parameters[paramIndex] = param; } } diff --git a/packages/winrtgen/lib/src/projections/types/object.dart b/packages/winrtgen/lib/src/projections/types/object.dart index d9a81947..037b0325 100644 --- a/packages/winrtgen/lib/src/projections/types/object.dart +++ b/packages/winrtgen/lib/src/projections/types/object.dart @@ -17,22 +17,34 @@ final class ObjectParameterProjection extends ParameterProjection { @override bool get isNullable { + final parent = method.parent; + + // The key type arguments of IKeyValuePair, IMap, + // and IMapView cannot be null. + if (parent.genericParams.length == 2 && + (parent.name.endsWith('IKeyValuePair`2') || + parent.isCollectionObject)) { + return switch (parameter.typeIdentifier.genericParameterSequence) { + 0 => false, + _ => true + }; + } + if (isReturnParam) { // Constructors cannot return null. - if (method.parent.isFactoryInterface) return false; + if (parent.isFactoryInterface) return false; // Methods that return collection interfaces cannot return null. if (!method.isGetProperty && - typeProjection.typeIdentifier.isCollectionObject) { + parameter.typeIdentifier.isCollectionObject) { return false; } // IIterable.First() cannot return null. - if (method.name == 'First' && method.parent.isCollectionObject) { + if (method.name == 'First' && parent.isCollectionObject) { return false; } - // if (isObjectType && isMethodFromPropertyValueStatics) return false; } @@ -49,7 +61,6 @@ final class ObjectParameterProjection extends ParameterProjection { _ => 'IPropertyValue' }; } - return 'Object?'; } return isNullable ? nullable(shortTypeName) : shortTypeName; @@ -71,7 +82,8 @@ final class ObjectParameterProjection extends ParameterProjection { }; } - return 'IPropertyValue.fromPtr($identifier).value'; + final cast = isNullable ? '' : ' as Object'; + return 'IPropertyValue.fromPtr($identifier).value$cast'; } if (type == 'Pointer') return identifier; @@ -89,7 +101,9 @@ final class ObjectParameterProjection extends ParameterProjection { @override String get toListInto => isObjectType - ? '$identifier[i]?.intoBox().ptr.ref.lpVtbl ?? nullptr' + ? isNullable + ? '$identifier[i]?.intoBox().ptr.ref.lpVtbl ?? nullptr' + : '$identifier[i].intoBox().ptr.ref.lpVtbl' : '$identifier[i].ptr.ref.lpVtbl'; // No deallocation is needed as Finalizer will handle it. @@ -115,7 +129,9 @@ final class ObjectParameterProjection extends ParameterProjection { if (isInParam) { if (typeProjection.isObjectType) { - return '$identifier?.intoBox().ptr.ref.lpVtbl ?? nullptr'; + return isNullable + ? '$identifier?.intoBox().ptr.ref.lpVtbl ?? nullptr' + : '$identifier.intoBox().ptr.ref.lpVtbl'; } else if (type.startsWith('IIterable<')) { final iid = typeProjection.typeIdentifier.iid; final nullCheck = isNullable ? '$identifier == null ? nullptr : ' : ''; diff --git a/packages/winrtgen/lib/src/projections/types/uri.dart b/packages/winrtgen/lib/src/projections/types/uri.dart index ac394e61..1d0170f0 100644 --- a/packages/winrtgen/lib/src/projections/types/uri.dart +++ b/packages/winrtgen/lib/src/projections/types/uri.dart @@ -11,8 +11,22 @@ final class UriParameterProjection extends ParameterProjection { @override bool get isNullable { + final parent = method.parent; + // Constructors cannot return null. - if (isReturnParam && method.parent.isFactoryInterface) return false; + if (isReturnParam && parent.isFactoryInterface) return false; + + // The key type arguments of IKeyValuePair, IMap, and + // IMapView cannot be null. + if (parent.genericParams.length == 2 && + (parent.name.endsWith('IKeyValuePair`2') || + parent.isCollectionObject)) { + return switch (parameter.typeIdentifier.genericParameterSequence) { + 0 => false, + _ => true + }; + } + // Treat everything else as nullable. return true; } @@ -36,8 +50,9 @@ final class UriParameterProjection extends ParameterProjection { } @override - String get toListInto => - '$identifier[i]?.toWinRTUri().ptr.ref.lpVtbl ?? nullptr'; + String get toListInto => isNullable + ? '$identifier[i]?.toWinRTUri().ptr.ref.lpVtbl ?? nullptr' + : '$identifier[i].toWinRTUri().ptr.ref.lpVtbl'; @override String get toListIdentifier => 'toDartUriList'; diff --git a/packages/winrtgen/lib/src/utilities/extensions/type_identifier_helpers.dart b/packages/winrtgen/lib/src/utilities/extensions/type_identifier_helpers.dart index e06847da..0b4ff83b 100644 --- a/packages/winrtgen/lib/src/utilities/extensions/type_identifier_helpers.dart +++ b/packages/winrtgen/lib/src/utilities/extensions/type_identifier_helpers.dart @@ -144,7 +144,7 @@ extension TypeIdentifierHelpers on TypeIdentifier { BaseType.valueTypeModifier => lastComponent(name), BaseType.genericTypeModifier => _parseGenericTypeIdentifierName(this), - BaseType.objectType => 'Object?', + BaseType.objectType => 'Object', BaseType.referenceTypeModifier => dereferenceType(this).shortName, _ => baseType.dartType, }; diff --git a/packages/winrtgen/lib/src/utilities/helpers.dart b/packages/winrtgen/lib/src/utilities/helpers.dart index 23b966b8..cf0ed64d 100644 --- a/packages/winrtgen/lib/src/utilities/helpers.dart +++ b/packages/winrtgen/lib/src/utilities/helpers.dart @@ -42,6 +42,22 @@ String folderFromType(String fullyQualifiedType) { return '$packageName/lib/src/${segments.join('/').toLowerCase()}'; } +/// Returns the all [Method]s in the Metadata. +List getAllMethodsInMetadata() { + final methods = []; + + for (final namespace in WinRTNamespace.values) { + final scope = MetadataStore.getWinRTScopeForNamespace(namespace); + methods.addAll( + [...scope.classes, ...scope.interfaces] + .map((typeDef) => typeDef.methods) + .expand((e) => e), + ); + } + + return methods; +} + /// Find a matching typedef, if one exists, for a Windows Runtime [type]. /// Otherwise, throws a [WinRTGenException]. TypeDef getMetadataForType(String type) { diff --git a/packages/winrtgen/test/goldens/imap_part.golden b/packages/winrtgen/test/goldens/imap_part.golden index 42e785cc..ec346819 100644 --- a/packages/winrtgen/test/goldens/imap_part.golden +++ b/packages/winrtgen/test/goldens/imap_part.golden @@ -595,6 +595,119 @@ final class _IMapInt64Inspectable extends IMap { } } +final class _IMapObjectObject extends IMap { + _IMapObjectObject.fromPtr(super.ptr, {required super.iterableIid}); + + @override + Object? lookup(Object key) { + final retValuePtr = calloc(); + + final hr = + ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) { + free(retValuePtr); + throwWindowsException(hr); + } + + if (retValuePtr.isNull) { + free(retValuePtr); + return null; + } + + return IPropertyValue.fromPtr(retValuePtr).value; + } + + @override + bool hasKey(Object key) { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(8) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + bool insert(Object key, Object? value) { + final retValuePtr = calloc(); + + try { + final hr = + ptr.ref.vtable + .elementAt(10) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + VTablePointer value, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + VTablePointer value, Pointer retValuePtr)>()( + ptr.ref.lpVtbl, + key.intoBox().ptr.ref.lpVtbl, + value?.intoBox().ptr.ref.lpVtbl ?? nullptr, + retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + void remove(Object key) { + final hr = ptr.ref.vtable + .elementAt(11) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, VTablePointer key)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key)>()( + ptr.ref.lpVtbl, key.intoBox().ptr.ref.lpVtbl); + + if (FAILED(hr)) throwWindowsException(hr); + } +} + final class _IMapStringInspectable extends IMap { _IMapStringInspectable.fromPtr(super.ptr, {required super.iterableIid, required this.creator}) @@ -1643,6 +1756,120 @@ final class _IMapUint64Inspectable extends IMap { } } +final class _IMapUriString extends IMap { + _IMapUriString.fromPtr(super.ptr, {required super.iterableIid}); + + @override + String lookup(Uri key) { + final retValuePtr = calloc(); + + try { + final hr = + ptr.ref.vtable + .elementAt(6) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.toDartString(); + } finally { + WindowsDeleteString(retValuePtr.value); + free(retValuePtr); + } + } + + @override + bool hasKey(Uri key) { + final retValuePtr = calloc(); + + try { + final hr = ptr.ref.vtable + .elementAt(8) + .cast< + Pointer< + NativeFunction< + HRESULT Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + Pointer retValuePtr)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl, retValuePtr); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + bool insert(Uri key, String value) { + final retValuePtr = calloc(); + + try { + final valueHString = value.toHString(); + + final hr = + ptr.ref.vtable + .elementAt(10) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, + VTablePointer key, + IntPtr value, + Pointer retValuePtr)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key, + int value, Pointer retValuePtr)>()( + ptr.ref.lpVtbl, + key.toWinRTUri().ptr.ref.lpVtbl, + valueHString, + retValuePtr); + + WindowsDeleteString(valueHString); + + if (FAILED(hr)) throwWindowsException(hr); + + return retValuePtr.value; + } finally { + free(retValuePtr); + } + } + + @override + void remove(Uri key) { + final hr = ptr.ref.vtable + .elementAt(11) + .cast< + Pointer< + NativeFunction< + HRESULT Function( + VTablePointer lpVtbl, VTablePointer key)>>>() + .value + .asFunction< + int Function(VTablePointer lpVtbl, VTablePointer key)>()( + ptr.ref.lpVtbl, key.toWinRTUri().ptr.ref.lpVtbl); + + if (FAILED(hr)) throwWindowsException(hr); + } +} + final class _IMapWinRTEnumInspectable extends IMap { _IMapWinRTEnumInspectable.fromPtr(super.ptr, {required super.iterableIid, diff --git a/packages/winrtgen/test/projections/generic_interface_test.dart b/packages/winrtgen/test/projections/generic_interface_test.dart index 38f62991..422aca93 100644 --- a/packages/winrtgen/test/projections/generic_interface_test.dart +++ b/packages/winrtgen/test/projections/generic_interface_test.dart @@ -20,7 +20,7 @@ void main() { group('GenericInterfacePartFileProjection', () { test('projects something', () { const genericType = GenericTypeWithOneTypeArg( - 'Windows.Foundation.IReference`1', [TypeArgKind.string]); + 'Windows.Foundation.IReference`1', {TypeArgKind.string}); final output = GenericInterfacePartFileProjection(genericType).toString(); expect(output, isNotEmpty); expect(output, contains('_IReferenceString')); @@ -50,6 +50,65 @@ void main() { }); group('WinRT generic interface', () { + group('type arguments are supported', () { + void verifySupportedTypeArgKindsOf(GenericType genericType) { + switch (genericType) { + case final GenericTypeWithOneTypeArg type: + final GenericTypeWithOneTypeArg( + :typeArgKinds, + :typeArgKindsInMetadata + ) = type; + + final diff = typeArgKindsInMetadata.difference(typeArgKinds); + if (diff.isNotEmpty) { + fail("$genericType does not support these TypeArgKinds: $diff"); + } + case final GenericTypeWithTwoTypeArgs type: + final GenericTypeWithTwoTypeArgs( + :typeArgKindPairs, + :typeArgKindPairsInMetadata + ) = type; + + final diff = + typeArgKindPairsInMetadata.difference(typeArgKindPairs); + if (diff.isNotEmpty) { + fail( + "$genericType does not support these TypeArgKind pairs: $diff"); + } + } + } + +// TODO(halildurmus): Write tests for: +// TypeArgKind.fromTypeIdentifier +// GenericTypeWithOneTypeArg.typeArgKindsInMetadata +// GenericTypeWithTwoTypeAgs.typeArgKindPairsInMetadata +// non-nullable object and uri parameters + + test('(IAsyncOperation)', () { + verifySupportedTypeArgKindsOf(iasyncOperation); + }); + + test('(IMap)', () { + verifySupportedTypeArgKindsOf(imap); + }); + + test('(IMapView)', () { + verifySupportedTypeArgKindsOf(imapView); + }); + + test('(IReference)', () { + verifySupportedTypeArgKindsOf(ireference); + }); + + test('(IVector)', () { + verifySupportedTypeArgKindsOf(ivector); + }); + + test('(IVectorView)', () { + verifySupportedTypeArgKindsOf(ivectorView); + }); + }); + group('has correct formatted type args', () { test('(1)', () { expect(asyncOperationBoolProjection.formattedTypeArgs, equals('bool')); diff --git a/packages/winrtgen/test/utilities/extensions/type_identifier_helpers_test.dart b/packages/winrtgen/test/utilities/extensions/type_identifier_helpers_test.dart index c4a0d350..c64f3a96 100644 --- a/packages/winrtgen/test/utilities/extensions/type_identifier_helpers_test.dart +++ b/packages/winrtgen/test/utilities/extensions/type_identifier_helpers_test.dart @@ -307,7 +307,7 @@ void main() { .last .typeIdentifier .shortName, - equals('Object?')); + equals('Object')); }); test('(7)', () {