using GFramework.Core.Abstractions.Events;
using GFramework.Core.Abstractions.StateManagement;
using GFramework.Core.Events;
namespace GFramework.Core.StateManagement;
///
/// 集中式状态容器的默认实现,用于统一管理复杂状态树的读取、归约和订阅通知。
/// 该类型定位于现有 BindableProperty 之上的可选能力,适合跨模块共享、需要统一变更入口
/// 或需要中间件/诊断能力的状态场景,而不是替代所有简单字段级响应式属性。
///
/// 状态树的根状态类型。
public sealed class Store : IStore, IStoreDiagnostics
{
///
/// Dispatch 串行化门闩。
/// 该锁保证任意时刻只有一个 action 管线在运行,从而保持状态演进顺序确定,
/// 同时避免让耗时 middleware / reducer 长时间占用状态锁。
///
private readonly object _dispatchGate = new();
///
/// 当前状态变化订阅者列表。
/// 使用显式订阅对象而不是委托链,便于处理原子初始化订阅、挂起补发和精确解绑。
///
private readonly List _listeners = [];
///
/// Store 内部所有可变状态的同步锁。
/// 该锁仅保护状态快照、订阅集合、缓存选择视图和注册表本身的短临界区访问。
///
private readonly object _lock = new();
///
/// 已注册的中间件链,按添加顺序执行。
/// Dispatch 开始时会抓取快照,因此运行中的分发不会受到后续注册变化影响。
///
private readonly List> _middlewares = [];
///
/// 按 action 具体运行时类型组织的 reducer 注册表。
/// Store 采用精确类型匹配策略,保证 reducer 执行顺序和行为保持确定性。
/// Dispatch 开始时会抓取对应 action 类型的 reducer 快照。
///
private readonly Dictionary> _reducers = [];
///
/// 已缓存的局部状态选择视图。
/// 该缓存用于避免高频访问的 Model 属性在每次 getter 调用时都创建新的选择对象。
///
private readonly Dictionary _selectionCache = [];
///
/// 用于判断状态是否发生有效变化的比较器。
///
private readonly IEqualityComparer _stateComparer;
///
/// 标记当前 Store 是否正在执行分发。
/// 该标记用于阻止同一 Store 的重入分发,避免产生难以推导的执行顺序和状态回滚问题。
///
private bool _isDispatching;
///
/// 最近一次分发的 action 类型。
///
private Type? _lastActionType;
///
/// 最近一次分发记录。
///
private StoreDispatchRecord? _lastDispatchRecord;
///
/// 最近一次真正改变状态的时间戳。
///
private DateTimeOffset? _lastStateChangedAt;
///
/// 当前 Store 持有的状态快照。
///
private TState _state;
///
/// 初始化一个新的 Store。
///
/// Store 的初始状态。
/// 状态比较器;未提供时使用 。
public Store(TState initialState, IEqualityComparer? comparer = null)
{
_state = initialState;
_stateComparer = comparer ?? EqualityComparer.Default;
}
///
/// 获取最近一次分发的 action 类型。
///
public Type? LastActionType
{
get
{
lock (_lock)
{
return _lastActionType;
}
}
}
///
/// 获取最近一次真正改变状态的时间戳。
///
public DateTimeOffset? LastStateChangedAt
{
get
{
lock (_lock)
{
return _lastStateChangedAt;
}
}
}
///
/// 获取当前状态快照。
///
public TState State
{
get
{
lock (_lock)
{
return _state;
}
}
}
///
/// 分发一个 action 并按顺序执行匹配的 reducer。
///
/// action 的具体类型。
/// 要分发的 action。
/// 当 为 时抛出。
/// 当同一 Store 发生重入分发时抛出。
public void Dispatch(TAction action)
{
ArgumentNullException.ThrowIfNull(action);
Action[] listenersSnapshot = Array.Empty>();
IStoreMiddleware[] middlewaresSnapshot = Array.Empty>();
IStoreReducerAdapter[] reducersSnapshot = Array.Empty();
IEqualityComparer stateComparerSnapshot = _stateComparer;
StoreDispatchContext? context = null;
var enteredDispatchScope = false;
lock (_dispatchGate)
{
try
{
lock (_lock)
{
EnsureNotDispatching();
_isDispatching = true;
enteredDispatchScope = true;
context = new StoreDispatchContext(action!, _state);
stateComparerSnapshot = _stateComparer;
middlewaresSnapshot = _middlewares.Count > 0
? _middlewares.ToArray()
: Array.Empty>();
reducersSnapshot = CreateReducerSnapshot(context.ActionType);
}
// middleware 和 reducer 可能包含较重的同步逻辑,因此仅持有 dispatch 串行门,
// 不占用状态锁,让读取、订阅和注册操作只在需要访问共享状态时短暂阻塞。
ExecuteDispatchPipeline(context, middlewaresSnapshot, reducersSnapshot, stateComparerSnapshot);
lock (_lock)
{
_lastActionType = context.ActionType;
_lastDispatchRecord = new StoreDispatchRecord(
context.Action,
context.PreviousState,
context.NextState,
context.HasStateChanged,
context.DispatchedAt);
if (!context.HasStateChanged)
{
return;
}
_state = context.NextState;
_lastStateChangedAt = context.DispatchedAt;
listenersSnapshot = SnapshotListenersForNotification(context.NextState);
}
}
finally
{
if (enteredDispatchScope)
{
lock (_lock)
{
_isDispatching = false;
}
}
}
}
// 始终在锁外通知订阅者,避免监听器内部读取 Store 或执行额外逻辑时产生死锁。
foreach (var listener in listenersSnapshot)
{
listener(context!.NextState);
}
}
///
/// 获取当前订阅者数量。
///
public int SubscriberCount
{
get
{
lock (_lock)
{
return _listeners.Count;
}
}
}
///
/// 获取最近一次分发记录。
///
public StoreDispatchRecord? LastDispatchRecord
{
get
{
lock (_lock)
{
return _lastDispatchRecord;
}
}
}
///
/// 订阅状态变化通知。
///
/// 状态变化时的监听器。
/// 用于取消订阅的句柄。
/// 当 为 时抛出。
public IUnRegister Subscribe(Action listener)
{
ArgumentNullException.ThrowIfNull(listener);
var subscription = new ListenerSubscription(listener);
lock (_lock)
{
_listeners.Add(subscription);
}
return new DefaultUnRegister(() => UnSubscribe(subscription));
}
///
/// 订阅状态变化通知,并立即回放当前状态。
///
/// 状态变化时的监听器。
/// 用于取消订阅的句柄。
/// 当 为 时抛出。
public IUnRegister SubscribeWithInitValue(Action listener)
{
ArgumentNullException.ThrowIfNull(listener);
var subscription = new ListenerSubscription(listener)
{
IsActive = false
};
TState currentState;
TState? pendingState = default;
var hasPendingState = false;
lock (_lock)
{
currentState = _state;
_listeners.Add(subscription);
}
try
{
listener(currentState);
}
catch
{
UnSubscribe(subscription);
throw;
}
lock (_lock)
{
if (!subscription.IsSubscribed)
{
return new DefaultUnRegister(() => { });
}
subscription.IsActive = true;
if (subscription.HasPendingState)
{
pendingState = subscription.PendingState;
hasPendingState = true;
subscription.HasPendingState = false;
subscription.PendingState = default!;
}
}
if (hasPendingState)
{
listener(pendingState!);
}
return new DefaultUnRegister(() => UnSubscribe(subscription));
}
///
/// 取消订阅指定监听器。
///
/// 需要移除的监听器。
/// 当 为 时抛出。
public void UnSubscribe(Action listener)
{
ArgumentNullException.ThrowIfNull(listener);
lock (_lock)
{
var index = _listeners.FindIndex(subscription => subscription.Listener == listener);
if (index < 0)
{
return;
}
_listeners[index].IsSubscribed = false;
_listeners.RemoveAt(index);
}
}
///
/// 创建一个用于当前状态类型的 Store 构建器。
///
/// 新的 Store 构建器实例。
public static StoreBuilder CreateBuilder()
{
return new StoreBuilder();
}
///
/// 注册一个强类型 reducer。
/// 同一 action 类型可注册多个 reducer,它们会按照注册顺序依次归约状态。
///
/// reducer 处理的 action 类型。
/// 要注册的 reducer 实例。
/// 当前 Store 实例,便于链式配置。
/// 当 为 时抛出。
public Store RegisterReducer(IReducer reducer)
{
ArgumentNullException.ThrowIfNull(reducer);
lock (_lock)
{
var actionType = typeof(TAction);
if (!_reducers.TryGetValue(actionType, out var reducers))
{
reducers = [];
_reducers[actionType] = reducers;
}
reducers.Add(new ReducerAdapter(reducer));
}
return this;
}
///
/// 使用委托快速注册一个 reducer。
///
/// reducer 处理的 action 类型。
/// 执行归约的委托。
/// 当前 Store 实例,便于链式配置。
/// 当 为 时抛出。
public Store RegisterReducer(Func reducer)
{
ArgumentNullException.ThrowIfNull(reducer);
return RegisterReducer(new DelegateReducer(reducer));
}
///
/// 添加一个 Store 中间件。
/// 中间件按添加顺序包裹 reducer 执行,可用于日志、审计或调试。
///
/// 要添加的中间件实例。
/// 当前 Store 实例,便于链式配置。
/// 当 为 时抛出。
public Store UseMiddleware(IStoreMiddleware middleware)
{
ArgumentNullException.ThrowIfNull(middleware);
lock (_lock)
{
_middlewares.Add(middleware);
}
return this;
}
///
/// 获取或创建一个带缓存的局部状态选择视图。
/// 对于会被频繁读取的 Model 只读属性,推荐使用该方法复用同一个选择实例。
///
/// 局部状态类型。
/// 缓存键,调用方应保证同一个键始终表示同一局部状态语义。
/// 状态选择委托。
/// 用于比较局部状态是否变化的比较器。
/// 稳定复用的选择视图实例。
public StoreSelection GetOrCreateSelection(
string key,
Func selector,
IEqualityComparer? comparer = null)
{
ArgumentNullException.ThrowIfNull(key);
ArgumentNullException.ThrowIfNull(selector);
lock (_lock)
{
if (_selectionCache.TryGetValue(key, out var existing))
{
if (existing is StoreSelection cachedSelection)
{
return cachedSelection;
}
throw new InvalidOperationException(
$"A cached selection with key '{key}' already exists with a different selected type.");
}
var selection = new StoreSelection(this, selector, comparer);
_selectionCache[key] = selection;
return selection;
}
}
///
/// 获取或创建一个带缓存的只读 BindableProperty 风格视图。
///
/// 局部状态类型。
/// 缓存键,调用方应保证同一个键始终表示同一局部状态语义。
/// 状态选择委托。
/// 用于比较局部状态是否变化的比较器。
/// 稳定复用的只读绑定视图。
public StoreSelection GetOrCreateBindableProperty(
string key,
Func selector,
IEqualityComparer? comparer = null)
{
return GetOrCreateSelection(key, selector, comparer);
}
///
/// 执行一次完整分发管线。
///
/// 当前分发上下文。
/// 本次分发使用的中间件快照。
/// 本次分发使用的 reducer 快照。
/// 本次分发使用的状态比较器快照。
private static void ExecuteDispatchPipeline(
StoreDispatchContext context,
IReadOnlyList> middlewares,
IReadOnlyList reducers,
IEqualityComparer stateComparer)
{
Action pipeline = () => ApplyReducers(context, reducers, stateComparer);
for (var i = middlewares.Count - 1; i >= 0; i--)
{
var middleware = middlewares[i];
var next = pipeline;
pipeline = () => middleware.Invoke(context, next);
}
pipeline();
}
///
/// 对当前 action 应用所有匹配的 reducer。
/// reducer 使用 action 的精确运行时类型进行查找,以保证匹配结果和执行顺序稳定。
///
/// 当前分发上下文。
/// 本次分发使用的 reducer 快照。
/// 本次分发使用的状态比较器快照。
private static void ApplyReducers(
StoreDispatchContext context,
IReadOnlyList reducers,
IEqualityComparer stateComparer)
{
if (reducers.Count == 0)
{
context.NextState = context.PreviousState;
context.HasStateChanged = false;
return;
}
var nextState = context.PreviousState;
// 多个 reducer 共享同一 action 类型时,后一个 reducer 以前一个 reducer 的输出作为输入,
// 从而支持按模块拆分归约逻辑,同时保持总体状态演进顺序明确。
foreach (var reducer in reducers)
{
nextState = reducer.Reduce(nextState, context.Action);
}
context.NextState = nextState;
context.HasStateChanged = !stateComparer.Equals(context.PreviousState, nextState);
}
///
/// 确保当前 Store 没有发生重入分发。
///
/// 当检测到重入分发时抛出。
private void EnsureNotDispatching()
{
if (_isDispatching)
{
throw new InvalidOperationException("Nested dispatch on the same store is not allowed.");
}
}
///
/// 从当前订阅集合中提取需要立即通知的监听器快照,并为尚未激活的初始化订阅保存待补发状态。
///
/// 本次分发后的最新状态。
/// 需要在锁外立即调用的监听器快照。
private Action[] SnapshotListenersForNotification(TState nextState)
{
if (_listeners.Count == 0)
{
return Array.Empty>();
}
var activeListeners = new List>(_listeners.Count);
foreach (var subscription in _listeners)
{
if (!subscription.IsSubscribed)
{
continue;
}
if (subscription.IsActive)
{
activeListeners.Add(subscription.Listener);
continue;
}
subscription.PendingState = nextState;
subscription.HasPendingState = true;
}
return activeListeners.Count > 0 ? activeListeners.ToArray() : Array.Empty>();
}
///
/// 为当前 action 类型创建 reducer 快照。
/// Dispatch 在离开状态锁前复制列表,以便后续在锁外执行稳定、不可变的 reducer 序列。
///
/// 当前分发的 action 类型。
/// 对应 action 类型的 reducer 快照;若未注册则返回空数组。
private IStoreReducerAdapter[] CreateReducerSnapshot(Type actionType)
{
if (!_reducers.TryGetValue(actionType, out var reducers) || reducers.Count == 0)
{
return Array.Empty();
}
return reducers.ToArray();
}
///
/// 解绑一个精确的订阅对象。
///
/// 要解绑的订阅对象。
private void UnSubscribe(ListenerSubscription subscription)
{
lock (_lock)
{
subscription.IsSubscribed = false;
_listeners.Remove(subscription);
}
}
///
/// 适配不同 action 类型 reducer 的内部统一接口。
/// Store 通过该接口在运行时按 action 具体类型执行 reducer,而不暴露内部装配细节。
///
private interface IStoreReducerAdapter
{
///
/// 使用当前 action 对状态进行一次归约。
///
/// 当前状态。
/// 分发中的 action。
/// 归约后的下一状态。
TState Reduce(TState currentState, object action);
}
///
/// 基于强类型 reducer 的适配器实现。
/// 该适配器仅负责安全地完成 object 到 action 类型的转换,然后委托给真实 reducer。
///
/// 当前适配器负责处理的 action 类型。
private sealed class ReducerAdapter(IReducer reducer) : IStoreReducerAdapter
{
///
/// 包装后的强类型 reducer 实例。
///
private readonly IReducer _reducer =
reducer ?? throw new ArgumentNullException(nameof(reducer));
///
/// 将运行时 action 转换为强类型 action 后执行归约。
///
/// 当前状态。
/// 运行时 action。
/// 归约后的下一状态。
public TState Reduce(TState currentState, object action)
{
return _reducer.Reduce(currentState, (TAction)action);
}
}
///
/// 基于委托的 reducer 适配器实现,便于快速在测试和应用代码中声明 reducer。
///
/// 当前适配器负责处理的 action 类型。
private sealed class DelegateReducer(Func reducer) : IReducer
{
///
/// 真正执行归约的委托。
///
private readonly Func _reducer =
reducer ?? throw new ArgumentNullException(nameof(reducer));
///
/// 执行一次委托归约。
///
/// 当前状态。
/// 当前 action。
/// 归约后的下一状态。
public TState Reduce(TState currentState, TAction action)
{
return _reducer(currentState, action);
}
}
///
/// 表示一个 Store 状态监听订阅。
/// 该对象用于支持初始化回放与正式订阅之间的原子衔接,避免 SubscribeWithInitValue 漏掉状态变化。
///
private sealed class ListenerSubscription(Action listener)
{
///
/// 获取订阅回调。
///
public Action Listener { get; } = listener;
///
/// 获取或设置订阅是否已激活。
/// 非激活状态表示正在执行初始化回放,此时新的状态变化会被暂存为待补发值。
///
public bool IsActive { get; set; } = true;
///
/// 获取或设置订阅是否仍然有效。
///
public bool IsSubscribed { get; set; } = true;
///
/// 获取或设置是否存在待补发的最新状态。
///
public bool HasPendingState { get; set; }
///
/// 获取或设置初始化阶段积累的最新状态。
///
public TState PendingState { get; set; } = default!;
}
}