public static Rune FromUtf16(byte[] array, ref int index, ByteOrder endianness = ByteOrder.LittleEndian)
        {
            var decoder = new Utf16.ByteDecoder(endianness);

            if (index + 2 > array.Length)
            {
                throw new ArgumentOutOfRangeException("index", "Need at least 2 bytes to process Utf16");
            }

            decoder.Process(array[index++]);
            var result = decoder.Process(array[index++]);

            if (result == null)
            {
                if (index + 2 > array.Length)
                {
                    throw new ArgumentOutOfRangeException("index", "Need 4 bytes to process Utf16 surrogate pair");
                }

                decoder.Process(array[index++]);
                result = decoder.Process(array[index++]);

                if (result == null)
                {
                    throw new RuneException(Utf16.MissingTrailingSurrogateMessage());
                }
            }

            return(new Rune(result.GetValueOrDefault()));
        }
        private static Rune[] UncheckedToRuneArray(string value, int start, int amount)
        {
            if (start < 0 || start > value.Length)
            {
                throw new ArgumentOutOfRangeException("start");
            }

            if (amount < 0 || start + amount > value.Length)
            {
                throw new ArgumentOutOfRangeException("amount");
            }


            var runes = new Rune[amount];

            int index = 0;


            var decoder = new Utf16.CharDecoder();

            bool result = true;

            for (int i = start; i < amount; i++)
            {
                var utf32 = decoder.Process(value[i]);

                if (utf32 != null)
                {
                    runes[index++] = (Rune)utf32.GetValueOrDefault();
                }
            }


            if (!result)
            {
                throw new RuneException(Utf16.MissingTrailingSurrogateMessage());
            }


            if (index < runes.Length)
            {
                Array.Resize(ref runes, index);
            }

            return(runes);
        }
        private static IEnumerable <Rune> UncheckedToRunes(string value, int start, int amount)
        {
            if (start < 0 || start > value.Length)
            {
                throw new ArgumentOutOfRangeException("start");
            }

            if (amount < 0 || start + amount > value.Length)
            {
                throw new ArgumentOutOfRangeException("amount");
            }


            var runes = new Rune[amount];


            var decoder = new Utf16.CharDecoder();

            bool result = true;

            for (int i = start; i < amount; i++)
            {
                var utf32 = decoder.Process(value[i]);

                if (utf32 != null)
                {
                    yield return((Rune)utf32.GetValueOrDefault());
                }
            }


            if (!result)
            {
                throw new RuneException(Utf16.MissingTrailingSurrogateMessage());
            }
        }
        // char... -> Rune...
        public static IEnumerable <Rune> ToRunes(this IEnumerable <char> chars)
        {
            var decoder = new Utf16.CharDecoder();

            return(DecodeValues(chars, decoder, Utf16.MissingTrailingSurrogateMessage()));
        }