diff --git a/Docs/Projection Design.md b/Docs/Projection Design.md index 44317bb0..dd1fef3e 100644 --- a/Docs/Projection Design.md +++ b/Docs/Projection Design.md @@ -80,17 +80,17 @@ Given a `getObject() -> Base` that actually returns a `Derived`, there is opt-in ## Members ### Properties and accessors -Properties are generated as both throwing accessors methods and nonthrowing properties (returning implicitly unwrapped optionals). +Properties are generated one throwing getter-only property, one throwing setter func, and one suffixed nonthrowing get-set property (when relevant). -**Rationale**: Swift does not support throwing property setters. This is a compromise between exposing errors from property accessors and supporting the convenient property syntax. +**Rationale**: Swift does not support throwing property setters. This compromise supports a natural syntax for reading properties while handling errors, a reasonable way for writing properties while handling errors, and a way to use the property setter syntax (with some friction to point out that exceptions cannot be handled). **Example**: ```swift -func _myProperty() throws -> IClosable // Getter -func _myProperty(_ value: IClosable) throws // Setter +var myProperty: IClosable { get throws } // Getter +func myProperty(_ value: IClosable) throws // Setter extension { - var myProperty: IClosable! { get set } // Nonthrowing property + var myProperty_: IClosable! { get set } // Nonthrowing property } ``` diff --git a/Generator/Sources/ProjectionModel/Projection+conversion.swift b/Generator/Sources/ProjectionModel/Projection+conversion.swift index 3d656843..ede4d120 100644 --- a/Generator/Sources/ProjectionModel/Projection+conversion.swift +++ b/Generator/Sources/ProjectionModel/Projection+conversion.swift @@ -88,13 +88,12 @@ extension Projection { public static func toMemberName(_ member: Member) -> String { let name = member.name - if member is Method, member.nameKind == .special { if let prefixEndIndex = name.findPrefixEndIndex("get_") ?? name.findPrefixEndIndex("set_") ?? name.findPrefixEndIndex("put_") { - // get_Foo() -> _foo() - return "_" + Casing.pascalToCamel(String(name[prefixEndIndex...])) + // get_Foo() -> foo + return Casing.pascalToCamel(String(name[prefixEndIndex...])) } else if let prefixEndIndex = name.findPrefixEndIndex("add_") ?? name.findPrefixEndIndex("remove_") { diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift index 9918dac8..cf972b20 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IIterable_swift @@ -27,23 +27,25 @@ internal class SequenceIterator: WinRTPrimaryExport Bool { current != nil } + var hasCurrent: Bool { get throws { _current != nil } } - func _current() throws -> T { - guard let current else { throw COMError.illegalMethodCall } - return current + var current: T { + get throws { + guard let _current else { throw COMError.illegalMethodCall } + return _current + } } func moveNext() throws -> Bool { - current = iterator.next() - return current != nil + _current = iterator.next() + return _current != nil } func getMany(_ items: [I.Element]) throws -> UInt32 { diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift index 941039f3..b7810124 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVectorView_swift @@ -25,9 +25,7 @@ fileprivate class CollectionVectorView: WinRTPrimaryExport UInt32 { - UInt32(collection.count) - } + public var size: UInt32 { get throws { UInt32(collection.count) } } public func first() throws -> WindowsFoundationCollections_IIterator { SequenceIterator(collection.makeIterator()) diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift index 38898cd3..74e9b1a1 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundationCollections_IVector_swift @@ -23,9 +23,7 @@ public class ArrayVector: WinRTPrimaryExport, self.elementEquals = elementEquals } - public func _size() throws -> UInt32 { - UInt32(array.count) - } + public var size: UInt32 { get throws { UInt32(array.count) } } public func first() throws -> WindowsFoundationCollections_IIterator { SequenceIterator(array.makeIterator()) diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift index 4f0b5bb8..69052da2 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncActionWithProgress_swift @@ -3,11 +3,11 @@ import WindowsRuntime extension WindowsFoundation_IAsyncActionWithProgressProtocol { public func get() async throws { - if try _status() == .started { + if try self.status == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } + guard try COM.NullResult.catch(self.completed) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() - try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) + try self.completed { _, _ in _Concurrency.Task { await awaiter.signal() } } await awaiter.wait() } diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift index 702f8271..433a04cb 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncAction_swift @@ -3,11 +3,11 @@ import WindowsRuntime extension WindowsFoundation_IAsyncActionProtocol { public func get() async throws { - if try _status() == .started { + if try self.status == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } + guard try COM.NullResult.catch(self.completed) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() - try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) + try self.completed { _, _ in _Concurrency.Task { await awaiter.signal() } } await awaiter.wait() } diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift index 413cdf79..fa1cdfdb 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperationWithProgress_swift @@ -3,11 +3,11 @@ import WindowsRuntime extension WindowsFoundation_IAsyncOperationWithProgressProtocol { public func get() async throws -> TResult { - if try _status() == .started { + if try self.status == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } + guard try COM.NullResult.catch(self.completed) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() - try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) + try self.completed { _, _ in _Concurrency.Task { await awaiter.signal() } } await awaiter.wait() } diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift index ada68cdd..5165fa28 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsFoundation_IAsyncOperation_swift @@ -3,11 +3,11 @@ import WindowsRuntime extension WindowsFoundation_IAsyncOperationProtocol { public func get() async throws -> TResult { - if try _status() == .started { + if try self.status == .started { // We can't await if the completed handler is already set - guard try COM.NullResult.catch(_completed()) == nil else { throw COM.COMError.illegalMethodCall } + guard try COM.NullResult.catch(self.completed) == nil else { throw COM.COMError.illegalMethodCall } let awaiter = WindowsRuntime.AsyncAwaiter() - try _completed({ _, _ in _Concurrency.Task { await awaiter.signal() } }) + try self.completed { _, _ in _Concurrency.Task { await awaiter.signal() } } await awaiter.wait() } diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_Buffer_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_Buffer_swift index 5ca42390..b05531c1 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_Buffer_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_Buffer_swift @@ -3,7 +3,7 @@ import WindowsRuntime extension WindowsStorageStreams_Buffer { public convenience init(_ bytes: [UInt8]) throws { try self.init(UInt32(bytes.count)) - try self._length(UInt32(bytes.count)) + try self.length(UInt32(bytes.count)) let byteAccess = try self._queryInterface(IBufferByteAccessBinding.self) let bufferPointer = try UnsafeMutableBufferPointer(start: byteAccess.interop.buffer(), count: bytes.count) _ = bufferPointer.update(fromContentsOf: bytes) diff --git a/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_IBuffer_swift b/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_IBuffer_swift index 987b5792..18afdc90 100644 --- a/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_IBuffer_swift +++ b/Generator/Sources/SwiftWinRT/Extensions/WindowsStorageStreams_IBuffer_swift @@ -11,6 +11,6 @@ extension WindowsStorageStreams_IBufferProtocol { extension Array where Element == UInt8 { public init(_ buffer: WindowsStorageStreams_IBuffer) throws { - self.init(try UnsafeBufferPointer(start: buffer.bytes, count: Int(buffer._length()))) + self.init(try UnsafeBufferPointer(start: buffer.bytes, count: Int(buffer.length))) } } \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Writing/COMImportClass.swift b/Generator/Sources/SwiftWinRT/Writing/COMImportClass.swift index f563337b..dec3abeb 100644 --- a/Generator/Sources/SwiftWinRT/Writing/COMImportClass.swift +++ b/Generator/Sources/SwiftWinRT/Writing/COMImportClass.swift @@ -36,7 +36,7 @@ internal func writeCOMImportClass( try writeGenericTypeAliases(interfaces: interfaces, projection: projection, to: writer) // Primary interface implementation - try writeInterfaceImplementation( + try writeMemberDefinitions( abiType: type, documentation: false, thisPointer: .init(name: "_interop"), projection: projection, to: writer) @@ -56,7 +56,7 @@ internal func writeCOMImportClass( for secondaryInterface in secondaryInterfaces { let secondaryInterfaceName = try WinRTTypeName.from(type: secondaryInterface.asBoundType).description writer.writeMarkComment("\(secondaryInterfaceName) members") - try writeInterfaceImplementation( + try writeMemberDefinitions( abiType: secondaryInterface.asBoundType, documentation: false, thisPointer: .init(name: SecondaryInterfaces.getPropertyName(secondaryInterface), lazy: true), projection: projection, to: writer) diff --git a/Generator/Sources/SwiftWinRT/Writing/ClassDefinition.swift b/Generator/Sources/SwiftWinRT/Writing/ClassDefinition.swift index 20d4ab75..e0670503 100644 --- a/Generator/Sources/SwiftWinRT/Writing/ClassDefinition.swift +++ b/Generator/Sources/SwiftWinRT/Writing/ClassDefinition.swift @@ -174,7 +174,7 @@ fileprivate func writeInterfaceImplementations( let thisPointer: ThisPointer = try classDefinition.isSealed && getRuntimeClassBase(classDefinition) == nil ? .init(name: "_interop") : .init(name: SecondaryInterfaces.getPropertyName(defaultInterface), lazy: true) - try writeInterfaceImplementation( + try writeMemberDefinitions( abiType: defaultInterface.asBoundType, classDefinition: classDefinition, thisPointer: thisPointer, projection: projection, to: writer) } @@ -186,7 +186,7 @@ fileprivate func writeInterfaceImplementations( try writeMarkComment(forInterface: secondaryInterface.interface, to: writer) } - try writeInterfaceImplementation( + try writeMemberDefinitions( abiType: secondaryInterface.interface.asBoundType, classDefinition: classDefinition, overridable: secondaryInterface.overridable, @@ -201,7 +201,7 @@ fileprivate func writeInterfaceImplementations( try writeMarkComment(forInterface: staticInterface.bind(), to: writer) } - try writeInterfaceImplementation( + try writeMemberDefinitions( abiType: staticInterface.bindType(), classDefinition: classDefinition, static: true, thisPointer: .init(name: SecondaryInterfaces.getPropertyName(staticInterface.bind()), lazy: true), projection: projection, to: writer) diff --git a/Generator/Sources/SwiftWinRT/Writing/ExtensionProperties.swift b/Generator/Sources/SwiftWinRT/Writing/ExtensionProperties.swift deleted file mode 100644 index ff7d1156..00000000 --- a/Generator/Sources/SwiftWinRT/Writing/ExtensionProperties.swift +++ /dev/null @@ -1,68 +0,0 @@ -import CodeWriters -import DotNetMetadata -import ProjectionModel - -internal func writeExtensionProperties( - typeDefinition: TypeDefinition, interfaces: [InterfaceDefinition], static: Bool, - projection: Projection, to writer: SwiftSourceFileWriter) throws { - // Only write the extension if we have at least one property (which needs a getter) - let hasGetters = try interfaces.contains { try $0.properties.contains { try $0.getter != nil } } - guard hasGetters else { return } - - let typeName: String - if let interface = typeDefinition as? InterfaceDefinition { - typeName = try projection.toProtocolName(interface) - } else { - typeName = try projection.toTypeName(typeDefinition) - } - - try writer.writeExtension(type: .identifier(typeName)) { writer in - for interface in interfaces { - for property in interface.properties { - try writeNonthrowingPropertyImplementation( - property: property, static: `static`, - classDefinition: typeDefinition as? ClassDefinition, - projection: projection, to: writer) - } - } - } -} - -internal func writeNonthrowingPropertyImplementation( - property: Property, static: Bool, classDefinition: ClassDefinition?, - projection: Projection, to writer: SwiftTypeDefinitionWriter) throws { - guard let getter = try property.getter else { return } - - let selfKeyword = `static` ? "Self" : "self" - - let writeSetter: ((inout SwiftStatementWriter) throws -> Void)? - if let setter = try property.setter { - writeSetter = { writer in - writer.writeStatement("try! \(selfKeyword).\(Projection.toMemberName(setter))(newValue)") - } - } else { - writeSetter = nil - } - - // Convert nullability representation from NullResult errors to implicitly unwrapped optionals (T!) - var propertyType = try projection.toReturnType(property.type) - let catchNullResult = projection.isNullAsErrorEligible(try property.type) - if catchNullResult { - propertyType = .optional(wrapped: propertyType, implicitUnwrap: true) - } - - try writer.writeComputedProperty( - documentation: projection.getDocumentationComment(property, classDefinition: classDefinition), - visibility: .public, - static: `static`, - name: Projection.toMemberName(property), - type: propertyType, - get: { writer in - let output = writer.output - output.write("try! ") - if catchNullResult { output.write("NullResult.catch(") } - output.write("\(selfKeyword).\(Projection.toMemberName(getter))()") - if catchNullResult { output.write(")") } - }, - set: writeSetter) -} \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift b/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift index a0fecebd..ea26d70c 100644 --- a/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift +++ b/Generator/Sources/SwiftWinRT/Writing/InterfaceDefinition.swift @@ -104,33 +104,31 @@ fileprivate func writeProtocol(_ interfaceDefinition: InterfaceDefinition, proje } } - // Write properties as "_getFoo() throws -> T" and "_setFoo(newValue: T) throws", - // to provide a way to handle errors. - // We'll generate non-throwing "var foo: T { get set }" as an extension. + // Write properties as "var foo: T { get throws}" and "func setFoo(_ newValue: T) throws", + // to provide a way to handle errors (Swift does not support throwing settable properties) + // We'll generate non-throwing "var foo_: T! { get set }" as an extension. for property in interfaceDefinition.properties { if let getter = try property.getter { - try writer.writeFunc( + try writer.writeProperty( documentation: projection.getDocumentationComment(property, accessor: .getter), - name: Projection.toMemberName(getter), - throws: true, - returnType: projection.toReturnType(property.type)) + name: Projection.toMemberName(property), + type: projection.toReturnType(getter.returnType), + throws: true) } if let setter = try property.setter { try writer.writeFunc( groupAsProperty: true, documentation: projection.getDocumentationComment(property, accessor: .setter), - name: Projection.toMemberName(setter), + name: Projection.toMemberName(property), params: setter.params.map { try projection.toParameter($0) }, throws: true) } } } - // Write fatalError'ing properties as an extension - try writeExtensionProperties( - typeDefinition: interfaceDefinition, interfaces: [interfaceDefinition], static: false, - projection: projection, to: writer) + // Write non-throwing properties as an extension + try writeNonthrowingPropertiesExtension(interfaceDefinition, projection: projection, to: writer) } fileprivate func writeProtocolTypeAlias(_ interfaceDefinition: InterfaceDefinition, projection: Projection, to writer: SwiftSourceFileWriter) throws { @@ -144,3 +142,18 @@ fileprivate func writeProtocolTypeAlias(_ interfaceDefinition: InterfaceDefiniti name: try projection.toProtocolName(interfaceDefinition), genericArgs: interfaceDefinition.genericParams.map { .identifier(name: $0.name) })) } + +fileprivate func writeNonthrowingPropertiesExtension( + _ interfaceDefinition: InterfaceDefinition, projection: Projection, to writer: SwiftSourceFileWriter) throws { + // Only write the extension if we have at least one property having both a getter and setter + let getSetProperties = try interfaceDefinition.properties.filter { try $0.getter != nil && $0.setter != nil } + guard !getSetProperties.isEmpty else { return } + + let typeName: String = try projection.toProtocolName(interfaceDefinition) + try writer.writeExtension(type: .identifier(typeName)) { writer in + for property in getSetProperties { + try writeNonthrowingPropertyImplementation( + property: property, static: false, projection: projection, to: writer) + } + } +} \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Writing/InterfaceImplementation.swift b/Generator/Sources/SwiftWinRT/Writing/MemberDefinition.swift similarity index 89% rename from Generator/Sources/SwiftWinRT/Writing/InterfaceImplementation.swift rename to Generator/Sources/SwiftWinRT/Writing/MemberDefinition.swift index 3a269c6f..7525321e 100644 --- a/Generator/Sources/SwiftWinRT/Writing/InterfaceImplementation.swift +++ b/Generator/Sources/SwiftWinRT/Writing/MemberDefinition.swift @@ -13,7 +13,7 @@ internal struct ThisPointer { } } -internal func writeInterfaceImplementation( +internal func writeMemberDefinitions( abiType: BoundType, classDefinition: ClassDefinition? = nil, documentation: Bool = true, overridable: Bool = false, static: Bool = false, thisPointer: ThisPointer, projection: Projection, to writer: SwiftTypeDefinitionWriter) throws { @@ -21,56 +21,50 @@ internal func writeInterfaceImplementation( guard method.isPublic && !(method is Constructor) else { continue } // Generate Delegate.Invoke as a regular method guard method.nameKind == .regular || abiType.definition is DelegateDefinition else { continue } - try writeInterfaceMethodImplementation( + try writeMethodDefinition( method, typeGenericArgs: abiType.genericArgs, classDefinition: classDefinition, documentation: documentation, overridable: overridable, static: `static`, thisPointer: thisPointer, projection: projection, to: writer) } for event in abiType.definition.events { - try writeInterfaceEventImplementation( + try writeEventDefinition( event, typeGenericArgs: abiType.genericArgs, classDefinition: classDefinition, documentation: documentation, overridable: overridable, static: `static`, thisPointer: thisPointer, projection: projection, to: writer) } for property in abiType.definition.properties { - try writeInterfacePropertyImplementation( + try writePropertyDefinition( property, typeGenericArgs: abiType.genericArgs, classDefinition: classDefinition, documentation: documentation, overridable: overridable, static: `static`, thisPointer: thisPointer, projection: projection, to: writer) } } -fileprivate func writeInterfacePropertyImplementation( +fileprivate func writePropertyDefinition( _ property: Property, typeGenericArgs: [TypeNode], classDefinition: ClassDefinition?, documentation: Bool, overridable: Bool, static: Bool, thisPointer: ThisPointer, projection: Projection, to writer: SwiftTypeDefinitionWriter) throws { - if try property.definingType.hasAttribute(ExclusiveToAttribute.self) { - // The property is exclusive to this class so it doesn't come - // from an interface that would an extension property. - // public static var myProperty: MyPropertyType { ... } - try writeNonthrowingPropertyImplementation( - property: property, static: `static`, classDefinition: classDefinition, - projection: projection, to: writer) - } - - // public [static] func _myProperty() throws -> MyPropertyType { ... } + // Write getter as get-only computed property, which supports throwing + // public [static] var myProperty: MyPropertyType { get throws { ... } } if let getter = try property.getter, try getter.hasReturnValue { let returnParamBinding = try projection.getParamBinding(getter.returnParam, genericTypeArgs: typeGenericArgs) - try writer.writeFunc( + try writer.writeComputedProperty( documentation: documentation ? projection.getDocumentationComment(property, accessor: .getter, classDefinition: classDefinition) : nil, visibility: overridable ? .open : .public, static: `static`, - name: Projection.toMemberName(getter), + name: Projection.toMemberName(property), + type: returnParamBinding.swiftType, throws: true, - returnType: returnParamBinding.swiftType) { writer throws in + get: { writer throws in try writeInteropMethodCall( name: Projection.toInteropMethodName(getter), params: [], returnParam: returnParamBinding, thisPointer: thisPointer, projection: projection, to: writer.output) - } + }) } + // Write setter as a method because settable properties do not support throwing // public [static] func myProperty(_ newValue: MyPropertyType) throws { ... } if let setter = try property.setter { guard let newValueParam = try setter.params.first else { fatalError() } @@ -79,7 +73,7 @@ fileprivate func writeInterfacePropertyImplementation( documentation: documentation ? projection.getDocumentationComment(property, accessor: .setter, classDefinition: classDefinition) : nil, visibility: .public, static: `static`, - name: Projection.toMemberName(setter), + name: Projection.toMemberName(property), params: [ newValueParamBinding.toSwiftParam() ], throws: true) { writer throws in try writeInteropMethodCall( @@ -88,9 +82,19 @@ fileprivate func writeInterfacePropertyImplementation( thisPointer: thisPointer, projection: projection, to: writer.output) } } + + // For convenience, define a get-set property, though this cannot be throwing so it must fatal error. + if try property.definingType.hasAttribute(ExclusiveToAttribute.self), try property.getter != nil && property.setter != nil { + // The property is exclusive to this class so it doesn't come + // from an interface that would declare an extension property. + // public static var myProperty: MyPropertyType { ... } + try writeNonthrowingPropertyImplementation( + property: property, static: `static`, classDefinition: classDefinition, + projection: projection, to: writer) + } } -fileprivate func writeInterfaceEventImplementation( +fileprivate func writeEventDefinition( _ event: Event, typeGenericArgs: [TypeNode], classDefinition: ClassDefinition?, documentation: Bool, overridable: Bool, static: Bool, thisPointer: ThisPointer, projection: Projection, to writer: SwiftTypeDefinitionWriter) throws { @@ -102,7 +106,8 @@ fileprivate func writeInterfaceEventImplementation( let eventRegistrationType = SupportModules.WinRT.eventRegistration try writer.writeFunc( documentation: documentation ? projection.getDocumentationComment(event, classDefinition: classDefinition) : nil, - visibility: overridable ? .open : .public, static: `static`, name: name, + visibility: overridable ? .open : .public, static: `static`, + name: name, params: [ handlerParamBinding.toSwiftParam(label: "adding") ], throws: true, returnType: eventRegistrationType) { writer throws in // Convert the return token into an EventRegistration type for ease of unregistering @@ -135,7 +140,7 @@ fileprivate func writeInterfaceEventImplementation( } } -fileprivate func writeInterfaceMethodImplementation( +fileprivate func writeMethodDefinition( _ method: Method, typeGenericArgs: [TypeNode], classDefinition: ClassDefinition?, documentation: Bool, overridable: Bool, static: Bool, thisPointer: ThisPointer, projection: Projection, to writer: SwiftTypeDefinitionWriter) throws { diff --git a/Generator/Sources/SwiftWinRT/Writing/NonthrowingProperties.swift b/Generator/Sources/SwiftWinRT/Writing/NonthrowingProperties.swift new file mode 100644 index 00000000..ce41d09c --- /dev/null +++ b/Generator/Sources/SwiftWinRT/Writing/NonthrowingProperties.swift @@ -0,0 +1,40 @@ +import CodeWriters +import DotNetMetadata +import ProjectionModel + +/// Writes a fatalerror'ing version of a property that delegates to the throwing accessors. +/// This allows the convenient "foo.prop = 42" syntax, at the expense of error handling. +/// The fatalerror'ing version exposes null results through implicitly unwrapped optionals. +internal func writeNonthrowingPropertyImplementation( + property: Property, static: Bool, classDefinition: ClassDefinition? = nil, + projection: Projection, to writer: SwiftTypeDefinitionWriter) throws { + // Nonthrowing properties are useful for the assignment syntax, so only relevant if we have a setter, + // and Swift does not support set-only properties, so we require both accessors. + guard try property.getter != nil, try property.setter != nil else { return } + + // Convert nullability representation from NullResult errors to implicitly unwrapped optionals (T!) + var propertyType = try projection.toReturnType(property.type) + let catchNullResult = projection.isNullAsErrorEligible(try property.type) + if catchNullResult { + propertyType = .optional(wrapped: propertyType, implicitUnwrap: true) + } + + let selfKeyword = `static` ? "Self" : "self" + + try writer.writeComputedProperty( + documentation: projection.getDocumentationComment(property, classDefinition: classDefinition), + visibility: .public, + static: `static`, + name: Projection.toMemberName(property) + "_", // Disambiguate from throwing accessors + type: propertyType, + get: { writer in + let output = writer.output + output.write("try! ") + if catchNullResult { output.write("NullResult.catch(") } + output.write("\(selfKeyword).\(Projection.toMemberName(property))") + if catchNullResult { output.write(")") } + }, + set: { writer in + writer.writeStatement("try! \(selfKeyword).\(Projection.toMemberName(property))(newValue)") + }) +} \ No newline at end of file diff --git a/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift b/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift index d010d036..c53c0a08 100644 --- a/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift +++ b/Generator/Sources/SwiftWinRT/Writing/VirtualTable.swift @@ -115,23 +115,25 @@ fileprivate func writeVirtualTableFunc( output.write("try ") output.write(methodKind == .delegateInvoke ? "this" : "this.\(swiftMemberName)") - output.write("(") - if methodKind == .eventAdder || methodKind == .eventRemover { - assert(params.count == 1) - output.write(methodKind == .eventAdder ? "adding: " : "removing: ") - } - for (index, param) in params.enumerated() { - if index > 0 { output.write(", ") } - if param.passBy != .value { output.write("&") } - if param.typeProjection.kind == .identity { - output.write(param.name) - if param.passBy != .value { output.write(".pointee") } - } else { - output.write(param.swiftBindingName) + if methodKind != .propertyGetter { + output.write("(") + if methodKind == .eventAdder || methodKind == .eventRemover { + assert(params.count == 1) + output.write(methodKind == .eventAdder ? "adding: " : "removing: ") + } + for (index, param) in params.enumerated() { + if index > 0 { output.write(", ") } + if param.passBy != .value { output.write("&") } + if param.typeProjection.kind == .identity { + output.write(param.name) + if param.passBy != .value { output.write(".pointee") } + } else { + output.write(param.swiftBindingName) + } } + output.write(")") + if methodKind == .eventAdder { output.write(".token") } } - output.write(")") - if methodKind == .eventAdder { output.write(".token") } if let returnParam, case .return(nullAsError: true) = returnParam.passBy { output.write(")") // NullResult.`catch` diff --git a/InteropTests/Tests/ActivationFactoryTests.swift b/InteropTests/Tests/ActivationFactoryTests.swift index 4f785328..0ff9d63a 100644 --- a/InteropTests/Tests/ActivationFactoryTests.swift +++ b/InteropTests/Tests/ActivationFactoryTests.swift @@ -5,11 +5,11 @@ import WinRTComponent class ActivationFactoryTests: WinRTTestCase { func testDefault() throws { - XCTAssertEqual(try OverloadedSum()._result(), 0) + XCTAssertEqual(try OverloadedSum().result, 0) } func testParameterized() throws { - XCTAssertEqual(try OverloadedSum(1)._result(), 1) - XCTAssertEqual(try OverloadedSum(1, 2)._result(), 3) + XCTAssertEqual(try OverloadedSum(1).result, 1) + XCTAssertEqual(try OverloadedSum(1, 2).result, 3) } } \ No newline at end of file diff --git a/InteropTests/Tests/AsyncTests.swift b/InteropTests/Tests/AsyncTests.swift index 45c81444..7cbf466c 100644 --- a/InteropTests/Tests/AsyncTests.swift +++ b/InteropTests/Tests/AsyncTests.swift @@ -5,18 +5,18 @@ import WinRTComponent class AsyncTests : XCTestCase { public func testAwaitAlreadyCompleted() async throws { let asyncOperation = try ManualAsyncOperation(0) - XCTAssertEqual(try asyncOperation._status(), .started) + XCTAssertEqual(try asyncOperation.status, .started) try asyncOperation.complete(42) - XCTAssertEqual(try asyncOperation._status(), .completed) + XCTAssertEqual(try asyncOperation.status, .completed) let result = try await asyncOperation.get() XCTAssertEqual(result, 42) } public func testAwaitAlreadyFailed() async throws { let asyncOperation = try ManualAsyncOperation(0) - XCTAssertEqual(try asyncOperation._status(), .started) + XCTAssertEqual(try asyncOperation.status, .started) try asyncOperation.completeWithError(HResult.outOfMemory) - XCTAssertEqual(try asyncOperation._status(), .error) + XCTAssertEqual(try asyncOperation.status, .error) do { let _ = try await asyncOperation.get() XCTFail("Expected an exception to be thrown") @@ -28,36 +28,36 @@ class AsyncTests : XCTestCase { public func testAwaitNotYetCompleted() async throws { let asyncOperation = try ManualAsyncOperation(0) - XCTAssertEqual(try asyncOperation._status(), .started) + XCTAssertEqual(try asyncOperation.status, .started) Self.runAfter(delay: 0.05) { try? asyncOperation.complete(42) } let result = try await asyncOperation.get() - XCTAssertEqual(try asyncOperation._status(), .completed) + XCTAssertEqual(try asyncOperation.status, .completed) XCTAssertEqual(result, 42) } public func testAwaitNotYetFailed() async throws { let asyncOperation = try ManualAsyncOperation(0) - XCTAssertEqual(try asyncOperation._status(), .started) + XCTAssertEqual(try asyncOperation.status, .started) Self.runAfter(delay: 0.05) { try? asyncOperation.completeWithError(HResult.outOfMemory) } do { let _ = try await asyncOperation.get() XCTFail("Expected an exception to be thrown") } catch let error as COMErrorProtocol { - XCTAssertEqual(try asyncOperation._status(), .error) + XCTAssertEqual(try asyncOperation.status, .error) XCTAssertEqual(error.hresult, HResult.outOfMemory) } } public func testAwaitWithExistingCompletionHandler() async throws { let asyncOperation = try ManualAsyncOperation(0) - try asyncOperation._completed { _, _ in } + try asyncOperation.completed { _, _ in } do { let _ = try await asyncOperation.get() XCTFail("Expected an exception to be thrown") } catch let error as COMErrorProtocol { - XCTAssertEqual(try asyncOperation._status(), .started) + XCTAssertEqual(try asyncOperation.status, .started) XCTAssertEqual(error.hresult, HResult.illegalMethodCall) } } diff --git a/InteropTests/Tests/ClassInheritanceTests.swift b/InteropTests/Tests/ClassInheritanceTests.swift index e34d685c..42f6055c 100644 --- a/InteropTests/Tests/ClassInheritanceTests.swift +++ b/InteropTests/Tests/ClassInheritanceTests.swift @@ -6,56 +6,56 @@ import WinRTComponent class ClassInheritanceTests : XCTestCase { public func testOverridableMemberOnBaseClass() throws { // Created from Swift - XCTAssertEqual(try MinimalBaseClass()._typeName(), "MinimalBaseClass") + XCTAssertEqual(try MinimalBaseClass().typeName, "MinimalBaseClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalBaseClass()), "MinimalBaseClass") // Created from WinRT - XCTAssertEqual(try MinimalBaseClassHierarchy.createBase()._typeName(), "MinimalBaseClass") + XCTAssertEqual(try MinimalBaseClassHierarchy.createBase().typeName, "MinimalBaseClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalBaseClassHierarchy.createBase()), "MinimalBaseClass") } public func testOverridenMemberInUnsealedDerivedClass() throws { // Created from Swift - XCTAssertEqual(try MinimalUnsealedDerivedClass()._typeName(), "MinimalUnsealedDerivedClass") + XCTAssertEqual(try MinimalUnsealedDerivedClass().typeName, "MinimalUnsealedDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalUnsealedDerivedClass()), "MinimalUnsealedDerivedClass") // Created from WinRT - XCTAssertEqual(try MinimalBaseClassHierarchy.createUnsealedDerived()._typeName(), "MinimalUnsealedDerivedClass") + XCTAssertEqual(try MinimalBaseClassHierarchy.createUnsealedDerived().typeName, "MinimalUnsealedDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalBaseClassHierarchy.createUnsealedDerived()), "MinimalUnsealedDerivedClass") } public func testOverridenMemberInSealedDerivedClass() throws { // Created from Swift - XCTAssertEqual(try MinimalSealedDerivedClass()._typeName(), "MinimalSealedDerivedClass") + XCTAssertEqual(try MinimalSealedDerivedClass().typeName, "MinimalSealedDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalSealedDerivedClass()), "MinimalSealedDerivedClass") // Created from WinRT - XCTAssertEqual(try MinimalBaseClassHierarchy.createSealedDerived()._typeName(), "MinimalSealedDerivedClass") + XCTAssertEqual(try MinimalBaseClassHierarchy.createSealedDerived().typeName, "MinimalSealedDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalBaseClassHierarchy.createSealedDerived()), "MinimalSealedDerivedClass") } public func testOverridenMemberInPrivateDerivedClass() throws { - XCTAssertEqual(try MinimalBaseClassHierarchy.createPrivateDerived()._typeName(), "PrivateDerivedClass") + XCTAssertEqual(try MinimalBaseClassHierarchy.createPrivateDerived().typeName, "PrivateDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(MinimalBaseClassHierarchy.createPrivateDerived()), "PrivateDerivedClass") } public func testOverridenMemberInSwiftDerivedClass() throws { class SwiftDerivedClass: MinimalBaseClass, @unchecked Sendable { public override init() throws { try super.init() } - public override func _typeName() throws -> String { "SwiftDerivedClass" } + public override var typeName: String { get throws { "SwiftDerivedClass" } } } - XCTAssertEqual(try SwiftDerivedClass()._typeName(), "SwiftDerivedClass") + XCTAssertEqual(try SwiftDerivedClass().typeName, "SwiftDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(SwiftDerivedClass()), "SwiftDerivedClass") } public func testOverridenMemberInSwiftClassDerivedFromUnsealedDerivedClass() throws { class SwiftDerivedDerivedClass: MinimalUnsealedDerivedClass, @unchecked Sendable { public override init() throws { try super.init() } - public override func _typeName() throws -> String { "SwiftDerivedDerivedClass" } + public override var typeName: String { get throws { "SwiftDerivedDerivedClass" } } } - XCTAssertEqual(try SwiftDerivedDerivedClass()._typeName(), "SwiftDerivedDerivedClass") + XCTAssertEqual(try SwiftDerivedDerivedClass().typeName, "SwiftDerivedDerivedClass") XCTAssertEqual(try MinimalBaseClassHierarchy.getTypeName(SwiftDerivedDerivedClass()), "SwiftDerivedDerivedClass") } diff --git a/InteropTests/Tests/CollectionTests.swift b/InteropTests/Tests/CollectionTests.swift index 3f93a9cd..9035455e 100644 --- a/InteropTests/Tests/CollectionTests.swift +++ b/InteropTests/Tests/CollectionTests.swift @@ -5,12 +5,12 @@ class CollectionTests: WinRTTestCase { func testIteration() throws { let iterable = try Collections.createIterable([3, 2, 1]) let iterator = try iterable.first() - XCTAssert(try iterator._hasCurrent()) - XCTAssertEqual(try iterator._current(), 3) + XCTAssert(try iterator.hasCurrent) + XCTAssertEqual(try iterator.current, 3) XCTAssert(try iterator.moveNext()) - XCTAssertEqual(try iterator._current(), 2) + XCTAssertEqual(try iterator.current, 2) XCTAssert(try iterator.moveNext()) - XCTAssertEqual(try iterator._current(), 1) + XCTAssertEqual(try iterator.current, 1) XCTAssertFalse(try iterator.moveNext()) } } \ No newline at end of file diff --git a/InteropTests/Tests/ErrorTests.swift b/InteropTests/Tests/ErrorTests.swift index e201ac5b..ac56623b 100644 --- a/InteropTests/Tests/ErrorTests.swift +++ b/InteropTests/Tests/ErrorTests.swift @@ -26,8 +26,8 @@ class ErrorTests: WinRTTestCase { } func testCallThrowingProperty() throws { - XCTAssertThrowsError(try Errors._notImplementedProperty()) - XCTAssertThrowsError(try Errors._notImplementedProperty("foo")) + XCTAssertThrowsError(try Errors.notImplementedProperty) + XCTAssertThrowsError(try Errors.notImplementedProperty("foo")) } func testThrowWithHResult() throws { diff --git a/InteropTests/Tests/EventTests.swift b/InteropTests/Tests/EventTests.swift index 53af9503..d78b00d4 100644 --- a/InteropTests/Tests/EventTests.swift +++ b/InteropTests/Tests/EventTests.swift @@ -21,12 +21,12 @@ class EventTests: WinRTTestCase { func testExportedEvent() throws { let eventSource = EventSource() let counter = try XCTUnwrap(Events.createCounter(eventSource)) - XCTAssertEqual(try counter._count(), 0) + XCTAssertEqual(try counter.count, 0) try eventSource.fire() - XCTAssertEqual(try counter._count(), 1) + XCTAssertEqual(try counter.count, 1) try counter.detach() try eventSource.fire() - XCTAssertEqual(try counter._count(), 1) + XCTAssertEqual(try counter.count, 1) class EventSource: WinRTPrimaryExport, IEventSourceProtocol { private var invocationList: EventInvocationList = .init() diff --git a/InteropTests/Tests/InspectableBoxingTests.swift b/InteropTests/Tests/InspectableBoxingTests.swift index 8ed42666..14efd235 100644 --- a/InteropTests/Tests/InspectableBoxingTests.swift +++ b/InteropTests/Tests/InspectableBoxingTests.swift @@ -5,7 +5,7 @@ import XCTest extension IInspectableProtocol { fileprivate func unbox(_: Binding.Type) throws -> Binding.SwiftValue { let ireference = try self.queryInterface(WindowsFoundation_IReferenceBinding.self) - return try ireference._value() + return try ireference.value } } @@ -46,7 +46,7 @@ class InspectableBoxingTests: WinRTTestCase { try assertRoundTrip { let ireference = try createIReference($0, binding: MinimalDelegateBinding.self) - return try XCTUnwrap(ireference._value()) + return try XCTUnwrap(ireference.value) } try assertRoundTrip { diff --git a/InteropTests/Tests/ObjectExportingTests.swift b/InteropTests/Tests/ObjectExportingTests.swift index 94d15945..047720e6 100644 --- a/InteropTests/Tests/ObjectExportingTests.swift +++ b/InteropTests/Tests/ObjectExportingTests.swift @@ -46,9 +46,9 @@ class ObjectExportingTests: WinRTTestCase { var instance: Exported? = Exported() let weakReferencer = try WeakReferencer(XCTUnwrap(instance)) - XCTAssertNotNil(try NullResult.catch(weakReferencer._target())) + XCTAssertNotNil(try NullResult.catch(weakReferencer.target)) instance = withExtendedLifetime(instance) { nil } - XCTAssertNil(try NullResult.catch(weakReferencer._target())) + XCTAssertNil(try NullResult.catch(weakReferencer.target)) } } \ No newline at end of file diff --git a/InteropTests/Tests/PropertyTests.swift b/InteropTests/Tests/PropertyTests.swift index 39f76441..e7751737 100644 --- a/InteropTests/Tests/PropertyTests.swift +++ b/InteropTests/Tests/PropertyTests.swift @@ -8,36 +8,34 @@ class PropertyTests: WinRTTestCase { let wrapper = try Int32Wrapper() func assertGet(expected: Int32) throws { - XCTAssertEqual(wrapper.getOnly, expected) - XCTAssertEqual(try wrapper._getOnly(), expected) - XCTAssertEqual(wrapper.getSet, expected) - XCTAssertEqual(try wrapper._getSet(), expected) + XCTAssertEqual(try wrapper.getOnly, expected) + XCTAssertEqual(try wrapper.getSet, expected) + XCTAssertEqual(wrapper.getSet_, expected) } try assertGet(expected: 0) - wrapper.getSet = 1 + try wrapper.getSet(1) try assertGet(expected: 1) - try wrapper._getSet(2) + wrapper.getSet_ = 2 try assertGet(expected: 2) } func testStatic() throws { func assertGet(expected: Int32) throws { - XCTAssertEqual(Int32Global.getOnly, expected) - XCTAssertEqual(try Int32Global._getOnly(), expected) - XCTAssertEqual(Int32Global.getSet, expected) - XCTAssertEqual(try Int32Global._getSet(), expected) + XCTAssertEqual(try Int32Global.getOnly, expected) + XCTAssertEqual(try Int32Global.getSet, expected) + XCTAssertEqual(Int32Global.getSet_, expected) } - Int32Global.getSet = 0 + try Int32Global.getSet(0) try assertGet(expected: 0) - Int32Global.getSet = 1 + try Int32Global.getSet(1) try assertGet(expected: 1) - try Int32Global._getSet(2) + Int32Global.getSet_ = 2 try assertGet(expected: 2) } } \ No newline at end of file diff --git a/InteropTests/Tests/WeakReferenceTests.swift b/InteropTests/Tests/WeakReferenceTests.swift index d1a17d5a..928bd441 100644 --- a/InteropTests/Tests/WeakReferenceTests.swift +++ b/InteropTests/Tests/WeakReferenceTests.swift @@ -17,12 +17,12 @@ class WeakReferenceTests: WinRTTestCase { let weakReference = try WeakReference(target) target = nil - XCTAssertNotNil(try strongReferencer._target()) + XCTAssertNotNil(try NullResult.catch(strongReferencer.target)) XCTAssertNotNil(try weakReference.resolve()) try strongReferencer.clear() - XCTAssertNil(try NullResult.catch(strongReferencer._target())) + XCTAssertNil(try NullResult.catch(strongReferencer.target)) XCTAssertNil(try weakReference.resolve()) } diff --git a/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IPropertyValue.swift b/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IPropertyValue.swift index 50459cb7..3cbf8bca 100644 --- a/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IPropertyValue.swift +++ b/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IPropertyValue.swift @@ -4,10 +4,10 @@ public typealias WindowsFoundation_IPropertyValue = any WindowsFoundation_IPrope /// Represents a value in a property store. You can't implement this interface, see Remarks. public protocol WindowsFoundation_IPropertyValueProtocol: IInspectableProtocol { /// Returns the type stored in the property value. - func _type() throws -> WindowsFoundation_PropertyType + var type: WindowsFoundation_PropertyType { get throws } /// Gets a value that indicates whether the property value is a scalar value. - func _isNumericScalar() throws -> Bool + var isNumericScalar: Bool { get throws } func getUInt8() throws -> UInt8 func getInt16() throws -> Int16 @@ -49,9 +49,6 @@ public protocol WindowsFoundation_IPropertyValueProtocol: IInspectableProtocol { } extension WindowsFoundation_IPropertyValueProtocol { - public var type: WindowsFoundation_PropertyType { try! _type() } - public var isNumericScalar: Bool { try! _isNumericScalar() } - public func getUInt8() throws -> UInt8 { throw COMError.notImpl } public func getInt16() throws -> Int16 { throw COMError.notImpl } public func getUInt16() throws -> UInt16 { throw COMError.notImpl } diff --git a/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReference.swift b/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReference.swift index 8b64e01c..22c77f99 100644 --- a/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReference.swift +++ b/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReference.swift @@ -15,12 +15,7 @@ public protocol WindowsFoundation_IReferenceProtocol: WindowsFoundation_IProp associatedtype T /// Gets the type that is represented as an IPropertyValue. - func _value() throws -> T -} - -extension WindowsFoundation_IReferenceProtocol { - /// Gets the type that is represented as an IPropertyValue. - var value: T { try! _value() } + var value: T { get throws } } import SWRT_WindowsFoundation @@ -60,20 +55,22 @@ public enum WindowsFoundation_IReferenceBinding } } - public func _type() throws -> WindowsFoundation_PropertyType { - try _ipropertyValue.get_Type() + public var type: WindowsFoundation_PropertyType { + get throws { try _ipropertyValue.get_Type() } } - public func _isNumericScalar() throws -> Bool { - try _ipropertyValue.get_IsNumericScalar() + public var isNumericScalar: Bool { + get throws { try _ipropertyValue.get_IsNumericScalar() } } - public func _value() throws -> T { - var abiValue = TBinding.abiDefaultValue - try withUnsafeMutablePointer(to: &abiValue) { abiValuePointer in - try _interop.get_Value(abiValuePointer) + public var value: T { + get throws { + var abiValue = TBinding.abiDefaultValue + try withUnsafeMutablePointer(to: &abiValue) { abiValuePointer in + try _interop.get_Value(abiValuePointer) + } + return TBinding.fromABI(consuming: &abiValue) } - return TBinding.fromABI(consuming: &abiValue) } public func _getABIValue(_ pointer: UnsafeMutableRawPointer) throws { diff --git a/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReferenceArray.swift b/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReferenceArray.swift index e60adee1..82140fd3 100644 --- a/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReferenceArray.swift +++ b/Support/Sources/WindowsRuntime/Projection/WindowsFoundation/WindowsFoundation_IReferenceArray.swift @@ -11,12 +11,7 @@ public protocol WindowsFoundation_IReferenceArrayProtocol: WindowsFoundation_ associatedtype T /// Gets the type that is represented as an IPropertyValue. - func _value() throws -> [T] -} - -extension WindowsFoundation_IReferenceArrayProtocol { - /// Gets the type that is represented as an IPropertyValue. - var value: [T] { try! _value() } + var value: [T] { get throws } } import SWRT_WindowsFoundation @@ -53,24 +48,26 @@ public enum WindowsFoundation_IReferenceArrayBinding WindowsFoundation_PropertyType { - try _ipropertyValue.get_Type() + public var type: WindowsFoundation_PropertyType { + get throws { try _ipropertyValue.get_Type() } } - public func _isNumericScalar() throws -> Bool { - try _ipropertyValue.get_IsNumericScalar() + public var isNumericScalar: Bool { + get throws { try _ipropertyValue.get_IsNumericScalar() } } - public func _value() throws -> [T] { - var length: UInt32 = 0 - var pointer: UnsafeMutableRawPointer? = nil - try _interop.get_Value(&length, &pointer) - guard let pointer else { return [] } - - var abiValue = COMArray( - pointer: pointer.bindMemory(to: TBinding.ABIValue.self, capacity: Int(length)), - count: length) - return ArrayBinding.fromABI(consuming: &abiValue) + public var value: [T] { + get throws { + var length: UInt32 = 0 + var pointer: UnsafeMutableRawPointer? = nil + try _interop.get_Value(&length, &pointer) + guard let pointer else { return [] } + + var abiValue = COMArray( + pointer: pointer.bindMemory(to: TBinding.ABIValue.self, capacity: Int(length)), + count: length) + return ArrayBinding.fromABI(consuming: &abiValue) + } } public func _getABIValue(_ length: inout UInt32, _ pointer: inout UnsafeMutableRawPointer?) throws { diff --git a/Support/Sources/WindowsRuntime/ReferenceArrayImpl.swift b/Support/Sources/WindowsRuntime/ReferenceArrayImpl.swift index 25943e9f..05b79cca 100644 --- a/Support/Sources/WindowsRuntime/ReferenceArrayImpl.swift +++ b/Support/Sources/WindowsRuntime/ReferenceArrayImpl.swift @@ -8,20 +8,21 @@ internal class ReferenceArrayImpl public override class var _runtimeClassName: String { "Windows.Foundation.IReferenceArray`1<\(TBinding.typeName)>" } - private let value: [TBinding.SwiftValue] + private let _value: [TBinding.SwiftValue] init(_ value: [TBinding.SwiftValue]) { - self.value = value + self._value = value super.init() } // IPropertyValue members - public func _type() throws -> WindowsFoundation_PropertyType { .otherTypeArray } - public func _isNumericScalar() throws -> Bool { false } + public var type: WindowsFoundation_PropertyType { get throws { .otherTypeArray } } + public var isNumericScalar: Bool { get throws { false } } + + public var value: [T] { get throws { _value } } - public func _value() throws -> [T] { value } public func _getABIValue(_ length: inout UInt32, _ pointer: inout UnsafeMutableRawPointer?) throws { - let abiValue = try ArrayBinding.toABI(self.value) + let abiValue = try ArrayBinding.toABI(self._value) length = abiValue.count pointer = abiValue.pointer.map { UnsafeMutableRawPointer($0) } } diff --git a/Support/Sources/WindowsRuntime/ReferenceImpl.swift b/Support/Sources/WindowsRuntime/ReferenceImpl.swift index 805ab721..e0e2b0ad 100644 --- a/Support/Sources/WindowsRuntime/ReferenceImpl.swift +++ b/Support/Sources/WindowsRuntime/ReferenceImpl.swift @@ -8,19 +8,19 @@ internal class ReferenceImpl public override class var _runtimeClassName: String { "Windows.Foundation.IReference`1<\(TBinding.typeName)>" } - private let value: TBinding.SwiftValue + private let _value: TBinding.SwiftValue init(_ value: TBinding.SwiftValue) { - self.value = value + self._value = value super.init() } // IPropertyValue members - public func _type() throws -> WindowsFoundation_PropertyType { .otherType } - public func _isNumericScalar() throws -> Bool { false } + public var type: WindowsFoundation_PropertyType { get throws { .otherType } } + public var isNumericScalar: Bool { get throws { false } } + public var value: T { get throws { _value } } - public func _value() throws -> T { value } public func _getABIValue(_ pointer: UnsafeMutableRawPointer) throws { - pointer.bindMemory(to: TBinding.ABIValue.self, capacity: 1).pointee = try TBinding.toABI(value) + pointer.bindMemory(to: TBinding.ABIValue.self, capacity: 1).pointee = try TBinding.toABI(_value) } } diff --git a/Support/Tests/IReferenceTests.swift b/Support/Tests/IReferenceTests.swift index c7913121..40c15ed6 100644 --- a/Support/Tests/IReferenceTests.swift +++ b/Support/Tests/IReferenceTests.swift @@ -4,41 +4,41 @@ import WindowsRuntime internal final class IReferenceTests: WinRTTestCase { func testPODPrimitive() throws { let ireference = try createIReference(true) - XCTAssertEqual(try ireference._value(), true) + XCTAssertEqual(try ireference.value, true) } func testAllocatingPrimitive() throws { let ireference = try createIReference("test") - XCTAssertEqual(try ireference._value(), "test") + XCTAssertEqual(try ireference.value, "test") } func testEnum() throws { let ireference = try createIReference(WindowsFoundation_PropertyType.boolean) - XCTAssertEqual(try ireference._value(), WindowsFoundation_PropertyType.boolean) + XCTAssertEqual(try ireference.value, WindowsFoundation_PropertyType.boolean) } func testStruct() throws { let ireference = try createIReference(WindowsFoundation_Point(x: 1, y: 2)) - XCTAssertEqual(try ireference._value(), WindowsFoundation_Point(x: 1, y: 2)) + XCTAssertEqual(try ireference.value, WindowsFoundation_Point(x: 1, y: 2)) } func testPODPrimitiveArray() throws { let ireferenceArray = try createIReferenceArray([true]) - XCTAssertEqual(try ireferenceArray._value(), [true]) + XCTAssertEqual(try ireferenceArray.value, [true]) } func testAllocatingPrimitiveArray() throws { let ireferenceArray = try createIReferenceArray(["test"]) - XCTAssertEqual(try ireferenceArray._value(), ["test"]) + XCTAssertEqual(try ireferenceArray.value, ["test"]) } func testEnumArray() throws { let ireferenceArray = try createIReferenceArray([WindowsFoundation_PropertyType.boolean]) - XCTAssertEqual(try ireferenceArray._value(), [WindowsFoundation_PropertyType.boolean]) + XCTAssertEqual(try ireferenceArray.value, [WindowsFoundation_PropertyType.boolean]) } func testStructArray() throws { let ireferenceArray = try createIReferenceArray([WindowsFoundation_Point(x: 1, y: 2)]) - XCTAssertEqual(try ireferenceArray._value(), [WindowsFoundation_Point(x: 1, y: 2)]) + XCTAssertEqual(try ireferenceArray.value, [WindowsFoundation_Point(x: 1, y: 2)]) } } \ No newline at end of file