namespace MoShiro.Protocol; /// 按 逐行构造一个 (用于测试、模拟器和离线工具,不用于节点热路径)。 public sealed class StreamBuilder { private readonly StreamSpec _spec; private readonly List[] _values; private readonly List[] _valid; public StreamBuilder(StreamSpec spec) { _spec = spec; _values = new List[spec.Columns.Count]; _valid = new List[spec.Columns.Count]; for (int i = 0; i < _values.Length; i++) { _values[i] = []; _valid[i] = []; } } public int Count { get; private set; } /// 添加一行;null 表示缺失值(只允许用于可空列)。 public StreamBuilder Add(params long?[] row) { if (row.Length != _values.Length) { throw new ArgumentException($"stream {_spec.Name} expects {_values.Length} values, got {row.Length}", nameof(row)); } for (int i = 0; i < row.Length; i++) { if (row[i] is null && !_spec.Columns[i].Nullable) { throw new ArgumentException($"column {_spec.Columns[i].Name} is not nullable", nameof(row)); } _values[i].Add(row[i] ?? 0); _valid[i].Add(row[i] is not null); } Count++; return this; } public RawStream Build() { var columns = new List(_values.Length); for (int i = 0; i < _values.Length; i++) { ColumnSpec spec = _spec.Columns[i]; columns.Add(new RawColumn(spec.Name, spec.Type, spec.Enc, spec.Nullable, spec.Role, [.. _values[i]], spec.Nullable ? [.. _valid[i]] : null)); } return new RawStream(_spec.Name, Count, columns); } }