// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.

using System.Buffers.Binary;
using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;

namespace Benchmarks;

[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[Config(typeof(GenericConfig))]
public class BinaryConversionBenchmarks
{
    private byte[] _data = null!;
    private int _offset;
    private int _writeBuffer;

    [GlobalSetup]
    public void Setup()
    {
        _data = RandomNumberGenerator.GetBytes(4000);
        _offset = RandomNumberGenerator.GetInt32(0, 3500);
        _writeBuffer = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
    }

    [Benchmark]
    public short BitConverterParseTest()
    {
        return BitConverter.ToInt16(_data, _offset);
    }

    [Benchmark]
    public short BinaryReader()
    {
        using var ms = new MemoryStream(_data);
        using var reader = new BinaryReader(ms);
        reader.BaseStream.Position = _offset;
        return reader.ReadInt16();
    }

    [Benchmark]
    public short BinaryPrimitivesRead()
    {
        return BinaryPrimitives.ReadInt16LittleEndian(
            new ArraySegment<byte>(_data, _offset, sizeof(short)));
    }

    [Benchmark]
    public void BinaryPrimitivesWrite()
    {
        BinaryPrimitives.WriteInt32LittleEndian(_data.AsSpan(_offset, 4),
            _writeBuffer);
    }

    [Benchmark]
    public void BitConverterCopy()
    {
        BitConverter.GetBytes(_writeBuffer).CopyTo(_data, _offset);
    }

    [Benchmark]
    public void BitConverterAssignment()
    {
        var bytes = BitConverter.GetBytes(_writeBuffer);
        _data[_offset] = bytes[0];
        _data[_offset + 1] = bytes[1];
        _data[_offset + 2] = bytes[2];
        _data[_offset + 3] = bytes[3];
    }
}