Tokamak/Sources/TokamakCore/Environment/Environment.swift

58 lines
1.8 KiB
Swift

// Copyright 2020 Tokamak contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// A protocol that allows the conforming type to access values from the `EnvironmentValues`.
/// (e.g. `Environment` and `EnvironmentObject`)
///
/// `EnvironmentValues` are injected in 2 places:
/// 1. `View.makeMountedView`
/// 2. `MountedHostView.update` when reconciling
///
@_spi(TokamakCore)
public protocol _EnvironmentReader {
mutating func _setContent(from values: EnvironmentValues)
}
@propertyWrapper
public struct Environment<Value>: DynamicProperty {
enum Content {
case keyPath(KeyPath<EnvironmentValues, Value>)
case value(Value)
}
private var content: Content
private let keyPath: KeyPath<EnvironmentValues, Value>
public init(_ keyPath: KeyPath<EnvironmentValues, Value>) {
content = .keyPath(keyPath)
self.keyPath = keyPath
}
public mutating func _setContent(from values: EnvironmentValues) {
content = .value(values[keyPath: keyPath])
}
public var wrappedValue: Value {
switch content {
case let .value(value):
return value
case let .keyPath(keyPath):
// not bound to a view, return the default value.
return EnvironmentValues()[keyPath: keyPath]
}
}
}
@_spi(TokamakCore)
extension Environment: _EnvironmentReader {}