diff --git a/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/GeneratorTests.cs b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/GeneratorTests.cs index ca3546c..8dbba9f 100644 --- a/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/GeneratorTests.cs +++ b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/GeneratorTests.cs @@ -19,6 +19,7 @@ static GeneratorTests() protected abstract string SnapshotExtension { get; } protected abstract string GenerateRaw(ParsedContracts contracts); + [MustUseReturnValue] protected string Generate(MessageDefinition message) { var contracts = new ParsedContracts(); @@ -26,6 +27,7 @@ protected string Generate(MessageDefinition message) return Generate(contracts); } + [MustUseReturnValue] protected string Generate(ParsedContracts contracts) { PreProcess(contracts); @@ -40,7 +42,6 @@ protected string Generate(ParsedContracts contracts) return result; } - [MustUseReturnValue] protected Task Verify(MessageDefinition message) { var contracts = new ParsedContracts(); @@ -48,7 +49,6 @@ protected Task Verify(MessageDefinition message) return Verify(contracts); } - [MustUseReturnValue] protected async Task Verify(ParsedContracts contracts) { PreProcess(contracts); diff --git a/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ProtoGeneratorTests.cs b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ProtoGeneratorTests.cs index 9ab1152..138050a 100644 --- a/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ProtoGeneratorTests.cs +++ b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ProtoGeneratorTests.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Abc.Zebus.MessageDsl.Analysis; using Abc.Zebus.MessageDsl.Ast; using Abc.Zebus.MessageDsl.Generator; using Abc.Zebus.MessageDsl.Tests.TestTools; @@ -190,6 +191,31 @@ public async Task should_handle_message_inheritance() code.ShouldContain("optional MsgC _subTypeMsgC = 11;"); } + [Test] + public async Task should_generate_reservations() + { + await Verify(new MessageDefinition + { + Name = "MsgA", + Parameters = + { + new ParameterDefinition("int?", "foo"), + }, + ReservedRanges = + { + new ReservationRange(2), + new ReservationRange(10, 15), + new ReservationRange(8, 14), + new ReservationRange(16), + new ReservationRange(42) + }, + Options = + { + Proto = true + } + }); + } + protected override string SnapshotExtension => "proto"; protected override string GenerateRaw(ParsedContracts contracts) diff --git a/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ReservationRangeTests.cs b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ReservationRangeTests.cs new file mode 100644 index 0000000..14b4f1e --- /dev/null +++ b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/ReservationRangeTests.cs @@ -0,0 +1,18 @@ +using Abc.Zebus.MessageDsl.Analysis; +using Abc.Zebus.MessageDsl.Tests.TestTools; +using NUnit.Framework; + +namespace Abc.Zebus.MessageDsl.Tests.MessageDsl; + +[TestFixture] +public class ReservationRangeTests +{ + [Test] + public void should_compress_ranges() + { + ReservationRange.Compress([new(2, 4), new(3, 5), new(6, 7), new(10, 12)]) + .ShouldEqual([new(2, 7), new(10, 12)]); + + ReservationRange.Compress([]).ShouldEqual([]); + } +} diff --git a/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/Snapshots/ProtoGeneratorTests.should_generate_reservations.verified.proto b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/Snapshots/ProtoGeneratorTests.should_generate_reservations.verified.proto new file mode 100644 index 0000000..69bb2a9 --- /dev/null +++ b/src/Abc.Zebus.MessageDsl.Tests/MessageDsl/Snapshots/ProtoGeneratorTests.should_generate_reservations.verified.proto @@ -0,0 +1,11 @@ + +// Generated by Abc.Zebus.MessageDsl v1.2.3.4 + +import "servicebus.proto"; + +message MsgA { + option (servicebus.message).type = Event; + + reserved 2, 8 to 16, 42; + optional int32 Foo = 1; +} diff --git a/src/Abc.Zebus.MessageDsl/Analysis/ReservationRange.cs b/src/Abc.Zebus.MessageDsl/Analysis/ReservationRange.cs index 5cb80eb..3658e07 100644 --- a/src/Abc.Zebus.MessageDsl/Analysis/ReservationRange.cs +++ b/src/Abc.Zebus.MessageDsl/Analysis/ReservationRange.cs @@ -1,4 +1,7 @@ -using Abc.Zebus.MessageDsl.Ast; +using System; +using System.Collections.Generic; +using System.Linq; +using Abc.Zebus.MessageDsl.Ast; namespace Abc.Zebus.MessageDsl.Analysis; @@ -6,6 +9,9 @@ internal readonly struct ReservationRange(int startTag, int endTag) { public static ReservationRange None => default; + public int StartTag => startTag; + public int EndTag => endTag; + private bool IsValid => startTag > 0; public ReservationRange(int tag) @@ -37,6 +43,32 @@ public void AddToMessage(MessageDefinition message) message.ReservedRanges.Add(this); } + public static IEnumerable Compress(IEnumerable ranges) + { + var startTag = 0; + var endTag = 0; + + foreach (var range in ranges.Where(i => i.IsValid).OrderBy(i => i.StartTag)) + { + if (startTag == 0) + { + startTag = range.StartTag; + endTag = range.EndTag; + } + + if (range.StartTag > endTag + 1) + { + yield return new ReservationRange(startTag, endTag); + startTag = range.StartTag; + } + + endTag = Math.Max(endTag, range.EndTag); + } + + if (startTag != 0) + yield return new ReservationRange(startTag, endTag); + } + public override string ToString() => IsValid ? startTag != endTag diff --git a/src/Abc.Zebus.MessageDsl/Generator/ProtoGenerator.cs b/src/Abc.Zebus.MessageDsl/Generator/ProtoGenerator.cs index 77d14d1..d9bc28d 100644 --- a/src/Abc.Zebus.MessageDsl/Generator/ProtoGenerator.cs +++ b/src/Abc.Zebus.MessageDsl/Generator/ProtoGenerator.cs @@ -85,6 +85,7 @@ private void WriteMessage(MessageDefinition message) using (Block()) { WriteMessageOptions(message); + WriteReservedFields(message); foreach (var param in message.Parameters) WriteField(param); @@ -109,6 +110,30 @@ private void WriteMessageOptions(MessageDefinition message) } } + private void WriteReservedFields(MessageDefinition message) + { + if (message.ReservedRanges.Count == 0) + return; + + Writer.Write("reserved "); + var first = true; + + foreach (var reservation in ReservationRange.Compress(message.ReservedRanges)) + { + if (first) + first = false; + else + Writer.Write(", "); + + if (reservation.StartTag == reservation.EndTag) + Writer.Write(reservation.StartTag); + else + Writer.Write("{0} to {1}", reservation.StartTag, reservation.EndTag); + } + + Writer.WriteLine(";"); + } + private void WriteField(ParameterDefinition param) { Writer.Write(