Close, but subscripts can't be named, so they're uglier than methods and aren't accessible directly as closures. There is no way to get this syntax
var integer: UInt64 = 0x123
integer.nybbles[0] = 0 // integer == 0x120
let nybbles = integer.nybbles
nybbles[1] = 0 // integer == 0x100
instead of
integer[nybble: index] = nybble
// Swift doesn't even have a type to reference the get/set pair.
without a separate subscriptable type, or a hack. I very much wish we had named subscripts but C# never got them implemented either so I don't think people understand the value in them. (More than the closure problem, which properties also have, it's largely about accurate naming. Swift subscripts are like Objective-C methods in that the first parameter has to combine the name of the things you're getting, with their index. When you've got something like array.elements[index: index], it's a win to be able to simplify to array[index], but it doesn't scale.)
We don't even have set-only properties over here, or a way to built-in way to grab a computed property's get/set pair (key paths are still appreciated), so I have zero hope.
public extension BinaryInteger {
var nybbles: ValueSubscript<Self, Int, Self> {
mutating get {
.init(
&self,
get: { integer in
{ index in
integer >> (index * 4) & 0xF
}
},
set: { integer, index, newValue in
let index = index * 4
let integerWithEmptyNybble = integer & ~(0xF << index)
integer = integerWithEmptyNybble | (newValue & 0xF) << index
}
)
}
}
}
/// An emulation of the missing Swift feature of named subscripts.
/// - Note: Argument labels are not supported.
public struct ValueSubscript<Root, Index, Value> {
public typealias Pointer = UnsafeMutablePointer<Root>
public typealias Get = (Root) -> (Index) -> Value
public typealias Set = (inout Root, Index, Value) -> Void
public var pointer: Pointer
public var get: Get
public var set: Set
}
public extension ValueSubscript {
init(
_ pointer: Pointer,
get: @escaping Get,
set: @escaping Set
) {
self.pointer = pointer
self.get = get
self.set = set
}
subscript(index: Index) -> Value {
get { get(pointer.pointee)(index) }
nonmutating set { set(&pointer.pointee, index, newValue) }
}
}