diff --git a/Dashboard.Drawing/DrawQueue.cs b/Dashboard.Drawing/DrawQueue.cs index 120bda5..9f04a20 100644 --- a/Dashboard.Drawing/DrawQueue.cs +++ b/Dashboard.Drawing/DrawQueue.cs @@ -1,11 +1,14 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.IO; +using System.Runtime.CompilerServices; namespace Dashboard.Drawing { - public class DrawQueue : IDisposable + public class DrawQueue : IEnumerable, IDisposable { private readonly HashList _extensions = new HashList(); private readonly HashList _commands = new HashList(); @@ -118,6 +121,10 @@ namespace Dashboard.Drawing } } + public Enumerator GetEnumerator() => new Enumerator(this); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + private static int ToVlq(int value, Span bytes) { if (value < 0) @@ -125,8 +132,13 @@ namespace Dashboard.Drawing else if (bytes.Length < 5) throw new ArgumentOutOfRangeException(nameof(bytes), "Must at least be five bytes long."); - int i; + if (value == 0) + { + bytes[0] = 0; + return 1; + } + int i; for (i = 0; i < 5 && value != 0; i++, value >>= 7) { if (i > 0) @@ -138,21 +150,25 @@ namespace Dashboard.Drawing return i; } - private static int FromVlq(ReadOnlySpan bytes) + private static int FromVlq(ReadOnlySpan bytes, out int value) { - int value = 0; + value = 0; - for (int i = 0; i < bytes.Length; i++) + int i; + for (i = 0; i < bytes.Length; i++) { byte b = bytes[i]; value = (value << 7) | b; if ((b & (1 << 7)) == 0) + { + i++; break; + } } - return value; + return i; } public void Dispose() @@ -195,8 +211,125 @@ namespace Dashboard.Drawing Write(command, bytes); } } + + public class Enumerator : ICommandFrame, IEnumerator + { + private readonly DrawQueue _queue; + private readonly byte[] _stream; + private int _length; + private int _index = -1; + private int _paramsIndex = -1; + private int _paramLength = 0; + private IDrawCommand? _current = null; + + public ICommandFrame Current => this; + + object? IEnumerator.Current => Current; + + public IDrawCommand Command => _current ?? throw new InvalidOperationException(); + + public bool HasParameters { get; private set; } + + public Enumerator(DrawQueue queue) + { + _queue = queue; + _stream = queue._commandStream.GetBuffer(); + _length = (int)queue._commandStream.Length; + } + + public bool MoveNext() + { + if (_index >= _length) + return false; + + if (_index == -1) + _index = 0; + + _index += FromVlq(_stream[_index .. (_index + 5)], out int command); + _current = _queue.Command[command]; + + HasParameters = _current.Length != 0; + + if (!HasParameters) + { + _paramsIndex = -1; + return true; + } + + int length; + if (_current.Length < 0) + { + _index += FromVlq(_stream[_index .. (_index + 5)], out length); + } + else + { + length = _current.Length; + } + + _paramsIndex = _index; + _paramLength = length; + _index += length; + + return true; + } + + public void Reset() + { + _index = -1; + _current = null; + } + + public object? GetParameter() + { + return _current?.GetParams(_queue, _stream.AsSpan(_paramsIndex, _paramLength)); + } + + public T GetParameter() + { + if (_current is IDrawCommand command) + { + return command.GetParams(_queue, _stream.AsSpan(_paramsIndex, _paramLength))!; + } + else + { + throw new InvalidOperationException(); + } + } + + public bool TryGetParameter([NotNullWhen(true)] out T? parameter) + { + if (_current is IDrawCommand command) + { + parameter = command.GetParams(_queue, _stream.AsSpan(_paramsIndex, _paramLength))!; + return true; + } + else + { + parameter = default; + return false; + } + } + + public void Dispose() + { + } + } } + public interface ICommandFrame + { + public IDrawCommand Command { get; } + + public bool HasParameters { get; } + + public object? GetParameter(); + + public T GetParameter(); + + public bool TryGetParameter([NotNullWhen(true)] out T? parameter); + } + + public interface IDrawController { /// diff --git a/tests/Dashboard.TestApplication/Program.cs b/tests/Dashboard.TestApplication/Program.cs index deb57ac..1295240 100644 --- a/tests/Dashboard.TestApplication/Program.cs +++ b/tests/Dashboard.TestApplication/Program.cs @@ -12,4 +12,12 @@ queue.Point(Vector3.Zero, 2f, fg); queue.Line(Vector3.Zero, Vector3.One * 2, 2f, bg); queue.Rect(Vector3.UnitX, 2 * Vector3.UnitX + Vector3.UnitY, fg, bg, 2f); +foreach (ICommandFrame frame in queue) +{ + Console.WriteLine("{0}", frame.Command.Name); + + if (frame.HasParameters) + Console.WriteLine("Param: {0}", frame.GetParameter()); +} + Debugger.Break();