Skip to content

Commit

Permalink
Make findAttribute/getAttributes always return a struct for the attri…
Browse files Browse the repository at this point in the history
…bute.
  • Loading branch information
tristanlabelle committed Feb 19, 2024
1 parent 634e6e4 commit b072544
Show file tree
Hide file tree
Showing 29 changed files with 115 additions and 63 deletions.
6 changes: 3 additions & 3 deletions Sources/DotNetMetadata/Attributable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ extension Attributable {
try attributes.contains { try $0.hasType(T.self) }
}

public func findAttribute<T: AttributeType>(_ type: T.Type) throws -> T.Value? {
public func findAttribute<T: AttributeType>(_ type: T.Type) throws -> T? {
guard let attribute = try attributes.first(where: { try $0.hasType(T.self) }) else { return nil }
return try attribute.decode(as: T.self)
}

public func getAttributes<T: AttributeType>(_ type: T.Type) throws -> [T.Value] {
var result = [T.Value]()
public func getAttributes<T: AttributeType>(_ type: T.Type) throws -> [T] {
var result = [T]()
for attribute in attributes {
guard try attribute.hasType(T.self) else { continue }
result.append(try attribute.decode(as: T.self))
Expand Down
6 changes: 2 additions & 4 deletions Sources/DotNetMetadata/AttributeType.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
public protocol AttributeType {
associatedtype Value = Self

static var namespace: String? { get }
static var name: String { get }
static var validOn: AttributeTargets { get }
static var allowMultiple: Bool { get }
static var inherited: Bool { get }

static func decode(_ attribute: Attribute) throws -> Value
static func decode(_ attribute: Attribute) throws -> Self
}

extension Attribute {
Expand All @@ -16,7 +14,7 @@ extension Attribute {
return actualType.namespace == type.namespace && actualType.name == type.name
}

public func decode<T: AttributeType>(as type: T.Type) throws -> T.Value {
public func decode<T: AttributeType>(as type: T.Type) throws -> T {
try type.decode(self)
}
}
4 changes: 2 additions & 2 deletions Sources/DotNetMetadata/Attributes/ComImportAttribute.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
public enum ComImportAttribute: AttributeType {
public struct ComImportAttribute: AttributeType {
public static var namespace: String? { "System.Runtime.InteropServices" }
public static var name: String { "ComImportAttribute" }
public static var validOn: AttributeTargets { .class | .interface }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { false }

public static func decode(_ attribute: Attribute) throws -> Void { () }
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
12 changes: 9 additions & 3 deletions Sources/DotNetMetadata/Attributes/ComVisibleAttribute.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
public enum ComVisibleAttribute: AttributeType {
public struct ComVisibleAttribute: AttributeType {
public var value: Bool

public init(_ value: Bool) {
self.value = value
}

public static var namespace: String? { "System.Runtime.InteropServices" }
public static var name: String { "ComVisibleAttribute" }
public static var validOn: AttributeTargets { .assembly | .allTypes | .method | .property | .field }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { false }

public static func decode(_ attribute: Attribute) throws -> Bool {
public static func decode(_ attribute: Attribute) throws -> Self {
let arguments = try attribute.arguments
guard arguments.count == 1,
case .constant(let constant) = arguments[0],
case .boolean(let value) = constant else { throw InvalidMetadataError.attributeArguments }

return value
return .init(value)
}
}
4 changes: 2 additions & 2 deletions Sources/DotNetMetadata/Attributes/FlagsAttribute.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/// Indicates that an enumeration can be treated as a bit field; that is, a set of flags.
public enum FlagsAttribute: AttributeType {
public struct FlagsAttribute: AttributeType {
public static var namespace: String? { "System" }
public static var name: String { "FlagsAttribute" }
public static var validOn: AttributeTargets { .enum }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { false }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
12 changes: 9 additions & 3 deletions Sources/DotNetMetadata/Attributes/GuidAttribute.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
public enum GuidAttribute: AttributeType {
public struct GuidAttribute: AttributeType {
public var value: String

public init(_ value: String) {
self.value = value
}

public static var namespace: String? { "System.Runtime.InteropServices" }
public static var name: String { "GuidAttribute" }
public static var validOn: AttributeTargets { .assembly | .allTypes }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> String {
public static func decode(_ attribute: Attribute) throws -> GuidAttribute {
let arguments = try attribute.arguments
guard arguments.count == 1,
case .constant(let constant) = arguments[0],
case .string(let value) = constant else { throw InvalidMetadataError.attributeArguments }
return value
return .init(value)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import DotNetMetadata

/// Indicates that multiple instances of a custom attribute can be applied to a target.
public enum AllowMultipleAttribute: AttributeType {
public struct AllowMultipleAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "AllowMultipleAttribute" }
public static var validOn: AttributeTargets { .class }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import DotNetMetadata

/// Specifies that the type represents an API contract.
public enum ApiContractAttribute: AttributeType {
public struct ApiContractAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "ApiContractAttribute" }
public static var validOn: AttributeTargets { .enum }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import DotNetMetadata

/// Indicates the default interface for a runtime class.
public enum DefaultAttribute: AttributeType {
public struct DefaultAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "DefaultAttribute" }
public static var validOn: AttributeTargets { .none } // No attribute target for interface implementations
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }

public static func getDefaultInterface(_ class: ClassDefinition) throws -> BoundInterface? {
try `class`.baseInterfaces.first { try $0.hasAttribute(DefaultAttribute.self) }?.interface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import DotNetMetadata

/// Indicates that a method is the default overload method.
/// This attribute must be used with OverloadAttribute.
public enum DefaultOverloadAttribute: AttributeType {
public struct DefaultOverloadAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "DefaultOverloadAttribute" }
public static var validOn: AttributeTargets { .method }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import DotNetMetadata

public enum DualApiPartitionAttribute: AttributeType {
public struct DualApiPartitionAttribute: AttributeType {
public var version: Version

public init(_ version: Version) {
self.version = version
}

public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "DualApiPartitionAttribute" }
public static var validOn: AttributeTargets { .class }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Version {
public static func decode(_ attribute: Attribute) throws -> Self {
let namedArguments = try attribute.namedArguments
if namedArguments.count == 0 { return Version(major: 0, minor: 0) }
if namedArguments.count == 0 { return .init(Version(major: 0, minor: 0)) }
guard namedArguments.count <= 1,
case .field(let field) = namedArguments[0].target,
field.name == "version",
case .constant(let versionConstant) = namedArguments[0].value,
case .uint32(let versionValue) = versionConstant else { throw InvalidMetadataError.attributeArguments }
return Version(unpacking: versionValue)
return .init(Version(unpacking: versionValue))
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import DotNetMetadata

public enum ExclusiveToAttribute: AttributeType {
public struct ExclusiveToAttribute: AttributeType {
public var target: ClassDefinition

public init(_ target: ClassDefinition) {
self.target = target
}

public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "ExclusiveToAttribute" }
public static var validOn: AttributeTargets { .interface }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> ClassDefinition {
public static func decode(_ attribute: Attribute) throws -> ExclusiveToAttribute {
let arguments = try attribute.arguments
guard arguments.count == 1,
case .type(let target) = arguments[0],
let targetClass = target as? ClassDefinition else { throw InvalidMetadataError.attributeArguments }
return targetClass
return .init(targetClass)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import DotNetMetadata

/// Indicates that a type or member should be marked in metadata as experimental,
/// and consequently may not be present in the final, released version of an SDK or library.
public enum ExperimentalAttribute: AttributeType {
public struct ExperimentalAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "ExperimentalAttribute" }
public static var validOn: AttributeTargets { .allTypes }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import DotNetMetadata
import struct Foundation.UUID

public enum GuidAttribute: AttributeType {
public struct GuidAttribute: AttributeType {
public var value: UUID

public init(_ value: UUID) {
self.value = value
}

public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "GuidAttribute" }
public static var validOn: AttributeTargets { .interface | .delegate }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> UUID {
public static func decode(_ attribute: Attribute) throws -> Self {
// [Windows.Foundation.Metadata.Guid(1516535814u, 33850, 19881, 134, 91, 157, 38, 229, 223, 173, 123)]
let arguments = try attribute.arguments
guard arguments.count == 11 else { throw InvalidMetadataError.attributeArguments }
Expand All @@ -28,11 +34,11 @@ public enum GuidAttribute: AttributeType {
return value
}

return UUID(uuid: (
return .init(UUID(uuid: (
UInt8((a >> 24) & 0xFF), UInt8((a >> 16) & 0xFF), UInt8((a >> 8) & 0xFF), UInt8((a >> 0) & 0xFF),
UInt8((b >> 8) & 0xFF), UInt8((b >> 0) & 0xFF),
UInt8((c >> 8) & 0xFF), UInt8((c >> 0) & 0xFF),
rest[0], rest[1], rest[2], rest[3], rest[4], rest[5], rest[6], rest[7]
))
)))
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import DotNetMetadata

/// Indicates that the interface contains internal methods.
public enum InternalAttribute: AttributeType {
public struct InternalAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "InternalAttribute" }
public static var validOn: AttributeTargets { .none } // No attribute target for interface implementations
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import DotNetMetadata

/// Indicates the number of array elements.
public enum LengthIsAttribute: AttributeType {
public struct LengthIsAttribute: AttributeType {
public var paramIndex: Int32

public init(_ paramIndex: Int32) {
self.paramIndex = paramIndex
}

public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "LengthIsAttribute" }
public static var validOn: AttributeTargets { .param }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Int32 {
public static func decode(_ attribute: Attribute) throws -> Self {
let arguments = try attribute.arguments
guard arguments.count == 1,
case .constant(let constant) = arguments[0],
case .int32(let value) = constant else { throw InvalidMetadataError.attributeArguments }
return value
return .init(value)
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import DotNetMetadata

/// Indicates the threading model of a Windows Runtime component.
public enum MarshalingBehaviorAttribute: AttributeType {
public struct MarshalingBehaviorAttribute: AttributeType {
public var type: MarshalingType

public init(type: MarshalingType) {
self.type = type
}

public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "MarshalingBehaviorAttribute" }
public static var validOn: AttributeTargets { .class }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> MarshalingType {
public static func decode(_ attribute: Attribute) throws -> Self {
let arguments = try attribute.arguments
guard arguments.count == 1,
case .constant(let constant) = arguments[0],
case .int32(let value) = constant,
let marshalingType = MarshalingType(rawValue: value) else { throw InvalidMetadataError.attributeArguments }
return marshalingType
return .init(type: marshalingType)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import DotNetMetadata

/// Indicates that the interface contains protected methods.
public enum NoExceptionAttribute: AttributeType {
public struct NoExceptionAttribute: AttributeType {
public static var namespace: String? { "Windows.Foundation.Metadata" }
public static var name: String { "NoExceptionAttribute" }
public static var validOn: AttributeTargets { .method | .property }
public static var allowMultiple: Bool { false }
public static var inherited: Bool { true }

public static func decode(_ attribute: Attribute) throws -> Void {}
public static func decode(_ attribute: Attribute) throws -> Self { .init() }
}
Loading

0 comments on commit b072544

Please sign in to comment.