Right. The idea is that you write this:
@propertyWrapper
struct Clamped<Value: Comparable> {
@shared private var bounds: Range<Value>
private var value: Value
init(wrappedValue: Value, @shared _: Range<Value>) {
// There must be a @shared initializer that's at least as
// accessible as this which has exactly the same parameters
// as this initializer's @shared parameters.
// This body can refer to @shared properties, but not directly
// to its @shared parameters.
...
}
@shared init(_ bounds: Range<Value>) {
// This body must initialize the @shared stored properties
// and cannot use any non-@shared members.
self.bounds = bounds
}
var wrappedValue: Value {
get { value }
set { value = bounds.clamping(newValue) }
}
}
That definition gets rewritten/lowered to something functionally like this:
extension Clamped {
struct Shared {
// @shared instance properties from the original type go here.
private var bounds: Range<Value>
// @shared initializers from the original type go here.
init(_ bounds: Range<Value>) {
self.bounds = bounds
}
}
struct Instance {
// Non-@shared instance properties from the original type go here.
private var value: Value
// Non-@shared initializers from the original type go here.
// @shared parameters are removed and replaced with an
// implicit _shared parameter. References to @shared
// properties in the body are rewritten to use the implicit
// _shared parameter.
init(wrappedValue: Value, _shared: UnsafePointer<Shared>) { ... }
// No other methods go here.
}
struct Composite {
// Static stored properties from the original type go here.
// The instance properties are always exactly as follows:
var _shared: UnsafePointer<Shared>
var _instance: UnsafeMutablePointer<Instance>
// Methods from the original type go here. References to
// shared properties are rewritten to use _shared.
// References to instance properties are rewritten to use
// _instance.
var wrappedValue: Value {
get { _instance.pointee.value }
set { _instance.pointee.value = _shared.pointee.bounds.clamping(newValue) }
}
}
}
Then if you have a use site:
@Clamped(1..<1024) var count: Int
This would get lowered like so:
static var count$shared = Clamped<Int>.Shared(1..<1024)
var count$instance: Clamped<Int>.Instance
var count: Clamped<Int>.Composite {
_read {
yield Clamped.Composite(_shared: &count$shared,
_instance: &count$instance)
}
_modify {
var temp = Clamped.Composite(_shared: &count$shared,
_instance: &count$instance)
yield &temp
}
}