Code/Core/Contexts/ExecutionContext/ExecutionContext.Persistence.cs
using System.Runtime.CompilerServices;
namespace Nodebox;
public partial class ExecutionContext {
public PersistentStore Store { get; set; } = new();
public class PersistentStore {
private readonly ConditionalWeakTable<Node, List<object>> _inputs = [];
private readonly ConditionalWeakTable<Node, List<object>> _outputs = [];
private List<object> GetInputsFor(Node node) => _inputs.GetOrAdd(
node,
[.. node.InputPins.Select(x => TypeLibrary.GetType(x.Type).CreateDefault())]
);
private List<object> GetOutputsFor(Node node) => _outputs.GetOrAdd(
node,
[.. node.OutputPins.Select(x => TypeLibrary.GetType(x.Type).CreateDefault())]
);
public View this[Node node] {
get => new(this, node);
}
public readonly ref struct View(PersistentStore store, Node node) {
private readonly PersistentStore _store = store;
private readonly Node _node = node;
private object GetInputObject(Type type, int index) {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.InputPins.Count, nameof(index));
// Log.Info($"{_node}[{index}] = {_node.inputValues[index]} ({_node.InputWires[index].Count})");
if (_node.InputWires[index].Count == 0) {
return _node.inputValues[index];
}
var data = _store.GetInputsFor(_node);
if (data.Count <= index) { data.Resize(index + 1, (_) => TypeLibrary.GetType(type).CreateDefault()); }
return data[index];
}
public T GetInput<T>(int index) => (T)GetInputObject(typeof(T), index);
private object GetOutputObject(int index) {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.OutputPins.Count, nameof(index));
return _store.GetOutputsFor(_node)[index];
}
public T GetOutput<T>(int index) => (T)GetOutputObject(index);
public void SetInput<T>(int index, T value) {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.InputPins.Count, nameof(index));
if (!value.GetType().IsAssignableTo(_node.InputPins[index].Type)) {
throw new InvalidCastException($"{value} is not assignable to {DisplayInfo.ForGenericType(_node.InputPins[index].Type).Name}");
}
var data = _store.GetInputsFor(_node);
if (data.Count <= index) { data.Resize(index + 1, (_) => TypeLibrary.GetType<T>().CreateDefault()); }
data[index] = value;
}
public void SetOutput<T>(int index, T value) {
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _node.OutputPins.Count, nameof(index));
if (!value.GetType().IsAssignableTo(_node.OutputPins[index].Type)) {
throw new InvalidCastException($"{value} is not assignable to {DisplayInfo.ForGenericType(_node.OutputPins[index].Type).Name}");
}
var data = _store.GetOutputsFor(_node);
if (data.Count <= index) { data.Resize(index + 1, (_) => TypeLibrary.GetType<T>().CreateDefault()); }
data[index] = value;
}
}
}
}