diff --git a/Sources/ConcurrencyExtras/AnyHashableSendable.swift b/Sources/ConcurrencyExtras/AnyHashableSendable.swift index e4a510b..c7691fb 100644 --- a/Sources/ConcurrencyExtras/AnyHashableSendable.swift +++ b/Sources/ConcurrencyExtras/AnyHashableSendable.swift @@ -5,6 +5,12 @@ public struct AnyHashableSendable: Hashable, Sendable { public let base: any Hashable & Sendable + /// Creates a type-erased hashable, sendable value that wraps the given instance. + @_disfavoredOverload + public init(_ base: any Hashable & Sendable) { + self.init(base) + } + /// Creates a type-erased hashable, sendable value that wraps the given instance. public init(_ base: some Hashable & Sendable) { if let base = base as? AnyHashableSendable { @@ -40,3 +46,33 @@ extension AnyHashableSendable: CustomStringConvertible { String(describing: base) } } + +extension AnyHashableSendable: _HasCustomAnyHashableRepresentation { + public func _toCustomAnyHashable() -> AnyHashable? { + base as? AnyHashable + } +} + +extension AnyHashableSendable: ExpressibleByBooleanLiteral { + public init(booleanLiteral value: Bool) { + self.init(value) + } +} + +extension AnyHashableSendable: ExpressibleByFloatLiteral { + public init(floatLiteral value: Double) { + self.init(value) + } +} + +extension AnyHashableSendable: ExpressibleByIntegerLiteral { + public init(integerLiteral value: Int) { + self.init(value) + } +} + +extension AnyHashableSendable: ExpressibleByStringLiteral { + public init(stringLiteral value: String) { + self.init(value) + } +} diff --git a/Tests/ConcurrencyExtrasTests/AnyHashableSendableTests.swift b/Tests/ConcurrencyExtrasTests/AnyHashableSendableTests.swift index 488d6b7..80eb747 100644 --- a/Tests/ConcurrencyExtrasTests/AnyHashableSendableTests.swift +++ b/Tests/ConcurrencyExtrasTests/AnyHashableSendableTests.swift @@ -15,4 +15,25 @@ final class AnyHashableSendableTests: XCTestCase { XCTAssertEqual(flat, nested) } + + func testExistential() { + let base: (any Hashable & Sendable)? = 1 + let wrapped = base.map(AnyHashableSendable.init) + XCTAssertEqual(wrapped, AnyHashableSendable(1)) + } + + func testAnyHashable() { + XCTAssertEqual(AnyHashableSendable(1), 1 as AnyHashable) + } + + func testLiterals() { + XCTAssertEqual(AnyHashableSendable(true), true) + XCTAssertEqual(AnyHashableSendable(1), 1) + XCTAssertEqual(AnyHashableSendable(4.2), 4.2) + XCTAssertEqual(AnyHashableSendable("Blob"), "Blob") + + let bool: AnyHashableSendable = true + XCTAssertEqual(bool.base as? Bool, true) + XCTAssertEqual(bool as AnyHashable as? Bool, true) + } }