Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Sources/Atoms/AtomRoot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import SwiftUI
///
public struct AtomRoot<Content: View>: View {
@StateObject
private var state: State
private var state = State()
private var overrides = Overrides()
private var observers = [Observer]()
private let content: Content
Expand All @@ -53,7 +53,6 @@ public struct AtomRoot<Content: View>: View {
///
/// - Parameter content: The content that uses atoms.
public init(@ViewBuilder content: () -> Content) {
self._state = StateObject(wrappedValue: State())
self.content = content()
}

Expand Down
46 changes: 44 additions & 2 deletions Sources/Atoms/AtomScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ import SwiftUI
/// ```
///
public struct AtomScope<Content: View>: View {
@StateObject
private var state = State()
private let store: StoreContext?
private let content: Content
private var overrides = Overrides()
private var observers = [Observer]()
private let content: Content

@Environment(\.store)
private var environmentStore
Expand Down Expand Up @@ -97,10 +100,44 @@ public struct AtomScope<Content: View>: View {
public var body: some View {
content.environment(
\.store,
(store ?? environmentStore).scoped(observers: observers)
(store ?? environmentStore).scoped(
store: state.store,
overrides: overrides,
observers: observers
)
)
}

/// Overrides the atom value with the given value.
///
/// When accessing the overridden atom, this context will create and return the given value
/// instead of the atom value.
///
/// - Parameters:
/// - atom: An atom that to be overridden.
/// - value: A value that to be used instead of the atom's value.
///
/// - Returns: The self instance.
public func override<Node: Atom>(_ atom: Node, with value: @escaping (Node) -> Node.Loader.Value) -> Self {
mutating { $0.overrides.insert(atom, with: value) }
}

/// Overrides the atom value with the given value.
///
/// Instead of overriding the particular instance of atom, this method overrides any atom that
/// has the same metatype.
/// When accessing the overridden atom, this context will create and return the given value
/// instead of the atom value.
///
/// - Parameters:
/// - atomType: An atom type that to be overridden.
/// - value: A value that to be used instead of the atom's value.
///
/// - Returns: The self instance.
public func override<Node: Atom>(_ atomType: Node.Type, with value: @escaping (Node) -> Node.Loader.Value) -> Self {
mutating { $0.overrides.insert(atomType, with: value) }
}

/// For debugging, observes updates with a snapshot that captures a specific set of values of atoms.
///
/// Use this to monitor and debugging the atoms or for producing side effects.
Expand All @@ -114,6 +151,11 @@ public struct AtomScope<Content: View>: View {
}

private extension AtomScope {
@MainActor
final class State: ObservableObject {
let store = AtomStore()
}

func `mutating`(_ mutation: (inout Self) -> Void) -> Self {
var view = self
mutation(&view)
Expand Down
12 changes: 3 additions & 9 deletions Sources/Atoms/Core/AtomCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,16 @@ internal protocol AtomCacheProtocol: CustomStringConvertible {
associatedtype Node: Atom

var atom: Node { get set }
var value: Node.Loader.Value? { get set }

func reset(with store: StoreContext)
var value: Node.Loader.Value { get set }
}

internal extension AtomCacheProtocol {
var description: String {
value.map { "\($0)" } ?? "nil"
"\(value)"
}
}

internal struct AtomCache<Node: Atom>: AtomCacheProtocol {
var atom: Node
var value: Node.Loader.Value?

func reset(with store: StoreContext) {
store.reset(atom)
}
var value: Node.Loader.Value
}
12 changes: 6 additions & 6 deletions Sources/Atoms/Core/Overrides.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@MainActor
@usableFromInline
internal struct Overrides {
private var _entriesForNode = [AtomKey: any AtomOverrideProtocol]()
private var _entriesForType = [AtomTypeKey: any AtomOverrideProtocol]()
private var entriesForNode = [AtomKey: any AtomOverrideProtocol]()
private var entriesForType = [AtomTypeKey: any AtomOverrideProtocol]()

nonisolated init() {}

Expand All @@ -10,20 +10,20 @@ internal struct Overrides {
with value: @escaping (Node) -> Node.Loader.Value
) {
let key = AtomKey(atom)
_entriesForNode[key] = AtomOverride(value: value)
entriesForNode[key] = AtomOverride(value: value)
}

mutating func insert<Node: Atom>(
_ atomType: Node.Type,
with value: @escaping (Node) -> Node.Loader.Value
) {
let key = AtomTypeKey(atomType)
_entriesForType[key] = AtomOverride(value: value)
entriesForType[key] = AtomOverride(value: value)
}

func value<Node: Atom>(for atom: Node) -> Node.Loader.Value? {
let key = AtomKey(atom)
let baseOverride = _entriesForNode[key] ?? _entriesForType[key.typeKey]
let baseOverride = entriesForNode[key] ?? entriesForType[key.typeKey]

guard let baseOverride else {
return nil
Expand Down
Loading