Skip to content

Instantly share code, notes, and snippets.

@shaps80
Last active December 16, 2024 15:40
Show Gist options
  • Save shaps80/3cd4ec65e9a240f5ff38ef780c4366db to your computer and use it in GitHub Desktop.
Save shaps80/3cd4ec65e9a240f5ff38ef780c4366db to your computer and use it in GitHub Desktop.
import Swift
@dynamicMemberLookup
public final class Wrapper<Wrapped> {
public var wrapped: Wrapped
public subscript<T>(dynamicMember keyPath: KeyPath<Wrapped, T>) -> T {
wrapped[keyPath: keyPath]
}
public subscript<T>(dynamicMember keyPath: WritableKeyPath<Wrapped, T>) -> T {
get { wrapped[keyPath: keyPath] }
set { wrapped[keyPath: keyPath] = newValue }
}
public init(wrapped: Wrapped) {
self.wrapped = wrapped
}
}
extension Wrapper: @unchecked Sendable where Wrapped: Sendable {}
extension Wrapper: Equatable where Wrapped: Equatable {
public static func == (lhs: Wrapper, rhs: Wrapper) -> Bool {
lhs.wrapped == rhs.wrapped
}
}
extension Wrapper: Hashable where Wrapped: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(wrapped)
}
}
extension Wrapper: Comparable where Wrapped: Comparable {
public static func < (lhs: Wrapper, rhs: Wrapper) -> Bool {
lhs.wrapped < rhs.wrapped
}
}
extension Wrapper: Decodable where Wrapped: Decodable {
public convenience init(from decoder: any Decoder) throws {
self.init(wrapped: try Wrapped(from: decoder))
}
}
extension Wrapper: Encodable where Wrapped: Encodable {
public func encode(to encoder: any Encoder) throws {
try wrapped.encode(to: encoder)
}
}
extension Wrapper: CustomStringConvertible where Wrapped: CustomStringConvertible {
public var description: String { wrapped.description }
}
extension Wrapper: CustomDebugStringConvertible where Wrapped: CustomDebugStringConvertible {
public var debugDescription: String { wrapped.debugDescription }
}
extension Wrapper: ExpressibleByNilLiteral where Wrapped: ExpressibleByNilLiteral {
public convenience init(nilLiteral: ()) {
self.init(wrapped: nil)
}
}
extension Wrapper: ExpressibleByFloatLiteral where Wrapped: ExpressibleByFloatLiteral {
public convenience init(floatLiteral value: Wrapped.FloatLiteralType) {
self.init(wrapped: .init(floatLiteral: value))
}
}
extension Wrapper: ExpressibleByIntegerLiteral where Wrapped: ExpressibleByIntegerLiteral {
public convenience init(integerLiteral value: Wrapped.IntegerLiteralType) {
self.init(wrapped: .init(integerLiteral: value))
}
}
extension Wrapper: ExpressibleByBooleanLiteral where Wrapped: ExpressibleByBooleanLiteral, Wrapped.BooleanLiteralType == Bool {
public convenience init(booleanLiteral value: Bool) {
self.init(wrapped: .init(booleanLiteral: value))
}
}
extension Wrapper: ExpressibleByStringLiteral, ExpressibleByUnicodeScalarLiteral, ExpressibleByExtendedGraphemeClusterLiteral where Wrapped: ExpressibleByStringLiteral & ExpressibleByUnicodeScalarLiteral & ExpressibleByUnicodeScalarLiteral, Wrapped.StringLiteralType == String {
public convenience init(stringLiteral value: StringLiteralType) {
self.init(wrapped: .init(stringLiteral: value))
}
}
#if canImport(Observation)
import Observation
extension Wrapper: Observable where Wrapped: Observable {}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment