Skip to content

Commit

Permalink
Add support for progress reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-strecker-sonarsource committed Jan 2, 2024
1 parent f31033e commit c7badca
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 27 deletions.
23 changes: 14 additions & 9 deletions ProtoBuf.Logic/MessageBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

namespace ProtoBuf.Logic
{
internal class BindingContext
{
public ConcurrentDictionary<(Type_Context, string names), ParserRuleContext?> TypeBindingCache { get; } = new();
public ConcurrentDictionary<(MessageDefContext? messageDef, int fieldIndex), FieldContext?> FieldCache { get; } = new();
}

internal class MessageBinder : IMessage
{
enum FieldType
Expand All @@ -17,16 +23,14 @@ enum FieldType
Packed
}

public MessageBinder(ProtoContext protoContext, MessageDefContext? messageDef) : this(protoContext, messageDef, null) { }

private MessageBinder(ProtoContext protoContext, MessageDefContext? messageDef, ConcurrentDictionary<(Type_Context, string names), ParserRuleContext?>? cache)
public MessageBinder(ProtoContext protoContext, MessageDefContext? messageDef, BindingContext bindingContext)
{
ProtoContext = protoContext;
MessageDef = messageDef;
BindingCache = cache ?? new();
BindingContext = bindingContext ?? new();
}

private ConcurrentDictionary<(Type_Context, string names), ParserRuleContext?> BindingCache { get; }
private BindingContext BindingContext { get; }
public ProtoContext ProtoContext { get; }
public MessageDefContext? MessageDef { get; }
public TypedMessage? Result { get; private set; }
Expand All @@ -39,7 +43,8 @@ public void MergeFrom(CodedInputStream input)
while (input.Position < targetPosition && !input.IsAtEnd)
{
var (index, type) = input.ReadWireTag();
var field = MessageDef?.messageBody().messageElement().Select(x => x.field()).FirstOrDefault(x => int.TryParse(x?.fieldNumber()?.GetText(), out var i) && i == index);
var field = BindingContext.FieldCache.GetOrAdd((MessageDef, index),
key => key.messageDef?.messageBody().messageElement().Select(x => x.field()).FirstOrDefault(x => int.TryParse(x?.fieldNumber()?.GetText(), out var i) && i == key.fieldIndex));
var parsedFields = MessageDef != null && field != null && FitsFieldType(type, field.type_()) is var fieldType and not FieldType.Unknown
? ParseField(input, fieldType, field)
: ParseUnknownField(input, new WireTag(index, type));
Expand Down Expand Up @@ -184,15 +189,15 @@ static IEnumerable<string> DottedNames(EnumTypeContext message)
{
var namesString = string.Join(".", names);
var key = (expectedType, namesString);
if (BindingCache.TryGetValue(key, out var cached))
if (BindingContext.TypeBindingCache.TryGetValue(key, out var cached))
{
return cached;
}
else
{
var result = BindType(names, expectedType, names => new MessageDefBinder(names)) as ParserRuleContext
?? BindType(names, expectedType, names => new EnumDefBinder(names));
BindingCache.TryAdd(key, result);
BindingContext.TypeBindingCache.TryAdd(key, result);
return result;
}
}
Expand All @@ -211,7 +216,7 @@ static IEnumerable<string> DottedNames(EnumTypeContext message)

private ProtoType? ParseMessage(CodedInputStream stream, MessageDefContext? messageDef)
{
var builder = new MessageBinder(ProtoContext, messageDef, BindingCache);
var builder = new MessageBinder(ProtoContext, messageDef, BindingContext);
stream.ReadRawMessage(builder);
return builder.Result;
}
Expand Down
16 changes: 11 additions & 5 deletions ProtoBuf.Logic/TypedMessageDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,22 @@ public sealed record class TypedField(string Name, int Index, ParserRuleContext?

public class TypedMessageDecoder
{
public IReadOnlyList<TypedMessage> Parse(CodedInputStream stream, ProtoContext protoContext, MessageDefContext initialMessage)
public async Task<IReadOnlyList<TypedMessage>> Parse(CodedInputStream stream, Func<double, Task> progress, ProtoContext protoContext, MessageDefContext initialMessage)
{
var result = new List<TypedMessage>();
var context = new BindingContext();
while (!stream.IsAtEnd)
{
var binder = new MessageBinder(protoContext, initialMessage);
stream.ReadRawMessage(binder);
if (binder.Result != null)
var message = await Task.Run(async () =>
{
result.Add(binder.Result);
await progress((double)(stream.Position * 100) / stream.SizeLimit);
var binder = new MessageBinder(protoContext, initialMessage, context);
stream.ReadRawMessage(binder);
return binder.Result;
});
if (message != null)
{
result.Add(message);
}
}
return result;
Expand Down
4 changes: 2 additions & 2 deletions ProtoBufTests/TypedMessageDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ private static IReadOnlyList<TypedMessage> ParseBinary(string pbFile, string pro
var decoder = new TypedMessageDecoder();
var proto = ProtoParser.ParseFile("AnalyzerReport.proto");
var tokenTypeInfo = proto.topLevelDef().Where(x => x.messageDef()?.messageName().GetText() == protoDefinition).First().messageDef();
var actual = decoder.Parse(stream, proto, tokenTypeInfo);
return actual;
var actual = decoder.Parse(stream, async _ => { }, proto, tokenTypeInfo);
return actual.Result;
}
}
}
8 changes: 6 additions & 2 deletions ProtoBufViewer.Blazor/Components/VirtualTreeView.razor
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
@using MudBlazor.Utilities
@typeparam T

<ul>
<ul class="@(TreeViewClassname())">
<Virtualize Items="viewList" ItemSize="40" Context="viewListItem">
<li @key="@(viewListItem.Key)" style="flex-shrink:0;margin-left:@(viewListItem.Level * 32)pt;height:30pt;" class="@(ListItemClassname())">
<li @key="@(viewListItem.Key)" style="flex-shrink: 0; margin-left: @(viewListItem.Level * 32)pt; height: 30pt;" class="@(ListItemClassname())">
<div class="@(ContentClassname(false))">
<MudTreeViewItemToggleButton Visible="ChildrenSelector?.Invoke(viewListItem.Item)?.Count > 0" Expanded="@viewListItem.IsExpanded" ExpandedChanged="newIsExpanded => OnClick(newIsExpanded, viewListItem)" />
@if (ItemTemplate == null)
Expand All @@ -29,4 +29,8 @@
.AddClass("cursor-pointer", false)
.AddClass("mud-treeview-item-selected", isSelected)
.Build();

protected string TreeViewClassname() =>
new CssBuilder("mud-treeview")
.Build();
}
23 changes: 19 additions & 4 deletions ProtoBufViewer.Blazor/Pages/Index.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Google.Protobuf;
using Microsoft.AspNetCore.Components.Forms;
using ProtoBuf.Logic;
using System.Diagnostics;
using static ProtoBuf.Antlr.Protobuf3Parser;

namespace ProtoBufViewer.Blazor.Pages
Expand All @@ -13,6 +14,7 @@ public partial class Index
HashSet<MessageViewModel> Messages { get; } = new();
MessageViewModel? SelectedMessage { get; set; }
ProtoContext? ParseResult { get; set; }
public double? Progress { get; set; }

List<ProtoType>? TypedMessages { get; set; }

Expand All @@ -34,14 +36,27 @@ private async Task MessageFileChanged(IBrowserFile file)

private async Task BinFilesChanged(IBrowserFile file)
{
if (ParseResult == null || SelectedMessage == null) return;
ProtoBinFile = file;
using var ms = new MemoryStream();
await file.OpenReadStream().CopyToAsync(ms);
using var ms = new MemoryStream(capacity: (int)file.Size);
Progress = 0;
await file.OpenReadStream(maxAllowedSize: file.Size).CopyToAsync(ms);
ms.Position = 0;
using var coded = CodedInputStream.CreateWithLimits(ms, int.MaxValue, int.MaxValue);
using var coded = CodedInputStream.CreateWithLimits(ms, (int)ms.Length, int.MaxValue);
var decoder = new TypedMessageDecoder();
var result = decoder.Parse(coded, ParseResult, SelectedMessage.MessageDefContext);
var lastRender = Stopwatch.StartNew();
var result = await decoder.Parse(coded, async progress =>
{
Progress = progress;
if (lastRender.ElapsedMilliseconds > 1000)
{
lastRender = Stopwatch.StartNew();
this.StateHasChanged();
await Task.Delay(50);
}
}, ParseResult, SelectedMessage.MessageDefContext);
TypedMessages = new(result);
Progress = null;
}
}
}
14 changes: 11 additions & 3 deletions ProtoBufViewer.Blazor/Pages/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@
@using ProtoBuf.Logic
@using static ProtoBuf.Antlr.Protobuf3Parser

<PageTitle>Protobuf Viewer</PageTitle>

<MudGrid>
<MudItem xs="12">
<PageTitle>Protobuf Viewer</PageTitle>
<MudItem xxl="12" xs="12">
@if (Progress.HasValue)
{
<MudProgressLinear Value="@Progress.Value" Color="Color.Primary" Class="mt-1"/>
}
else
{
<div class="mt-2" />
}
</MudItem>
<MudItem xs="12" sm="4">
<MudFileUpload T="IBrowserFile" Accept="*.proto" FilesChanged="MessageFileChanged" Hidden="@false" InputClass="absolute mud-width-full mud-height-full overflow-hidden z-20" InputStyle="opacity:0">
Expand Down Expand Up @@ -58,7 +66,7 @@
}
else
{
<MudFileUpload T="IBrowserFile" FilesChanged="BinFilesChanged" Hidden="@false" InputClass="absolute mud-width-full mud-height-full overflow-hidden z-20" InputStyle="opacity:0">
<MudFileUpload T="IBrowserFile" FilesChanged="BinFilesChanged" Hidden="@false" InputClass="absolute mud-width-full mud-height-full overflow-hidden z-20" InputStyle="opacity:0" >
<ButtonTemplate>
@if (ProtoBinFile == null)
{
Expand Down
4 changes: 2 additions & 2 deletions ProtoBufViewer.WPF/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private void OpenBinary()
}
}

private void ParseBinary()
private async Task ParseBinary()
{
TypedMessages = null;
try
Expand All @@ -149,7 +149,7 @@ private void ParseBinary()
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read);
using var coded = CodedInputStream.CreateWithLimits(fs, int.MaxValue, int.MaxValue);
var decoder = new TypedMessageDecoder();
TypedMessages = decoder.Parse(coded, protoContext, messageDefContext);
TypedMessages = await decoder.Parse(coded, async _ => { }, protoContext, messageDefContext);
}
}
catch (Exception ex)
Expand Down

0 comments on commit c7badca

Please sign in to comment.