* Change event handler IDs to be longs * Update unit tests * Enable detailed errors for test app * CR: Explicitly check if we exceed Number.MAX_SAFE_INTEGER * Update ref assemblies
This commit is contained in:
parent
010ffe6121
commit
4e04b81415
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
||||||
public override Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } }
|
public override Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } }
|
||||||
public System.Threading.Tasks.Task AddComponentAsync(System.Type componentType, string domElementSelector) { throw null; }
|
public System.Threading.Tasks.Task AddComponentAsync(System.Type componentType, string domElementSelector) { throw null; }
|
||||||
public System.Threading.Tasks.Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
|
public System.Threading.Tasks.Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
|
||||||
public override System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo eventFieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
public override System.Threading.Tasks.Task DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo eventFieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
||||||
protected override void Dispose(bool disposing) { }
|
protected override void Dispose(bool disposing) { }
|
||||||
protected override void HandleException(System.Exception exception) { }
|
protected override void HandleException(System.Exception exception) { }
|
||||||
protected override System.Threading.Tasks.Task UpdateDisplayAsync(in Microsoft.AspNetCore.Components.Rendering.RenderBatch batch) { throw null; }
|
protected override System.Threading.Tasks.Task UpdateDisplayAsync(in Microsoft.AspNetCore.Components.Rendering.RenderBatch batch) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Task DispatchEventAsync(int eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs eventArgs)
|
public override Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
// Be sure we only run one event handler at once. Although they couldn't run
|
// Be sure we only run one event handler at once. Although they couldn't run
|
||||||
// simultaneously anyway (there's only one thread), they could run nested on
|
// simultaneously anyway (there's only one thread), they could run nested on
|
||||||
|
|
@ -183,12 +183,12 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
||||||
|
|
||||||
readonly struct IncomingEventInfo
|
readonly struct IncomingEventInfo
|
||||||
{
|
{
|
||||||
public readonly int EventHandlerId;
|
public readonly ulong EventHandlerId;
|
||||||
public readonly EventFieldInfo EventFieldInfo;
|
public readonly EventFieldInfo EventFieldInfo;
|
||||||
public readonly UIEventArgs EventArgs;
|
public readonly UIEventArgs EventArgs;
|
||||||
public readonly TaskCompletionSource<object> TaskCompletionSource;
|
public readonly TaskCompletionSource<object> TaskCompletionSource;
|
||||||
|
|
||||||
public IncomingEventInfo(int eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs eventArgs)
|
public IncomingEventInfo(ulong eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
EventHandlerId = eventHandlerId;
|
EventHandlerId = eventHandlerId;
|
||||||
EventFieldInfo = eventFieldInfo;
|
EventFieldInfo = eventFieldInfo;
|
||||||
|
|
|
||||||
|
|
@ -724,7 +724,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
{
|
{
|
||||||
private readonly object _dummy;
|
private readonly object _dummy;
|
||||||
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<int> DisposedComponentIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<int> DisposedComponentIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<int> DisposedEventHandlerIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<ulong> DisposedEventHandlerIDs { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame> ReferenceFrames { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<Microsoft.AspNetCore.Components.RenderTree.RenderTreeFrame> ReferenceFrames { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiff> UpdatedComponents { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
public Microsoft.AspNetCore.Components.RenderTree.ArrayRange<Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiff> UpdatedComponents { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
}
|
}
|
||||||
|
|
@ -735,7 +735,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } }
|
public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } }
|
||||||
protected internal virtual void AddToRenderQueue(int componentId, Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
|
protected internal virtual void AddToRenderQueue(int componentId, Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
|
||||||
protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; }
|
protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo fieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
public virtual System.Threading.Tasks.Task DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo fieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
protected virtual void Dispose(bool disposing) { }
|
protected virtual void Dispose(bool disposing) { }
|
||||||
protected abstract void HandleException(System.Exception exception);
|
protected abstract void HandleException(System.Exception exception);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components.RenderTree
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an entry in a tree of user interface (UI) items.
|
/// Represents an entry in a tree of user interface (UI) items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit, Pack = 4)]
|
||||||
public readonly struct RenderTreeFrame
|
public readonly struct RenderTreeFrame
|
||||||
{
|
{
|
||||||
// Note that the struct layout has to be valid in both 32-bit and 64-bit runtime platforms,
|
// Note that the struct layout has to be valid in both 32-bit and 64-bit runtime platforms,
|
||||||
|
|
@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Components.RenderTree
|
||||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Attribute"/>
|
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Attribute"/>
|
||||||
/// gets the ID of the corresponding event handler, if any.
|
/// gets the ID of the corresponding event handler, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(8)] public readonly int AttributeEventHandlerId;
|
[FieldOffset(8)] public readonly ulong AttributeEventHandlerId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Attribute"/>,
|
/// If the <see cref="FrameType"/> property equals <see cref="RenderTreeFrameType.Attribute"/>,
|
||||||
|
|
@ -267,7 +267,7 @@ namespace Microsoft.AspNetCore.Components.RenderTree
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute constructor
|
// Attribute constructor
|
||||||
private RenderTreeFrame(int sequence, string attributeName, object attributeValue, int attributeEventHandlerId, string attributeEventUpdatesAttributeName)
|
private RenderTreeFrame(int sequence, string attributeName, object attributeValue, ulong attributeEventHandlerId, string attributeEventUpdatesAttributeName)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
FrameType = RenderTreeFrameType.Attribute;
|
FrameType = RenderTreeFrameType.Attribute;
|
||||||
|
|
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.Components.RenderTree
|
||||||
internal RenderTreeFrame WithComponent(ComponentState componentState)
|
internal RenderTreeFrame WithComponent(ComponentState componentState)
|
||||||
=> new RenderTreeFrame(Sequence, componentSubtreeLength: ComponentSubtreeLength, ComponentType, componentState, ComponentKey);
|
=> new RenderTreeFrame(Sequence, componentSubtreeLength: ComponentSubtreeLength, ComponentType, componentState, ComponentKey);
|
||||||
|
|
||||||
internal RenderTreeFrame WithAttributeEventHandlerId(int eventHandlerId)
|
internal RenderTreeFrame WithAttributeEventHandlerId(ulong eventHandlerId)
|
||||||
=> new RenderTreeFrame(Sequence, attributeName: AttributeName, AttributeValue, eventHandlerId, AttributeEventUpdatesAttributeName);
|
=> new RenderTreeFrame(Sequence, attributeName: AttributeName, AttributeValue, eventHandlerId, AttributeEventUpdatesAttributeName);
|
||||||
|
|
||||||
internal RenderTreeFrame WithAttributeValue(object attributeValue)
|
internal RenderTreeFrame WithAttributeValue(object attributeValue)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components.RenderTree;
|
using Microsoft.AspNetCore.Components.RenderTree;
|
||||||
|
|
@ -30,13 +30,13 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the IDs of the event handlers that were disposed.
|
/// Gets the IDs of the event handlers that were disposed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ArrayRange<int> DisposedEventHandlerIDs { get; }
|
public ArrayRange<ulong> DisposedEventHandlerIDs { get; }
|
||||||
|
|
||||||
internal RenderBatch(
|
internal RenderBatch(
|
||||||
ArrayRange<RenderTreeDiff> updatedComponents,
|
ArrayRange<RenderTreeDiff> updatedComponents,
|
||||||
ArrayRange<RenderTreeFrame> referenceFrames,
|
ArrayRange<RenderTreeFrame> referenceFrames,
|
||||||
ArrayRange<int> disposedComponentIDs,
|
ArrayRange<int> disposedComponentIDs,
|
||||||
ArrayRange<int> disposedEventHandlerIDs)
|
ArrayRange<ulong> disposedEventHandlerIDs)
|
||||||
{
|
{
|
||||||
UpdatedComponents = updatedComponents;
|
UpdatedComponents = updatedComponents;
|
||||||
ReferenceFrames = referenceFrames;
|
ReferenceFrames = referenceFrames;
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
// Primary result data
|
// Primary result data
|
||||||
public ArrayBuilder<RenderTreeDiff> UpdatedComponentDiffs { get; } = new ArrayBuilder<RenderTreeDiff>();
|
public ArrayBuilder<RenderTreeDiff> UpdatedComponentDiffs { get; } = new ArrayBuilder<RenderTreeDiff>();
|
||||||
public ArrayBuilder<int> DisposedComponentIds { get; } = new ArrayBuilder<int>();
|
public ArrayBuilder<int> DisposedComponentIds { get; } = new ArrayBuilder<int>();
|
||||||
public ArrayBuilder<int> DisposedEventHandlerIds { get; } = new ArrayBuilder<int>();
|
public ArrayBuilder<ulong> DisposedEventHandlerIds { get; } = new ArrayBuilder<ulong>();
|
||||||
|
|
||||||
// Buffers referenced by UpdatedComponentDiffs
|
// Buffers referenced by UpdatedComponentDiffs
|
||||||
public ArrayBuilder<RenderTreeEdit> EditsBuffer { get; } = new ArrayBuilder<RenderTreeEdit>(64);
|
public ArrayBuilder<RenderTreeEdit> EditsBuffer { get; } = new ArrayBuilder<RenderTreeEdit>(64);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
{
|
{
|
||||||
internal class RenderTreeUpdater
|
internal class RenderTreeUpdater
|
||||||
{
|
{
|
||||||
public static void UpdateToMatchClientState(RenderTreeBuilder renderTreeBuilder, int eventHandlerId, object newFieldValue)
|
public static void UpdateToMatchClientState(RenderTreeBuilder renderTreeBuilder, ulong eventHandlerId, object newFieldValue)
|
||||||
{
|
{
|
||||||
// We only allow the client to supply string or bool currently, since those are the only kinds of
|
// We only allow the client to supply string or bool currently, since those are the only kinds of
|
||||||
// values we output on attributes that go to the client
|
// values we output on attributes that go to the client
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
private static readonly Action<ILogger, int, Type, Exception> _disposingComponent =
|
private static readonly Action<ILogger, int, Type, Exception> _disposingComponent =
|
||||||
LoggerMessage.Define<int, Type>(LogLevel.Debug, new EventId(4, "DisposingComponent"), "Disposing component {ComponentId} of type {ComponentType}");
|
LoggerMessage.Define<int, Type>(LogLevel.Debug, new EventId(4, "DisposingComponent"), "Disposing component {ComponentId} of type {ComponentType}");
|
||||||
|
|
||||||
private static readonly Action<ILogger, int, string, Exception> _handlingEvent =
|
private static readonly Action<ILogger, ulong, string, Exception> _handlingEvent =
|
||||||
LoggerMessage.Define<int, string>(LogLevel.Debug, new EventId(5, "HandlingEvent"), "Handling event {EventId} of type '{EventType}'");
|
LoggerMessage.Define<ulong, string>(LogLevel.Debug, new EventId(5, "HandlingEvent"), "Handling event {EventId} of type '{EventType}'");
|
||||||
|
|
||||||
public static void InitializingComponent(ILogger logger, ComponentState componentState, ComponentState parentComponentState)
|
public static void InitializingComponent(ILogger logger, ComponentState componentState, ComponentState parentComponentState)
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void HandlingEvent(ILogger<Renderer> logger, int eventHandlerId, UIEventArgs eventArgs)
|
internal static void HandlingEvent(ILogger<Renderer> logger, ulong eventHandlerId, UIEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
_handlingEvent(logger, eventHandlerId, eventArgs?.Type ?? "null", null);
|
_handlingEvent(logger, eventHandlerId, eventArgs?.Type ?? "null", null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,13 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly Dictionary<int, ComponentState> _componentStateById = new Dictionary<int, ComponentState>();
|
private readonly Dictionary<int, ComponentState> _componentStateById = new Dictionary<int, ComponentState>();
|
||||||
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder();
|
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder();
|
||||||
private readonly Dictionary<int, EventCallback> _eventBindings = new Dictionary<int, EventCallback>();
|
private readonly Dictionary<ulong, EventCallback> _eventBindings = new Dictionary<ulong, EventCallback>();
|
||||||
private readonly Dictionary<int, int> _eventHandlerIdReplacements = new Dictionary<int, int>();
|
private readonly Dictionary<ulong, ulong> _eventHandlerIdReplacements = new Dictionary<ulong, ulong>();
|
||||||
private readonly ILogger<Renderer> _logger;
|
private readonly ILogger<Renderer> _logger;
|
||||||
|
|
||||||
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
|
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
|
||||||
private bool _isBatchInProgress;
|
private bool _isBatchInProgress;
|
||||||
private int _lastEventHandlerId = 0;
|
private ulong _lastEventHandlerId;
|
||||||
private List<Task> _pendingTasks;
|
private List<Task> _pendingTasks;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -206,7 +206,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
/// A <see cref="Task"/> which will complete once all asynchronous processing related to the event
|
/// A <see cref="Task"/> which will complete once all asynchronous processing related to the event
|
||||||
/// has completed.
|
/// has completed.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public virtual Task DispatchEventAsync(int eventHandlerId, EventFieldInfo fieldInfo, UIEventArgs eventArgs)
|
public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo fieldInfo, UIEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
EnsureSynchronizationContext();
|
EnsureSynchronizationContext();
|
||||||
|
|
||||||
|
|
@ -354,7 +354,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void TrackReplacedEventHandlerId(int oldEventHandlerId, int newEventHandlerId)
|
internal void TrackReplacedEventHandlerId(ulong oldEventHandlerId, ulong newEventHandlerId)
|
||||||
{
|
{
|
||||||
// Tracking the chain of old->new replacements allows us to interpret incoming EventFieldInfo
|
// Tracking the chain of old->new replacements allows us to interpret incoming EventFieldInfo
|
||||||
// values even if they refer to an event handler ID that's since been superseded. This is essential
|
// values even if they refer to an event handler ID that's since been superseded. This is essential
|
||||||
|
|
@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
_eventHandlerIdReplacements.Add(oldEventHandlerId, newEventHandlerId);
|
_eventHandlerIdReplacements.Add(oldEventHandlerId, newEventHandlerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int FindLatestEventHandlerIdInChain(int eventHandlerId)
|
private ulong FindLatestEventHandlerIdInChain(ulong eventHandlerId)
|
||||||
{
|
{
|
||||||
while (_eventHandlerIdReplacements.TryGetValue(eventHandlerId, out var replacementEventHandlerId))
|
while (_eventHandlerIdReplacements.TryGetValue(eventHandlerId, out var replacementEventHandlerId))
|
||||||
{
|
{
|
||||||
|
|
@ -573,7 +573,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveEventHandlerIds(ArrayRange<int> eventHandlerIds, Task afterTaskIgnoreErrors)
|
private void RemoveEventHandlerIds(ArrayRange<ulong> eventHandlerIds, Task afterTaskIgnoreErrors)
|
||||||
{
|
{
|
||||||
if (eventHandlerIds.Count == 0)
|
if (eventHandlerIds.Count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -598,7 +598,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
|
|
||||||
// Factor out the async part into a separate local method purely so, in the
|
// Factor out the async part into a separate local method purely so, in the
|
||||||
// synchronous case, there's no state machine or task construction
|
// synchronous case, there's no state machine or task construction
|
||||||
async Task ContinueAfterTask(ArrayRange<int> eventHandlerIds, Task afterTaskIgnoreErrors)
|
async Task ContinueAfterTask(ArrayRange<ulong> eventHandlerIds, Task afterTaskIgnoreErrors)
|
||||||
{
|
{
|
||||||
// We need to delay the actual removal (e.g., until we've confirmed the client
|
// We need to delay the actual removal (e.g., until we've confirmed the client
|
||||||
// has processed the batch and hence can be sure not to reuse the handler IDs
|
// has processed the batch and hence can be sure not to reuse the handler IDs
|
||||||
|
|
@ -637,7 +637,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateRenderTreeToMatchClientState(int eventHandlerId, EventFieldInfo fieldInfo)
|
private void UpdateRenderTreeToMatchClientState(ulong eventHandlerId, EventFieldInfo fieldInfo)
|
||||||
{
|
{
|
||||||
var componentState = GetOptionalComponentState(fieldInfo.ComponentId);
|
var componentState = GetOptionalComponentState(fieldInfo.ComponentId);
|
||||||
if (componentState != null)
|
if (componentState != null)
|
||||||
|
|
|
||||||
|
|
@ -859,7 +859,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
Assert.Equal(0, entry.ReferenceFrameIndex);
|
Assert.Equal(0, entry.ReferenceFrameIndex);
|
||||||
});
|
});
|
||||||
AssertFrame.Attribute(referenceFrames[0], "onbar", addedHandler);
|
AssertFrame.Attribute(referenceFrames[0], "onbar", addedHandler);
|
||||||
Assert.NotEqual(0, removedEventHandlerFrame.AttributeEventHandlerId);
|
Assert.NotEqual(default, removedEventHandlerFrame.AttributeEventHandlerId);
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
new[] { removedEventHandlerFrame.AttributeEventHandlerId },
|
new[] { removedEventHandlerFrame.AttributeEventHandlerId },
|
||||||
batchBuilder.DisposedEventHandlerIDs.AsEnumerable());
|
batchBuilder.DisposedEventHandlerIDs.AsEnumerable());
|
||||||
|
|
@ -1592,7 +1592,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
Assert.Empty(result.Edits);
|
Assert.Empty(result.Edits);
|
||||||
AssertFrame.Attribute(oldAttributeFrame, "ontest", retainedHandler);
|
AssertFrame.Attribute(oldAttributeFrame, "ontest", retainedHandler);
|
||||||
AssertFrame.Attribute(newAttributeFrame, "ontest", retainedHandler);
|
AssertFrame.Attribute(newAttributeFrame, "ontest", retainedHandler);
|
||||||
Assert.NotEqual(0, oldAttributeFrame.AttributeEventHandlerId);
|
Assert.NotEqual(default, oldAttributeFrame.AttributeEventHandlerId);
|
||||||
Assert.Equal(oldAttributeFrame.AttributeEventHandlerId, newAttributeFrame.AttributeEventHandlerId);
|
Assert.Equal(oldAttributeFrame.AttributeEventHandlerId, newAttributeFrame.AttributeEventHandlerId);
|
||||||
Assert.Empty(batchBuilder.DisposedEventHandlerIDs.AsEnumerable());
|
Assert.Empty(batchBuilder.DisposedEventHandlerIDs.AsEnumerable());
|
||||||
}
|
}
|
||||||
|
|
@ -1619,7 +1619,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
Assert.Single(result.Edits);
|
Assert.Single(result.Edits);
|
||||||
AssertFrame.Attribute(oldAttributeFrame, "ontest", retainedHandler);
|
AssertFrame.Attribute(oldAttributeFrame, "ontest", retainedHandler);
|
||||||
AssertFrame.Attribute(newAttributeFrame, "ontest", retainedHandler);
|
AssertFrame.Attribute(newAttributeFrame, "ontest", retainedHandler);
|
||||||
Assert.NotEqual(0, oldAttributeFrame.AttributeEventHandlerId);
|
Assert.NotEqual(default, oldAttributeFrame.AttributeEventHandlerId);
|
||||||
Assert.Equal(oldAttributeFrame.AttributeEventHandlerId, newAttributeFrame.AttributeEventHandlerId);
|
Assert.Equal(oldAttributeFrame.AttributeEventHandlerId, newAttributeFrame.AttributeEventHandlerId);
|
||||||
Assert.Empty(batchBuilder.DisposedEventHandlerIDs.AsEnumerable());
|
Assert.Empty(batchBuilder.DisposedEventHandlerIDs.AsEnumerable());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3313,7 +3313,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type);
|
Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type);
|
||||||
var attributeFrame = batch2.ReferenceFrames[edit.ReferenceFrameIndex];
|
var attributeFrame = batch2.ReferenceFrames[edit.ReferenceFrameIndex];
|
||||||
AssertFrame.Attribute(attributeFrame, "ontestevent", typeof(Action<UIChangeEventArgs>));
|
AssertFrame.Attribute(attributeFrame, "ontestevent", typeof(Action<UIChangeEventArgs>));
|
||||||
Assert.NotEqual(0, attributeFrame.AttributeEventHandlerId);
|
Assert.NotEqual(default, attributeFrame.AttributeEventHandlerId);
|
||||||
Assert.NotEqual(eventHandlerId, attributeFrame.AttributeEventHandlerId);
|
Assert.NotEqual(eventHandlerId, attributeFrame.AttributeEventHandlerId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -3365,7 +3365,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type);
|
Assert.Equal(RenderTreeEditType.SetAttribute, edit.Type);
|
||||||
var attributeFrame = latestBatch.ReferenceFrames[edit.ReferenceFrameIndex];
|
var attributeFrame = latestBatch.ReferenceFrames[edit.ReferenceFrameIndex];
|
||||||
AssertFrame.Attribute(attributeFrame, "ontestevent", typeof(Action<UIChangeEventArgs>));
|
AssertFrame.Attribute(attributeFrame, "ontestevent", typeof(Action<UIChangeEventArgs>));
|
||||||
Assert.NotEqual(0, attributeFrame.AttributeEventHandlerId);
|
Assert.NotEqual(default, attributeFrame.AttributeEventHandlerId);
|
||||||
Assert.NotEqual(eventHandlerId, attributeFrame.AttributeEventHandlerId);
|
Assert.NotEqual(eventHandlerId, attributeFrame.AttributeEventHandlerId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,16 +130,15 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
|
|
||||||
void Write(in RenderTreeFrame frame)
|
void Write(in RenderTreeFrame frame)
|
||||||
{
|
{
|
||||||
|
// TODO: Change this to write as a short, saving 2 bytes per frame
|
||||||
_binaryWriter.Write((int)frame.FrameType);
|
_binaryWriter.Write((int)frame.FrameType);
|
||||||
|
|
||||||
// We want each frame to take up the same number of bytes, so that the
|
// We want each frame to take up the same number of bytes, so that the
|
||||||
// recipient can index into the array directly instead of having to
|
// recipient can index into the array directly instead of having to
|
||||||
// walk through it.
|
// walk through it.
|
||||||
// Since we can fit every frame type into 3 ints, use that as the
|
// Since we can fit every frame type into 16 bytes, use that as the
|
||||||
// common size. For smaller frames, we add padding to expand it to
|
// common size. For smaller frames, we add padding to expand it to
|
||||||
// 12 bytes (i.e., 3 x 4-byte ints).
|
// 16 bytes.
|
||||||
// The total size then for each frame is 16 bytes (frame type, then
|
|
||||||
// 3 other ints).
|
|
||||||
switch (frame.FrameType)
|
switch (frame.FrameType)
|
||||||
{
|
{
|
||||||
case RenderTreeFrameType.Attribute:
|
case RenderTreeFrameType.Attribute:
|
||||||
|
|
@ -160,41 +159,41 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
var attributeValueString = frame.AttributeValue as string;
|
var attributeValueString = frame.AttributeValue as string;
|
||||||
WriteString(attributeValueString, allowDeduplication: string.IsNullOrEmpty(attributeValueString));
|
WriteString(attributeValueString, allowDeduplication: string.IsNullOrEmpty(attributeValueString));
|
||||||
}
|
}
|
||||||
_binaryWriter.Write(frame.AttributeEventHandlerId);
|
_binaryWriter.Write(frame.AttributeEventHandlerId); // 8 bytes
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.Component:
|
case RenderTreeFrameType.Component:
|
||||||
_binaryWriter.Write(frame.ComponentSubtreeLength);
|
_binaryWriter.Write(frame.ComponentSubtreeLength);
|
||||||
_binaryWriter.Write(frame.ComponentId);
|
_binaryWriter.Write(frame.ComponentId);
|
||||||
WritePadding(_binaryWriter, 4);
|
WritePadding(_binaryWriter, 8);
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.ComponentReferenceCapture:
|
case RenderTreeFrameType.ComponentReferenceCapture:
|
||||||
// The client doesn't need to know about these. But we still have
|
// The client doesn't need to know about these. But we still have
|
||||||
// to include them in the array otherwise the ReferenceFrameIndex
|
// to include them in the array otherwise the ReferenceFrameIndex
|
||||||
// values in the edits data would be wrong.
|
// values in the edits data would be wrong.
|
||||||
WritePadding(_binaryWriter, 12);
|
WritePadding(_binaryWriter, 16);
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.Element:
|
case RenderTreeFrameType.Element:
|
||||||
_binaryWriter.Write(frame.ElementSubtreeLength);
|
_binaryWriter.Write(frame.ElementSubtreeLength);
|
||||||
WriteString(frame.ElementName, allowDeduplication: true);
|
WriteString(frame.ElementName, allowDeduplication: true);
|
||||||
WritePadding(_binaryWriter, 4);
|
WritePadding(_binaryWriter, 8);
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.ElementReferenceCapture:
|
case RenderTreeFrameType.ElementReferenceCapture:
|
||||||
WriteString(frame.ElementReferenceCaptureId, allowDeduplication: false);
|
WriteString(frame.ElementReferenceCaptureId, allowDeduplication: false);
|
||||||
WritePadding(_binaryWriter, 8);
|
WritePadding(_binaryWriter, 12);
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.Region:
|
case RenderTreeFrameType.Region:
|
||||||
_binaryWriter.Write(frame.RegionSubtreeLength);
|
_binaryWriter.Write(frame.RegionSubtreeLength);
|
||||||
WritePadding(_binaryWriter, 8);
|
WritePadding(_binaryWriter, 12);
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.Text:
|
case RenderTreeFrameType.Text:
|
||||||
WriteString(
|
WriteString(
|
||||||
frame.TextContent,
|
frame.TextContent,
|
||||||
allowDeduplication: string.IsNullOrWhiteSpace(frame.TextContent));
|
allowDeduplication: string.IsNullOrWhiteSpace(frame.TextContent));
|
||||||
WritePadding(_binaryWriter, 8);
|
WritePadding(_binaryWriter, 12);
|
||||||
break;
|
break;
|
||||||
case RenderTreeFrameType.Markup:
|
case RenderTreeFrameType.Markup:
|
||||||
WriteString(frame.MarkupContent, allowDeduplication: false);
|
WriteString(frame.MarkupContent, allowDeduplication: false);
|
||||||
WritePadding(_binaryWriter, 8);
|
WritePadding(_binaryWriter, 12);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"Unsupported frame type: {frame.FrameType}");
|
throw new ArgumentException($"Unsupported frame type: {frame.FrameType}");
|
||||||
|
|
@ -216,6 +215,21 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
return startPos;
|
return startPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Write(in ArrayRange<ulong> numbers)
|
||||||
|
{
|
||||||
|
var startPos = (int)_binaryWriter.BaseStream.Position;
|
||||||
|
_binaryWriter.Write(numbers.Count);
|
||||||
|
|
||||||
|
var array = numbers.Array;
|
||||||
|
var count = numbers.Count;
|
||||||
|
for (var index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
_binaryWriter.Write(array[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return startPos;
|
||||||
|
}
|
||||||
|
|
||||||
void WriteString(string value, bool allowDeduplication)
|
void WriteString(string value, bool allowDeduplication)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
new ArrayRange<RenderTreeDiff>(),
|
new ArrayRange<RenderTreeDiff>(),
|
||||||
new ArrayRange<RenderTreeFrame>(),
|
new ArrayRange<RenderTreeFrame>(),
|
||||||
new ArrayRange<int>(),
|
new ArrayRange<int>(),
|
||||||
new ArrayRange<int>(new[] { 123, int.MaxValue, int.MinValue, 456 }, 3) // Only use first 3 to show that param is respected
|
new ArrayRange<ulong>(new ulong[] { 123, ulong.MaxValue, ulong.MinValue, 456 }, 3) // Only use first 3 to show that param is respected
|
||||||
));
|
));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -84,15 +84,15 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
0, // Length of UpdatedComponents
|
0, // Length of UpdatedComponents
|
||||||
0, // Length of ReferenceFrames
|
0, // Length of ReferenceFrames
|
||||||
0, // Length of DisposedComponentIds
|
0, // Length of DisposedComponentIds
|
||||||
3, 123, int.MaxValue, int.MinValue, // DisposedEventHandlerIds as length-prefixed array
|
3, (ulong)123, ulong.MaxValue, ulong.MinValue, // DisposedEventHandlerIds as length-prefixed array
|
||||||
|
|
||||||
0, // Index of UpdatedComponents
|
0, // Index of UpdatedComponents
|
||||||
4, // Index of ReferenceFrames
|
4, // Index of ReferenceFrames
|
||||||
8, // Index of DisposedComponentIds
|
8, // Index of DisposedComponentIds
|
||||||
12, // Index of DisposedEventHandlerIds
|
12, // Index of DisposedEventHandlerIds
|
||||||
28 // Index of strings
|
40 // Index of strings
|
||||||
);
|
);
|
||||||
Assert.Equal(48, bytes.Length); // No other data
|
Assert.Equal(60, bytes.Length); // No other data
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -200,7 +200,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
RenderTreeFrame.Attribute(123, "Attribute with string value", "String value"),
|
RenderTreeFrame.Attribute(123, "Attribute with string value", "String value"),
|
||||||
RenderTreeFrame.Attribute(124, "Attribute with nonstring value", 1),
|
RenderTreeFrame.Attribute(124, "Attribute with nonstring value", 1),
|
||||||
RenderTreeFrame.Attribute(125, "Attribute with delegate value", new Action(() => { }))
|
RenderTreeFrame.Attribute(125, "Attribute with delegate value", new Action(() => { }))
|
||||||
.WithAttributeEventHandlerId(789),
|
.WithAttributeEventHandlerId(((ulong)uint.MaxValue) + 1),
|
||||||
RenderTreeFrame.ChildComponent(126, typeof(object))
|
RenderTreeFrame.ChildComponent(126, typeof(object))
|
||||||
.WithComponentSubtreeLength(5678)
|
.WithComponentSubtreeLength(5678)
|
||||||
.WithComponent(new ComponentState(renderer, 2000, new FakeComponent(), null)),
|
.WithComponent(new ComponentState(renderer, 2000, new FakeComponent(), null)),
|
||||||
|
|
@ -230,22 +230,22 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
var referenceFramesStartIndex = ReadInt(bytes, bytes.Length - 16);
|
var referenceFramesStartIndex = ReadInt(bytes, bytes.Length - 16);
|
||||||
AssertBinaryContents(bytes, referenceFramesStartIndex,
|
AssertBinaryContents(bytes, referenceFramesStartIndex,
|
||||||
16, // Number of frames
|
16, // Number of frames
|
||||||
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0,
|
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0, 0,
|
||||||
RenderTreeFrameType.Attribute, "Attribute with nonstring value", NullStringMarker, 0,
|
RenderTreeFrameType.Attribute, "Attribute with nonstring value", NullStringMarker, 0, 0,
|
||||||
RenderTreeFrameType.Attribute, "Attribute with delegate value", NullStringMarker, 789,
|
RenderTreeFrameType.Attribute, "Attribute with delegate value", NullStringMarker, ((ulong)uint.MaxValue) + 1,
|
||||||
RenderTreeFrameType.Component, 5678, 2000, 0,
|
RenderTreeFrameType.Component, 5678, 2000, 0, 0,
|
||||||
RenderTreeFrameType.ComponentReferenceCapture, 0, 0, 0,
|
RenderTreeFrameType.ComponentReferenceCapture, 0, 0, 0, 0,
|
||||||
RenderTreeFrameType.Element, 1234, "Some element", 0,
|
RenderTreeFrameType.Element, 1234, "Some element", 0, 0,
|
||||||
RenderTreeFrameType.ElementReferenceCapture, "my unique ID", 0, 0,
|
RenderTreeFrameType.ElementReferenceCapture, "my unique ID", 0, 0, 0,
|
||||||
RenderTreeFrameType.Region, 1234, 0, 0,
|
RenderTreeFrameType.Region, 1234, 0, 0, 0,
|
||||||
RenderTreeFrameType.Text, "Some text", 0, 0,
|
RenderTreeFrameType.Text, "Some text", 0, 0, 0,
|
||||||
RenderTreeFrameType.Markup, "Some markup", 0, 0,
|
RenderTreeFrameType.Markup, "Some markup", 0, 0, 0,
|
||||||
RenderTreeFrameType.Text, "\n\t ", 0, 0,
|
RenderTreeFrameType.Text, "\n\t ", 0, 0, 0,
|
||||||
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0,
|
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0, 0,
|
||||||
RenderTreeFrameType.Element, 999, "Some element", 0,
|
RenderTreeFrameType.Element, 999, "Some element", 0, 0,
|
||||||
RenderTreeFrameType.Text, "Some text", 0, 0,
|
RenderTreeFrameType.Text, "Some text", 0, 0, 0,
|
||||||
RenderTreeFrameType.Markup, "Some markup", 0, 0,
|
RenderTreeFrameType.Markup, "Some markup", 0, 0, 0,
|
||||||
RenderTreeFrameType.Text, "\n\t ", 0, 0
|
RenderTreeFrameType.Text, "\n\t ", 0, 0, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert.Equal(new[]
|
Assert.Equal(new[]
|
||||||
|
|
@ -320,6 +320,10 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
{
|
{
|
||||||
Assert.Equal(expectedInt, reader.ReadInt32());
|
Assert.Equal(expectedInt, reader.ReadInt32());
|
||||||
}
|
}
|
||||||
|
else if (expectedEntry is ulong expectedUlong)
|
||||||
|
{
|
||||||
|
Assert.Equal(expectedUlong, reader.ReadUInt64());
|
||||||
|
}
|
||||||
else if (expectedEntry is string || expectedEntry == NullStringMarker)
|
else if (expectedEntry is string || expectedEntry == NullStringMarker)
|
||||||
{
|
{
|
||||||
// For strings, we have to look up the value in the table of strings
|
// For strings, we have to look up the value in the table of strings
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ namespace Microsoft.AspNetCore.Components.Test.Helpers
|
||||||
public new Task RenderRootComponentAsync(int componentId, ParameterCollection parameters)
|
public new Task RenderRootComponentAsync(int componentId, ParameterCollection parameters)
|
||||||
=> Dispatcher.InvokeAsync(() => base.RenderRootComponentAsync(componentId, parameters));
|
=> Dispatcher.InvokeAsync(() => base.RenderRootComponentAsync(componentId, parameters));
|
||||||
|
|
||||||
public Task DispatchEventAsync(int eventHandlerId, UIEventArgs args)
|
public Task DispatchEventAsync(ulong eventHandlerId, UIEventArgs args)
|
||||||
=> Dispatcher.InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, null, args));
|
=> Dispatcher.InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, null, args));
|
||||||
|
|
||||||
public new Task DispatchEventAsync(int eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs args)
|
public new Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs args)
|
||||||
=> Dispatcher.InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, eventFieldInfo, args));
|
=> Dispatcher.InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, eventFieldInfo, args));
|
||||||
|
|
||||||
private static Task UnwrapTask(Task task)
|
private static Task UnwrapTask(Task task)
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -13,6 +13,8 @@ let invoke_method: (method: MethodHandle, target: System_Object, argsArrayPtr: n
|
||||||
let mono_string_get_utf8: (managedString: System_String) => Mono.Utf8Ptr;
|
let mono_string_get_utf8: (managedString: System_String) => Mono.Utf8Ptr;
|
||||||
let mono_string: (jsString: string) => System_String;
|
let mono_string: (jsString: string) => System_String;
|
||||||
const appBinDirName = 'appBinDir';
|
const appBinDirName = 'appBinDir';
|
||||||
|
const uint64HighOrderShift = Math.pow(2, 32);
|
||||||
|
const maxSafeNumberHighPart = Math.pow(2, 21) - 1; // The high-order int32 from Number.MAX_SAFE_INTEGER
|
||||||
|
|
||||||
export const monoPlatform: Platform = {
|
export const monoPlatform: Platform = {
|
||||||
start: function start(loadAssemblyUrls: string[]) {
|
start: function start(loadAssemblyUrls: string[]) {
|
||||||
|
|
@ -122,6 +124,19 @@ export const monoPlatform: Platform = {
|
||||||
return Module.getValue((baseAddress as any as number) + (fieldOffset || 0), 'i32');
|
return Module.getValue((baseAddress as any as number) + (fieldOffset || 0), 'i32');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
readUint64Field: function readHeapUint64(baseAddress: Pointer, fieldOffset?: number): number {
|
||||||
|
// Module.getValue(..., 'i64') doesn't work because the implementation treats 'i64' as
|
||||||
|
// being the same as 'i32'. Also we must take care to read both halves as unsigned.
|
||||||
|
const address = (baseAddress as any as number) + (fieldOffset || 0);
|
||||||
|
const heapU32Index = address >> 2;
|
||||||
|
const highPart = Module.HEAPU32[heapU32Index + 1];
|
||||||
|
if (highPart > maxSafeNumberHighPart) {
|
||||||
|
throw new Error(`Cannot read uint64 with high order part ${highPart}, because the result would exceed Number.MAX_SAFE_INTEGER.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (highPart * uint64HighOrderShift) + Module.HEAPU32[heapU32Index];
|
||||||
|
},
|
||||||
|
|
||||||
readFloatField: function readHeapFloat(baseAddress: Pointer, fieldOffset?: number): number {
|
readFloatField: function readHeapFloat(baseAddress: Pointer, fieldOffset?: number): number {
|
||||||
return Module.getValue((baseAddress as any as number) + (fieldOffset || 0), 'float');
|
return Module.getValue((baseAddress as any as number) + (fieldOffset || 0), 'float');
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export interface Platform {
|
||||||
getObjectFieldsBaseAddress(referenceTypedObject: System_Object): Pointer;
|
getObjectFieldsBaseAddress(referenceTypedObject: System_Object): Pointer;
|
||||||
readInt16Field(baseAddress: Pointer, fieldOffset?: number): number;
|
readInt16Field(baseAddress: Pointer, fieldOffset?: number): number;
|
||||||
readInt32Field(baseAddress: Pointer, fieldOffset?: number): number;
|
readInt32Field(baseAddress: Pointer, fieldOffset?: number): number;
|
||||||
|
readUint64Field(baseAddress: Pointer, fieldOffset?: number): number;
|
||||||
readFloatField(baseAddress: Pointer, fieldOffset?: number): number;
|
readFloatField(baseAddress: Pointer, fieldOffset?: number): number;
|
||||||
readObjectField<T extends System_Object>(baseAddress: Pointer, fieldOffset?: number): T;
|
readObjectField<T extends System_Object>(baseAddress: Pointer, fieldOffset?: number): T;
|
||||||
readStringField(baseAddress: Pointer, fieldOffset?: number): string | null;
|
readStringField(baseAddress: Pointer, fieldOffset?: number): string | null;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ import { RenderBatch, ArrayRange, RenderTreeDiff, ArrayValues, RenderTreeEdit, E
|
||||||
import { decodeUtf8 } from './Utf8Decoder';
|
import { decodeUtf8 } from './Utf8Decoder';
|
||||||
|
|
||||||
const updatedComponentsEntryLength = 4; // Each is a single int32 giving the location of the data
|
const updatedComponentsEntryLength = 4; // Each is a single int32 giving the location of the data
|
||||||
const referenceFramesEntryLength = 16; // 1 byte for frame type, then 3 bytes for type-specific data
|
const referenceFramesEntryLength = 20; // 1 int for frame type, then 16 bytes for type-specific data
|
||||||
const disposedComponentIdsEntryLength = 4; // Each is an int32 giving the ID
|
const disposedComponentIdsEntryLength = 4; // Each is an int32 giving the ID
|
||||||
const disposedEventHandlerIdsEntryLength = 4; // Each is an int32 giving the ID
|
const disposedEventHandlerIdsEntryLength = 8; // Each is an int64 giving the ID
|
||||||
const editsEntryLength = 16; // 4 ints
|
const editsEntryLength = 16; // 4 ints
|
||||||
const stringTableEntryLength = 4; // Each is an int32 giving the string data location, or -1 for null
|
const stringTableEntryLength = 4; // Each is an int32 giving the string data location, or -1 for null
|
||||||
|
const uint64HighPartShift = Math.pow(2, 32);
|
||||||
|
const maxSafeNumberHighPart = Math.pow(2, 21) - 1; // The high-order int32 from Number.MAX_SAFE_INTEGER
|
||||||
|
|
||||||
export class OutOfProcessRenderBatch implements RenderBatch {
|
export class OutOfProcessRenderBatch implements RenderBatch {
|
||||||
constructor(private batchData: Uint8Array) {
|
constructor(private batchData: Uint8Array) {
|
||||||
|
|
@ -51,7 +53,7 @@ export class OutOfProcessRenderBatch implements RenderBatch {
|
||||||
|
|
||||||
disposedEventHandlerIdsEntry(values: ArrayValues<number>, index: number): number {
|
disposedEventHandlerIdsEntry(values: ArrayValues<number>, index: number): number {
|
||||||
const entryPos = (values as any) + index * disposedEventHandlerIdsEntryLength;
|
const entryPos = (values as any) + index * disposedEventHandlerIdsEntryLength;
|
||||||
return readInt32LE(this.batchData, entryPos);
|
return readUint64LE(this.batchData, entryPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
diffReader: RenderTreeDiffReader;
|
diffReader: RenderTreeDiffReader;
|
||||||
|
|
@ -160,7 +162,7 @@ class OutOfProcessRenderTreeFrameReader implements RenderTreeFrameReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeEventHandlerId(frame: RenderTreeFrame) {
|
attributeEventHandlerId(frame: RenderTreeFrame) {
|
||||||
return readInt32LE(this.batchDataUint8, frame as any + 12); // 4th int
|
return readUint64LE(this.batchDataUint8, frame as any + 12); // Bytes 12-19
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,6 +237,24 @@ function readInt32LE(buffer: Uint8Array, position: number): any {
|
||||||
| (buffer[position + 3] << 24);
|
| (buffer[position + 3] << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readUint32LE(buffer: Uint8Array, position: number): any {
|
||||||
|
return (buffer[position])
|
||||||
|
+ (buffer[position + 1] << 8)
|
||||||
|
+ (buffer[position + 2] << 16)
|
||||||
|
+ ((buffer[position + 3] << 24) >>> 0); // The >>> 0 coerces the value to unsigned
|
||||||
|
}
|
||||||
|
|
||||||
|
function readUint64LE(buffer: Uint8Array, position: number): any {
|
||||||
|
// This cannot be done using bit-shift operators in JavaScript, because
|
||||||
|
// those all implicitly convert to int32
|
||||||
|
const highPart = readUint32LE(buffer, position + 4);
|
||||||
|
if (highPart > maxSafeNumberHighPart) {
|
||||||
|
throw new Error(`Cannot read uint64 with high order part ${highPart}, because the result would exceed Number.MAX_SAFE_INTEGER.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (highPart * uint64HighPartShift) + readUint32LE(buffer, position);
|
||||||
|
}
|
||||||
|
|
||||||
function readLEB128(buffer: Uint8Array, position: number) {
|
function readLEB128(buffer: Uint8Array, position: number) {
|
||||||
let result = 0;
|
let result = 0;
|
||||||
let shift = 0;
|
let shift = 0;
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ export class SharedMemoryRenderBatch implements RenderBatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
disposedEventHandlerIdsEntry(values: ArrayValues<number>, index: number) {
|
disposedEventHandlerIdsEntry(values: ArrayValues<number>, index: number) {
|
||||||
const pointer = arrayValuesEntry(values, index, /* int length */ 4);
|
const pointer = arrayValuesEntry(values, index, /* long length */ 8);
|
||||||
return platform.readInt32Field(pointer as any as Pointer);
|
return platform.readUint64Field(pointer as any as Pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayRangeReader = arrayRangeReader;
|
arrayRangeReader = arrayRangeReader;
|
||||||
|
|
@ -108,7 +108,7 @@ const frameReader = {
|
||||||
markupContent: (frame: RenderTreeFrame) => platform.readStringField(frame as any, 16)!,
|
markupContent: (frame: RenderTreeFrame) => platform.readStringField(frame as any, 16)!,
|
||||||
attributeName: (frame: RenderTreeFrame) => platform.readStringField(frame as any, 16),
|
attributeName: (frame: RenderTreeFrame) => platform.readStringField(frame as any, 16),
|
||||||
attributeValue: (frame: RenderTreeFrame) => platform.readStringField(frame as any, 24),
|
attributeValue: (frame: RenderTreeFrame) => platform.readStringField(frame as any, 24),
|
||||||
attributeEventHandlerId: (frame: RenderTreeFrame) => platform.readInt32Field(frame as any, 8),
|
attributeEventHandlerId: (frame: RenderTreeFrame) => platform.readUint64Field(frame as any, 8),
|
||||||
};
|
};
|
||||||
|
|
||||||
function arrayValuesEntry<T>(arrayValues: ArrayValues<T>, index: number, itemSize: number): T {
|
function arrayValuesEntry<T>(arrayValues: ArrayValues<T>, index: number, itemSize: number): T {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Components.Web
|
||||||
public int BrowserRendererId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public int BrowserRendererId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string EventArgsType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public Microsoft.AspNetCore.Components.Rendering.EventFieldInfo EventFieldInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public Microsoft.AspNetCore.Components.Rendering.EventFieldInfo EventFieldInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public int EventHandlerId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public ulong EventHandlerId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.Components.Web
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For framework use only.
|
/// For framework use only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int EventHandlerId { get; set; }
|
public ulong EventHandlerId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For framework use only.
|
/// For framework use only.
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ namespace Ignitor
|
||||||
RenderTreeFrame.Attribute(123, "Attribute with string value", "String value"),
|
RenderTreeFrame.Attribute(123, "Attribute with string value", "String value"),
|
||||||
RenderTreeFrame.Attribute(124, "Attribute with nonstring value", 1),
|
RenderTreeFrame.Attribute(124, "Attribute with nonstring value", 1),
|
||||||
RenderTreeFrame.Attribute(125, "Attribute with delegate value", new Action(() => { }))
|
RenderTreeFrame.Attribute(125, "Attribute with delegate value", new Action(() => { }))
|
||||||
.WithAttributeEventHandlerId(789),
|
.WithAttributeEventHandlerId((ulong)uint.MaxValue + 1),
|
||||||
RenderTreeFrame.ChildComponent(126, typeof(object))
|
RenderTreeFrame.ChildComponent(126, typeof(object))
|
||||||
.WithComponentSubtreeLength(5678)
|
.WithComponentSubtreeLength(5678)
|
||||||
.WithComponent(new ComponentState(renderer, 2000, new FakeComponent(), null)),
|
.WithComponent(new ComponentState(renderer, 2000, new FakeComponent(), null)),
|
||||||
|
|
@ -180,22 +180,22 @@ namespace Ignitor
|
||||||
var referenceFramesStartIndex = ReadInt(bytes, bytes.Length - 16);
|
var referenceFramesStartIndex = ReadInt(bytes, bytes.Length - 16);
|
||||||
AssertBinaryContents(bytes, referenceFramesStartIndex,
|
AssertBinaryContents(bytes, referenceFramesStartIndex,
|
||||||
16, // Number of frames
|
16, // Number of frames
|
||||||
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0,
|
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0, 0,
|
||||||
RenderTreeFrameType.Attribute, "Attribute with nonstring value", NullStringMarker, 0,
|
RenderTreeFrameType.Attribute, "Attribute with nonstring value", NullStringMarker, 0, 0,
|
||||||
RenderTreeFrameType.Attribute, "Attribute with delegate value", NullStringMarker, 789,
|
RenderTreeFrameType.Attribute, "Attribute with delegate value", NullStringMarker, (ulong)uint.MaxValue + 1,
|
||||||
RenderTreeFrameType.Component, 5678, 2000, 0,
|
RenderTreeFrameType.Component, 5678, 2000, 0, 0,
|
||||||
RenderTreeFrameType.ComponentReferenceCapture, 0, 0, 0,
|
RenderTreeFrameType.ComponentReferenceCapture, 0, 0, 0, 0,
|
||||||
RenderTreeFrameType.Element, 1234, "Some element", 0,
|
RenderTreeFrameType.Element, 1234, "Some element", 0, 0,
|
||||||
RenderTreeFrameType.ElementReferenceCapture, "my unique ID", 0, 0,
|
RenderTreeFrameType.ElementReferenceCapture, "my unique ID", 0, 0, 0,
|
||||||
RenderTreeFrameType.Region, 1234, 0, 0,
|
RenderTreeFrameType.Region, 1234, 0, 0, 0,
|
||||||
RenderTreeFrameType.Text, "Some text", 0, 0,
|
RenderTreeFrameType.Text, "Some text", 0, 0, 0,
|
||||||
RenderTreeFrameType.Markup, "Some markup", 0, 0,
|
RenderTreeFrameType.Markup, "Some markup", 0, 0, 0,
|
||||||
RenderTreeFrameType.Text, "\n\t ", 0, 0,
|
RenderTreeFrameType.Text, "\n\t ", 0, 0, 0,
|
||||||
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0,
|
RenderTreeFrameType.Attribute, "Attribute with string value", "String value", 0, 0,
|
||||||
RenderTreeFrameType.Element, 999, "Some element", 0,
|
RenderTreeFrameType.Element, 999, "Some element", 0, 0,
|
||||||
RenderTreeFrameType.Text, "Some text", 0, 0,
|
RenderTreeFrameType.Text, "Some text", 0, 0, 0,
|
||||||
RenderTreeFrameType.Markup, "Some markup", 0, 0,
|
RenderTreeFrameType.Markup, "Some markup", 0, 0, 0,
|
||||||
RenderTreeFrameType.Text, "\n\t ", 0, 0
|
RenderTreeFrameType.Text, "\n\t ", 0, 0, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert.Equal(new[]
|
Assert.Equal(new[]
|
||||||
|
|
@ -279,6 +279,10 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
Assert.Equal(expectedInt, reader.ReadInt32());
|
Assert.Equal(expectedInt, reader.ReadInt32());
|
||||||
}
|
}
|
||||||
|
else if (expectedEntry is ulong expectedUlong)
|
||||||
|
{
|
||||||
|
Assert.Equal(expectedUlong, reader.ReadUInt64());
|
||||||
|
}
|
||||||
else if (expectedEntry is string || expectedEntry == NullStringMarker)
|
else if (expectedEntry is string || expectedEntry == NullStringMarker)
|
||||||
{
|
{
|
||||||
// For strings, we have to look up the value in the table of strings
|
// For strings, we have to look up the value in the table of strings
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,10 @@ namespace ComponentsApp.Server
|
||||||
{
|
{
|
||||||
services.AddMvc();
|
services.AddMvc();
|
||||||
services.AddSingleton<CircuitHandler, LoggingCircuitHandler>();
|
services.AddSingleton<CircuitHandler, LoggingCircuitHandler>();
|
||||||
services.AddServerSideBlazor();
|
services.AddServerSideBlazor(options =>
|
||||||
|
{
|
||||||
|
options.JSInteropDetailedErrors = true;
|
||||||
|
});
|
||||||
|
|
||||||
services.AddSingleton<WeatherForecastService, DefaultWeatherForecastService>();
|
services.AddSingleton<WeatherForecastService, DefaultWeatherForecastService>();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ namespace Ignitor
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeEventHandler(int eventHandlerId)
|
private void DisposeEventHandler(ulong eventHandlerId)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ namespace Ignitor
|
||||||
|
|
||||||
public class ElementEventDescriptor
|
public class ElementEventDescriptor
|
||||||
{
|
{
|
||||||
public ElementEventDescriptor(string eventName, int eventId)
|
public ElementEventDescriptor(string eventName, ulong eventId)
|
||||||
{
|
{
|
||||||
EventName = eventName ?? throw new ArgumentNullException(nameof(eventName));
|
EventName = eventName ?? throw new ArgumentNullException(nameof(eventName));
|
||||||
EventId = eventId;
|
EventId = eventId;
|
||||||
|
|
@ -109,7 +109,7 @@ namespace Ignitor
|
||||||
|
|
||||||
public string EventName { get; }
|
public string EventName { get; }
|
||||||
|
|
||||||
public int EventId { get; }
|
public ulong EventId { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ClickAsync(HubConnection connection)
|
public async Task ClickAsync(HubConnection connection)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
public static class RenderBatchReader
|
public static class RenderBatchReader
|
||||||
{
|
{
|
||||||
|
private const int ReferenceFrameSize = 20;
|
||||||
|
|
||||||
private static readonly Renderer Renderer = new FakeRenderer();
|
private static readonly Renderer Renderer = new FakeRenderer();
|
||||||
|
|
||||||
public static RenderBatch Read(ReadOnlySpan<byte> data)
|
public static RenderBatch Read(ReadOnlySpan<byte> data)
|
||||||
|
|
@ -131,69 +133,67 @@ namespace Ignitor
|
||||||
|
|
||||||
private static ArrayRange<RenderTreeFrame> ReadReferenceFrames(ReadOnlySpan<byte> data, string[] strings)
|
private static ArrayRange<RenderTreeFrame> ReadReferenceFrames(ReadOnlySpan<byte> data, string[] strings)
|
||||||
{
|
{
|
||||||
var result = new RenderTreeFrame[data.Length / 16];
|
var result = new RenderTreeFrame[data.Length / ReferenceFrameSize];
|
||||||
|
|
||||||
for (var i = 0; i < data.Length; i += 16)
|
for (var i = 0; i < data.Length; i += ReferenceFrameSize)
|
||||||
{
|
{
|
||||||
var frameData = data.Slice(i, 16);
|
var frameData = data.Slice(i, ReferenceFrameSize);
|
||||||
|
|
||||||
var type = (RenderTreeFrameType)BitConverter.ToInt32(frameData.Slice(0, 4));
|
var type = (RenderTreeFrameType)BitConverter.ToInt32(frameData.Slice(0, 4));
|
||||||
|
|
||||||
// We want each frame to take up the same number of bytes, so that the
|
// We want each frame to take up the same number of bytes, so that the
|
||||||
// recipient can index into the array directly instead of having to
|
// recipient can index into the array directly instead of having to
|
||||||
// walk through it.
|
// walk through it.
|
||||||
// Since we can fit every frame type into 3 ints, use that as the
|
// Since we can fit every frame type into 16 bytes, use that as the
|
||||||
// common size. For smaller frames, we add padding to expand it to
|
// common size. For smaller frames, we add padding to expand it to
|
||||||
// 12 bytes (i.e., 3 x 4-byte ints).
|
// 16 bytes.
|
||||||
// The total size then for each frame is 16 bytes (frame type, then
|
|
||||||
// 3 other ints).
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case RenderTreeFrameType.Attribute:
|
case RenderTreeFrameType.Attribute:
|
||||||
var attributeName = ReadString(frameData.Slice(4, 4), strings);
|
var attributeName = ReadString(frameData.Slice(4, 4), strings);
|
||||||
var attributeValue = ReadString(frameData.Slice(8, 4), strings);
|
var attributeValue = ReadString(frameData.Slice(8, 4), strings);
|
||||||
var attributeEventHandlerId = BitConverter.ToInt32(frameData.Slice(12, 4));
|
var attributeEventHandlerId = BitConverter.ToUInt64(frameData.Slice(12, 8));
|
||||||
result[i / 16] = RenderTreeFrame.Attribute(0, attributeName, attributeValue).WithAttributeEventHandlerId(attributeEventHandlerId);
|
result[i / ReferenceFrameSize] = RenderTreeFrame.Attribute(0, attributeName, attributeValue).WithAttributeEventHandlerId(attributeEventHandlerId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.Component:
|
case RenderTreeFrameType.Component:
|
||||||
var componentSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4));
|
var componentSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4));
|
||||||
var componentId = BitConverter.ToInt32(frameData.Slice(8, 4)); // Nowhere to put this without creating a ComponentState
|
var componentId = BitConverter.ToInt32(frameData.Slice(8, 4)); // Nowhere to put this without creating a ComponentState
|
||||||
result[i / 16] = RenderTreeFrame.ChildComponent(0, componentType: null)
|
result[i / ReferenceFrameSize] = RenderTreeFrame.ChildComponent(0, componentType: null)
|
||||||
.WithComponentSubtreeLength(componentSubtreeLength)
|
.WithComponentSubtreeLength(componentSubtreeLength)
|
||||||
.WithComponent(new ComponentState(Renderer, componentId, new FakeComponent(), null));
|
.WithComponent(new ComponentState(Renderer, componentId, new FakeComponent(), null));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.ComponentReferenceCapture:
|
case RenderTreeFrameType.ComponentReferenceCapture:
|
||||||
// Client doesn't process these, skip.
|
// Client doesn't process these, skip.
|
||||||
result[i / 16] = RenderTreeFrame.ComponentReferenceCapture(0, null, 0);
|
result[i / ReferenceFrameSize] = RenderTreeFrame.ComponentReferenceCapture(0, null, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.Element:
|
case RenderTreeFrameType.Element:
|
||||||
var elementSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4));
|
var elementSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4));
|
||||||
var elementName = ReadString(frameData.Slice(8, 4), strings);
|
var elementName = ReadString(frameData.Slice(8, 4), strings);
|
||||||
result[i / 16] = RenderTreeFrame.Element(0, elementName).WithElementSubtreeLength(elementSubtreeLength);
|
result[i / ReferenceFrameSize] = RenderTreeFrame.Element(0, elementName).WithElementSubtreeLength(elementSubtreeLength);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.ElementReferenceCapture:
|
case RenderTreeFrameType.ElementReferenceCapture:
|
||||||
var referenceCaptureId = ReadString(frameData.Slice(4, 4), strings);
|
var referenceCaptureId = ReadString(frameData.Slice(4, 4), strings);
|
||||||
result[i / 16] = RenderTreeFrame.ElementReferenceCapture(0, null)
|
result[i / ReferenceFrameSize] = RenderTreeFrame.ElementReferenceCapture(0, null)
|
||||||
.WithElementReferenceCaptureId(referenceCaptureId);
|
.WithElementReferenceCaptureId(referenceCaptureId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.Region:
|
case RenderTreeFrameType.Region:
|
||||||
var regionSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4));
|
var regionSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4));
|
||||||
result[i / 16] = RenderTreeFrame.Region(0).WithRegionSubtreeLength(regionSubtreeLength);
|
result[i / ReferenceFrameSize] = RenderTreeFrame.Region(0).WithRegionSubtreeLength(regionSubtreeLength);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.Text:
|
case RenderTreeFrameType.Text:
|
||||||
var text = ReadString(frameData.Slice(4, 4), strings);
|
var text = ReadString(frameData.Slice(4, 4), strings);
|
||||||
result[i / 16] = RenderTreeFrame.Text(0, text);
|
result[i / ReferenceFrameSize] = RenderTreeFrame.Text(0, text);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RenderTreeFrameType.Markup:
|
case RenderTreeFrameType.Markup:
|
||||||
var markup = ReadString(frameData.Slice(4, 4), strings);
|
var markup = ReadString(frameData.Slice(4, 4), strings);
|
||||||
result[i / 16] = RenderTreeFrame.Markup(0, markup);
|
result[i / ReferenceFrameSize] = RenderTreeFrame.Markup(0, markup);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -209,9 +209,9 @@ namespace Ignitor
|
||||||
return new ArrayRange<int>(Array.Empty<int>(), 0);
|
return new ArrayRange<int>(Array.Empty<int>(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArrayRange<int> ReadDisposedEventHandlerIds(ReadOnlySpan<byte> data)
|
private static ArrayRange<ulong> ReadDisposedEventHandlerIds(ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
return new ArrayRange<int>(Array.Empty<int>(), 0);
|
return new ArrayRange<ulong>(Array.Empty<ulong>(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ReadString(ReadOnlySpan<byte> data, string[] strings)
|
private static string ReadString(ReadOnlySpan<byte> data, string[] strings)
|
||||||
|
|
@ -276,7 +276,7 @@ namespace Ignitor
|
||||||
{
|
{
|
||||||
// This is a count-prefixed contiguous array of RenderTreeFrame.
|
// This is a count-prefixed contiguous array of RenderTreeFrame.
|
||||||
var count = BitConverter.ToInt32(data.Slice(_referenceFrames, 4));
|
var count = BitConverter.ToInt32(data.Slice(_referenceFrames, 4));
|
||||||
return data.Slice(_referenceFrames + 4, count * 16);
|
return data.Slice(_referenceFrames + 4, count * ReferenceFrameSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> GetStringTableIndexes(ReadOnlySpan<byte> data)
|
public ReadOnlySpan<byte> GetStringTableIndexes(ReadOnlySpan<byte> data)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue