Skip to content

Instantly share code, notes, and snippets.

@kkebo
Last active July 30, 2021 21:08
Show Gist options
  • Save kkebo/8c655297c9fafd42c36abfe4d4e557d0 to your computer and use it in GitHub Desktop.
Save kkebo/8c655297c9fafd42c36abfe4d4e557d0 to your computer and use it in GitHub Desktop.
Rust の Box 的なやつを Swift で (Box はヒープに置くことが目的、BoxObject は参照にすることが目的)
@propertyWrapper
public struct Box<Value> {
private var object: BoxObject<Value>
public var value: Value {
get { self.object.value }
set {
if !isKnownUniquelyReferenced(&self.object) {
self.object = self.object.copy()
}
self.object.value = newValue
}
}
public var wrappedValue: Value {
get { self.value }
set { self.value = newValue }
}
public init(_ value: Value) {
self.object = .init(value)
}
public init(wrappedValue: Value) {
self.init(wrappedValue)
}
}
extension Box: TextOutputStreamable {
public func write<Target>(to target: inout Target) where Target: TextOutputStream {
print(self.value, terminator: "", to: &target)
}
}
extension Box: Equatable where Value: Equatable {
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.value == rhs.value
}
}
extension Box: Comparable where Value: Comparable {
public static func < (lhs: Self, rhs: Self) -> Bool {
lhs.value < rhs.value
}
}
extension Box: Hashable where Value: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(self.value)
}
}
extension Box: Error where Value: Error {}
extension Box: Encodable where Value: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.value)
}
}
extension Box: Decodable where Value: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.init(try container.decode(Value.self))
}
}
extension Box: CustomStringConvertible where Value: CustomStringConvertible {
public var description: String { self.value.description }
}
extension Box: CustomDebugStringConvertible where Value: CustomDebugStringConvertible {
public var debugDescription: String { self.value.debugDescription }
}
public final class BoxObject<Value> {
public var value: Value
public init(_ value: Value) { self.value = value }
public func copy() -> Self {
.init(self.value)
}
}
extension BoxObject: TextOutputStreamable {
public func write<Target>(to target: inout Target) where Target: TextOutputStream {
print(self.value, terminator: "", to: &target)
}
}
extension BoxObject: Equatable where Value: Equatable {
public static func == (lhs: BoxObject, rhs: BoxObject) -> Bool {
lhs.value == rhs.value
}
}
extension BoxObject: Comparable where Value: Comparable {
public static func < (lhs: BoxObject, rhs: BoxObject) -> Bool {
lhs.value < rhs.value
}
}
extension BoxObject: Hashable where Value: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(self.value)
}
}
extension BoxObject: Error where Value: Error {}
extension BoxObject: Encodable where Value: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.value)
}
}
extension BoxObject: Decodable where Value: Decodable {
public convenience init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.init(try container.decode(Value.self))
}
}
extension BoxObject: CustomStringConvertible where Value: CustomStringConvertible {
public var description: String { self.value.description }
}
extension BoxObject: CustomDebugStringConvertible where Value: CustomDebugStringConvertible {
public var debugDescription: String { self.value.debugDescription }
}
struct Piyo {
@Box var a: Int
var b: Box<Int>
var c: BoxObject<Int>
}
var piyo = Piyo(a: 3, b: .init(4), c: .init(9))
print(piyo)
var a = piyo
a.a = 10
a.b.value = 5
a.c.value = 99
print(piyo)
print(a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment