File: System\Formats\Nrbf\ArrayRectangularPrimitiveRecord.cs
Web Access
Project: src\src\libraries\System.Formats.Nrbf\src\System.Formats.Nrbf.csproj (System.Formats.Nrbf)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Formats.Nrbf.Utils;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
 
namespace System.Formats.Nrbf
{
    internal sealed class ArrayRectangularPrimitiveRecord<T> : ArrayRecord where T : unmanaged
    {
        private readonly int[] _lengths;
        private readonly IReadOnlyList<T> _values;
        private TypeName? _typeName;
 
        internal ArrayRectangularPrimitiveRecord(ArrayInfo arrayInfo, int[] lengths, IReadOnlyList<T> values) : base(arrayInfo)
        {
            _lengths = lengths;
            _values = values;
            ValuesToRead = 0; // there is nothing to read anymore
        }
 
        public override ReadOnlySpan<int> Lengths => _lengths;
 
        public override SerializationRecordType RecordType => SerializationRecordType.BinaryArray;
 
        public override TypeName TypeName
            => _typeName ??= TypeNameHelpers.GetPrimitiveTypeName(TypeNameHelpers.GetPrimitiveType<T>()).MakeArrayTypeName(Rank);
 
        internal override (AllowedRecordTypes allowed, PrimitiveType primitiveType) GetAllowedRecordType() => throw new InvalidOperationException();
 
        private protected override void AddValue(object value) => throw new InvalidOperationException();
 
        [RequiresDynamicCode("May call Array.CreateInstance().")]
        private protected override Array Deserialize(Type arrayType, bool allowNulls)
        {
            Array result =
#if NET9_0_OR_GREATER
                Array.CreateInstanceFromArrayType(arrayType, _lengths);
#else
                Array.CreateInstance(typeof(T), _lengths);
#endif
            int[] indices = new int[_lengths.Length];
            nuint numElementsWritten = 0; // only for debugging; not used in release builds
 
            for (int i = 0; i < _values.Count; i++)
            {
                result.SetValue(_values[i], indices);
                numElementsWritten++;
 
                int dimension = indices.Length - 1;
                while (dimension >= 0)
                {
                    indices[dimension]++;
                    if (indices[dimension] < Lengths[dimension])
                    {
                        break;
                    }
                    indices[dimension] = 0;
                    dimension--;
                }
 
                if (dimension < 0)
                {
                    break;
                }
            }
 
            Debug.Assert(numElementsWritten == (uint)_values.Count, "We should have traversed the entirety of the source values collection.");
            Debug.Assert(numElementsWritten == (ulong)result.LongLength, "We should have traversed the entirety of the destination array.");
 
            return result;
        }
    }
}