private static ArrayRange <RenderTreeFrame> ReadReferenceFrames(ReadOnlySpan <byte> data, string[] strings) { var result = new RenderTreeFrame[data.Length / ReferenceFrameSize]; for (var i = 0; i < data.Length; i += ReferenceFrameSize) { var frameData = data.Slice(i, ReferenceFrameSize); var type = (RenderTreeFrameType)BitConverter.ToInt32(frameData.Slice(0, 4)); // 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 // walk through it. // 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 // 16 bytes. switch (type) { case RenderTreeFrameType.Attribute: var attributeName = ReadString(frameData.Slice(4, 4), strings); var attributeValue = ReadString(frameData.Slice(8, 4), strings); var attributeEventHandlerId = BitConverter.ToUInt64(frameData.Slice(12, 8)); result[i / ReferenceFrameSize] = RenderTreeFrame.Attribute(0, attributeName, attributeValue).WithAttributeEventHandlerId(attributeEventHandlerId); break; case RenderTreeFrameType.Component: var componentSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4)); var componentId = BitConverter.ToInt32(frameData.Slice(8, 4)); // Nowhere to put this without creating a ComponentState result[i / ReferenceFrameSize] = RenderTreeFrame.ChildComponent(0, componentType: null) .WithComponentSubtreeLength(componentSubtreeLength) .WithComponent(new ComponentState(Renderer, componentId, new FakeComponent(), null)); break; case RenderTreeFrameType.ComponentReferenceCapture: // Client doesn't process these, skip. result[i / ReferenceFrameSize] = RenderTreeFrame.ComponentReferenceCapture(0, null, 0); break; case RenderTreeFrameType.Element: var elementSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4)); var elementName = ReadString(frameData.Slice(8, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.Element(0, elementName).WithElementSubtreeLength(elementSubtreeLength); break; case RenderTreeFrameType.ElementReferenceCapture: var referenceCaptureId = ReadString(frameData.Slice(4, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.ElementReferenceCapture(0, null) .WithElementReferenceCaptureId(referenceCaptureId); break; case RenderTreeFrameType.Region: var regionSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4)); result[i / ReferenceFrameSize] = RenderTreeFrame.Region(0).WithRegionSubtreeLength(regionSubtreeLength); break; case RenderTreeFrameType.Text: var text = ReadString(frameData.Slice(4, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.Text(0, text); break; case RenderTreeFrameType.Markup: var markup = ReadString(frameData.Slice(4, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.Markup(0, markup); break; default: throw new ArgumentException($"Unsupported frame type: {type}"); } } return(new ArrayRange <RenderTreeFrame>(result, result.Length)); }