|
| 1 | +@propertyWrapper |
| 2 | +public struct Environment<T: Sendable>: Sendable { |
| 3 | + enum _Storage { |
| 4 | + case taskLocal(TaskLocal<T>) |
| 5 | + case optionalTaskLocal(TaskLocal<T?>) |
| 6 | + } |
| 7 | + |
| 8 | + var storage: _Storage |
| 9 | + |
| 10 | + public init(requiring taskLocal: TaskLocal<T?>) { |
| 11 | + storage = .optionalTaskLocal(taskLocal) |
| 12 | + } |
| 13 | + |
| 14 | + public init(_ taskLocal: TaskLocal<T>) { |
| 15 | + storage = .taskLocal(taskLocal) |
| 16 | + } |
| 17 | + |
| 18 | + public var wrappedValue: T { |
| 19 | + switch storage { |
| 20 | + case let .taskLocal(taskLocal): return taskLocal.wrappedValue |
| 21 | + case let .optionalTaskLocal(taskLocal): |
| 22 | + guard let value = taskLocal.wrappedValue else { |
| 23 | + fatalError("No value set for \(T.self) in \(taskLocal)") |
| 24 | + } |
| 25 | + |
| 26 | + return value |
| 27 | + } |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +public extension HTML { |
| 32 | + func environment<T: Sendable>(_ taskLocal: TaskLocal<T>, _ value: T) -> _ModifiedTaskLocal<T, Self> { |
| 33 | + _ModifiedTaskLocal(wrappedContent: self, taskLocal: taskLocal, value: value) |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +public struct _ModifiedTaskLocal<T: Sendable, Content: HTML>: HTML { |
| 38 | + public typealias Tag = Content.Tag |
| 39 | + |
| 40 | + var wrappedContent: Content |
| 41 | + var taskLocal: TaskLocal<T> |
| 42 | + var value: T |
| 43 | + |
| 44 | + @_spi(Rendering) |
| 45 | + public static func _render<Renderer>(_ html: consuming _ModifiedTaskLocal<T, Content>, into renderer: inout Renderer, with context: consuming _RenderingContext) where Renderer: _HTMLRendering { |
| 46 | + html.taskLocal.withValue(html.value) { |
| 47 | + Content._render(html.wrappedContent, into: &renderer, with: context) |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + @_spi(Rendering) |
| 52 | + public static func _render<Renderer>(_ html: consuming Self, into renderer: inout Renderer, with context: consuming _RenderingContext) async throws where Renderer: _AsyncHTMLRendering { |
| 53 | + try await html.taskLocal.withValue(html.value) { |
| 54 | + try await Content._render(html.wrappedContent, into: &renderer, with: context) |
| 55 | + } |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +extension _ModifiedTaskLocal: Sendable where Content: Sendable {} |
0 commit comments