/// <summary>
        ///     Compare two unsigned little endian <see cref="byte" /> arrays
        /// </summary>
        /// <param name="left">the left side operand</param>
        /// <param name="right">the right side operand</param>
        public static int CompareUnsignedLittleEndian([NotNull] byte[] left,
                                                      [NotNull] byte[] right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }

            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }

            var enumerable = new ConcurrentLittleEndianByteEnumerable(left, right).GetMsbToLsbEnumerable();

            foreach (var(leftByte, rightByte) in enumerable)
            {
                var comparison = leftByte.CompareTo(rightByte);

                if (comparison != 0)
                {
                    return(comparison > 0
                               ? 1
                               : -1);
                }
            }

            return(0); // bytes are equal
        }
        public static byte[] AddUnsignedLittleEndian([NotNull] byte[] left,
                                                     [NotNull] byte[] right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }

            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }

            var enumerable  = new ConcurrentLittleEndianByteEnumerable(left, right).GetLsbToMsbEnumerable();
            var resultQueue = new Queue <byte>(); // use stack for fifo
            var carry       = 0;

            foreach (var(leftByte, rightByte) in enumerable)
            {
                var sum = carry + leftByte + rightByte;

                resultQueue.Enqueue((byte)(sum & 0xFF)); // push the byte value of sum
                carry = sum >> 8;                        // new carry value is sum shifted by 8 bits (a byte)
            }

            if (carry != 0)                       // if a carry value exists it should be pushed as it is the new MSB
            {
                resultQueue.Enqueue((byte)carry); // enqueue carry
            }

            return(resultQueue.ToArray());
        }
        public void ReverseIterate_FromByteEnumerable_Trimmed_Test(byte[] leftBytes,
                                                                   byte[] rightBytes)
        {
            // Arrange
            this._testOutputHelper.WriteLine($"left: [{leftBytes.ToString("h")}]");
            this._testOutputHelper.WriteLine($"right: [{rightBytes.ToString("h")}]");

            var expectedTrimmedLeftLength = leftBytes.Reverse()
                                            .SkipWhile(b => b == 0x00)
                                            .Count();
            var expectedTrimmedRightLength = rightBytes.Reverse()
                                             .SkipWhile(b => b == 0x00)
                                             .Count();
            var length = Math.Max(expectedTrimmedLeftLength, expectedTrimmedRightLength);

            this._testOutputHelper.WriteLine($"expectedLength: {length}");

            var expectedLeft = leftBytes.Take(expectedTrimmedLeftLength)
                               .Concat(Enumerable.Repeat((byte)0x00, length - expectedTrimmedLeftLength))
                               .Reverse()
                               .ToArray();

            var expectedRight = rightBytes.Take(expectedTrimmedRightLength)
                                .Concat(Enumerable.Repeat((byte)0x00, length - expectedTrimmedRightLength))
                                .Reverse()
                                .ToArray();

            this._testOutputHelper.WriteLine($"expected left: [{expectedLeft.ToString("h")}]");
            this._testOutputHelper.WriteLine($"expected right: [{expectedRight.ToString("h")}]");

            var enumerable = new ConcurrentLittleEndianByteEnumerable(leftBytes, rightBytes);

            // Act
            var result = enumerable.ReverseEnumerable()
                         .ToList();

            // Assert
            Assert.NotNull(result);
            Assert.IsAssignableFrom <IReadOnlyCollection <(byte leftByte, byte rightByte)> >(result);

            Assert.Equal(length, result.Count);

            var leftResult = result.Select(tuple => tuple.leftByte)
                             .ToArray();
            var rightResult = result.Select(tuple => tuple.rightByte)
                              .ToArray();

            this._testOutputHelper.WriteLine($"resulting left: [{leftResult.ToString("h")}]");
            this._testOutputHelper.WriteLine($"resulting right: [{rightResult.ToString("h")}]");

            Assert.Equal(expectedLeft, leftResult);
            Assert.Equal(expectedRight, rightResult);
            Assert.Equal(length, enumerable.Count);
        }
        public static byte[] SubtractUnsignedLittleEndian([NotNull] byte[] left,
                                                          [NotNull] byte[] right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }

            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }

            var comparison = CompareUnsignedLittleEndian(left, right);

            if (comparison == 0)
            {
                return(Array.Empty <byte>());
            }

            if (comparison == -1)
            {
                throw new InvalidOperationException("The operation would result in a non-unsigned value");
            }

            var enumerable  = new ConcurrentLittleEndianByteEnumerable(left, right).GetLsbToMsbEnumerable();
            var resultQueue = new Queue <byte>();
            var borrowed    = false;

            foreach (var(leftByte, rightByte) in enumerable)
            {
                byte minuend; // min·u·end /ˈminyəˌwend/ (noun) a quantity or number from which another is to be subtracted. Not to be confused with the subtrahend. Duh.
                var  canBorrow = leftByte > 0;

                if (borrowed && canBorrow)          // previous operation needed to borrow, and a borrow is possible
                {
                    minuend = (byte)(leftByte - 1); // decrement as this value has been borrowed from in the previous iteration
                }
                else if (borrowed)                  // && !canBorrow (implied)
                {
                    minuend = 0xff;                 // 0 byte becomes 255
                }
                else
                {
                    minuend = leftByte;
                }

                if (minuend >= rightByte) // left is big enough to subtract right
                {
                    var difference = (byte)(minuend - rightByte);
                    resultQueue.Enqueue(difference);

                    borrowed = borrowed && !canBorrow; // set borrow if a borrow happened some time previously but it could not be accommodated in this iteration; borrow from next
                }
                else // left is less than right, automatically borrow from next iteration
                {
                    var difference = (byte)((minuend + 0x0100) - rightByte); // handle borrowed
                    resultQueue.Enqueue(difference);
                    borrowed = true;
                }
            }

            return(resultQueue.ToArray()
                   .TrimLittleEndianLeadingZeroBytes());           // TODO, do without explicit trimming?
        }