static void Normalize(Stream stream, CborValue node)
        {
            switch (node.Type)
            {
            case CborValueType.Object:
                var map = (CborObject)node;
                stream.WriteByte(0xBF);
                foreach (var key in map.Keys.Select(k => k.Value <string>()).OrderBy(k => k))
                {
                    stream.WriteByte(0x78);
                    var utf = Encoding.UTF8.GetBytes(key);
                    stream.WriteByte(checked ((byte)utf.Length));
                    stream.Write(utf);
                    Normalize(stream, map[key]);
                }
                stream.WriteByte(0xFF);
                break;

            case CborValueType.Array:
                var array = (CborArray)node;
                stream.WriteByte(0x9F);
                foreach (var item in array)
                {
                    Normalize(stream, item);
                }
                stream.WriteByte(0xFF);
                break;

            case CborValueType.Positive:
                stream.WriteByte(0x1B);
                stream.Write(ToBytes(node.Value <long>()));
                break;

            case CborValueType.Negative:
                stream.WriteByte(0x3B);
                stream.Write(ToBytes(-node.Value <long>()));
                break;

            case CborValueType.Single:
            case CborValueType.Double:
                stream.WriteByte(0xFB);
                stream.Write(ToBytes(node.Value <double>()));
                break;

            case CborValueType.ByteString:
                var bytes = node.Value <ReadOnlyMemory <byte> >().ToArray();
                stream.WriteByte(0x5A);
                stream.Write(ToBytes(bytes.Length));
                stream.Write(bytes);
                break;

            case CborValueType.String:
            {
                var utf = Encoding.UTF8.GetBytes(node.Value <string>());
                stream.WriteByte(0x7A);
                stream.Write(ToBytes(utf.Length));
                stream.Write(utf);
            }
            break;

            case CborValueType.Boolean:
                if (node.Value <bool>())
                {
                    stream.WriteByte(0xF5);
                }
                else
                {
                    stream.WriteByte(0xF4);
                }
                break;

            case CborValueType.Null:
                stream.WriteByte(0xF6);
                break;

            case CborValueType.Decimal:
            case CborValueType.Undefined:
            default:
                throw new ArgumentException();
            }
        }
        public void ReadArray()
        {
            string    hexBuffer   = "8663666F6FFB40283D70A3D70A3DF5F6820102A162696401";
            CborArray actualArray = Helper.Read <CborArray>(hexBuffer);

            Assert.NotNull(actualArray);

            // values
            Assert.Equal(6, actualArray.Count);

            // string
            CborValue actualString = actualArray[0];

            Assert.NotNull(actualString);
            Assert.Equal(CborValueType.String, actualString.Type);
            Assert.IsType <CborString>(actualString);
            Assert.Equal("foo", actualString.Value <string>());

            // number
            CborValue actualNumber = actualArray[1];

            Assert.NotNull(actualNumber);
            Assert.Equal(CborValueType.Double, actualNumber.Type);
            Assert.IsType <CborDouble>(actualNumber);
            Assert.Equal(12.12, actualNumber.Value <double>(), 3);

            // bool
            CborValue actualBool = actualArray[2];

            Assert.NotNull(actualBool);
            Assert.Equal(CborValueType.Boolean, actualBool.Type);
            Assert.IsType <CborBoolean>(actualBool);
            Assert.True(actualBool.Value <bool>());

            // null
            CborValue actualNull = actualArray[3];

            Assert.NotNull(actualNull);
            Assert.Equal(CborValueType.Null, actualNull.Type);

            // array
            CborValue actualArrayValue = actualArray[4];

            Assert.NotNull(actualArrayValue);
            Assert.Equal(CborValueType.Array, actualArrayValue.Type);
            Assert.IsType <CborArray>(actualArrayValue);
            CborArray CborArray = (CborArray)actualArrayValue;

            Assert.Equal(2, CborArray.Count);
            Assert.Equal(1, CborArray[0].Value <double>());
            Assert.Equal(2, CborArray[1].Value <double>());

            // object
            CborValue actualObject = actualArray[5];

            Assert.NotNull(actualObject);
            Assert.Equal(CborValueType.Object, actualObject.Type);
            Assert.IsType <CborObject>(actualObject);
            CborObject cborObject = (CborObject)actualObject;

            Assert.True(cborObject.TryGetValue("id", out CborValue value));
            Assert.Equal(CborValueType.Positive, value.Type);
            Assert.Equal(1, value.Value <int>());
        }