/***
* ==++==
*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ==--==
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Asynchronous I/O: streams API, used for formatted input and output, based on unformatted I/O using stream buffers
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
#pragma once

#ifndef _CASA_STREAMS_H
#define _CASA_STREAMS_H

#include "cpprest/astreambuf.h"
#include <iosfwd>

namespace Concurrency { namespace streams
{
    template<typename CharType> class basic_ostream;
    template<typename CharType> class basic_istream;

    namespace details {
    template<typename CharType>
        class basic_ostream_helper
        {
        public:
            basic_ostream_helper(streams::streambuf<CharType> buffer) : m_buffer(buffer) { }

            ~basic_ostream_helper() { }

        private:
            template<typename CharType1> friend class streams::basic_ostream;

            concurrency::streams::streambuf<CharType> m_buffer;
        };

        template<typename CharType>
        class basic_istream_helper
        {
        public:
            basic_istream_helper(streams::streambuf<CharType> buffer) : m_buffer(buffer) { }

            ~basic_istream_helper() { }

        private:
            template<typename CharType1> friend class streams::basic_istream;

            concurrency::streams::streambuf<CharType> m_buffer;
        };

        template <typename CharType>
        struct Value2StringFormatter
        {
            template <typename T>
            static std::basic_string<CharType> format(const T &val)
            {
                std::basic_ostringstream<CharType> ss;
                ss << val;
                return ss.str();
            }
        };

        template <>
        struct Value2StringFormatter <uint8_t>
        {
            template <typename T>
            static std::basic_string<uint8_t> format(const T &val)
            {
                std::basic_ostringstream<char> ss;
                ss << val;
                return reinterpret_cast<const uint8_t *>(ss.str().c_str());
            }

            static std::basic_string<uint8_t> format(const utf16string &val)
            {
                return format(utility::conversions::utf16_to_utf8(val));
            }

        };

        static const char *_in_stream_msg = "stream not set up for input of data";
        static const char *_in_streambuf_msg = "stream buffer not set up for input of data";
        static const char *_out_stream_msg = "stream not set up for output of data";
        static const char *_out_streambuf_msg = "stream buffer not set up for output of data";
    }

    /// <summary>
    /// Base interface for all asynchronous output streams.
    /// </summary>
    template<typename CharType>
    class basic_ostream
    {
    public:

        typedef Concurrency::streams::char_traits<CharType> traits;
        typedef typename traits::int_type int_type;
        typedef typename traits::pos_type pos_type;
        typedef typename traits::off_type off_type;

        /// <summary>
        /// Default constructor
        /// </summary>
        basic_ostream() {}

        /// <summary>
        /// Copy constructor
        /// </summary>
        /// <param name="other">The source object</param>
        basic_ostream(const basic_ostream &other) : m_helper(other.m_helper) { }

        /// <summary>
        /// Assignment operator
        /// </summary>
        /// <param name="other">The source object</param>
        /// <returns>A reference to the stream object that contains the result of the assignment.</returns>
        basic_ostream & operator =(const basic_ostream &other) { m_helper = other.m_helper; return *this; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="buffer">A stream buffer.</param>
        basic_ostream(streams::streambuf<CharType> buffer) :
            m_helper(std::make_shared<details::basic_ostream_helper<CharType>>(buffer))
        {
            _verify_and_throw(details::_out_streambuf_msg);
        }

        /// <summary>
        /// Close the stream, preventing further write operations.
        /// </summary>
        pplx::task<void> close() const
        {
            return is_valid() ?
                helper()->m_buffer.close(std::ios_base::out) :
                pplx::task_from_result();
        }

        /// <summary>
        /// Close the stream with exception, preventing further write operations.
        /// </summary>
        /// <param name="eptr">Pointer to the exception.</param>
        pplx::task<void> close(std::exception_ptr eptr) const
        {
            return is_valid() ?
                helper()->m_buffer.close(std::ios_base::out, eptr) :
                pplx::task_from_result();
        }

        /// <summary>
        /// Put a single character into the stream.
        /// </summary>
        /// <param name="ch">A character</param>
        pplx::task<int_type> write(CharType ch) const
        {
            pplx::task<int_type> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
            return helper()->m_buffer.putc(ch);
        }

        /// <summary>
        /// Write a single value of "blittable" type T into the stream.
        /// </summary>
        /// <param name="value">A value of type T.</param>
        /// <remarks>
        /// This is not a replacement for a proper binary serialization solution, but it may
        /// form the foundation for one. Writing data bit-wise to a stream is a primitive
        /// operation of binary serialization.
        /// Currently, no attention is paid to byte order. All data is written in the platform's
        /// native byte order, which means little-endian on all platforms that have been tested.
        /// This function is only available for streams using a single-byte character size.
        /// </remarks>
        template<typename T>
        CASABLANCA_DEPRECATED("Unsafe API that will be removed in future releases, use one of the other write overloads instead.")
        pplx::task<size_t> write(T value) const
        {
            static_assert(sizeof(CharType) == 1, "binary write is only supported for single-byte streams");
            static_assert(std::is_trivial<T>::value, "unsafe to use with non-trivial types");

            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;

            auto copy = std::make_shared<T>(std::move(value));
            return helper()->m_buffer.putn_nocopy((CharType*)copy.get(), sizeof(T)).then([copy](pplx::task<size_t> op) -> size_t { return op.get(); });
        }

        /// <summary>
        /// Write a number of characters from a given stream buffer into the stream.
        /// </summary>
        /// <param name="source">A source stream buffer.</param>
        /// <param name="count">The number of characters to write.</param>
        pplx::task<size_t> write(streams::streambuf<CharType> source, size_t count) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
            if ( !source.can_read() )
                return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data")));

            if (count == 0)
                return pplx::task_from_result((size_t)0);

            auto buffer = helper()->m_buffer;
            auto data = buffer.alloc(count);

            if ( data != nullptr )
            {
                auto post_read =
                    [buffer](pplx::task<size_t> op)-> pplx::task<size_t>
                    {
                        auto b = buffer;
                        b.commit(op.get());
                        return op;
                    };
                return source.getn(data, count).then(post_read);
            }
            else
            {
                size_t available = 0;

                const bool acquired = source.acquire(data, available);
                if (available >= count)
                {
                    auto post_write =
                        [source,data](pplx::task<size_t> op)-> pplx::task<size_t>
                        {
                            auto s = source;
                            s.release(data,op.get());
                            return op;
                        };
                    return buffer.putn_nocopy(data, count).then(post_write);
                }
                else
                {
                    // Always have to release if acquire returned true.
                    if(acquired)
                    {
                        source.release(data, 0);
                    }

                    std::shared_ptr<CharType> buf(new CharType[count], [](CharType *buf) { delete [] buf; });

                    auto post_write =
                        [buf](pplx::task<size_t> op)-> pplx::task<size_t>
                        {
                            return op;
                        };
                    auto post_read =
                        [buf,post_write,buffer](pplx::task<size_t> op) -> pplx::task<size_t>
                        {
                            auto b = buffer;
                            return b.putn_nocopy(buf.get(), op.get()).then(post_write);
                        };

                    return source.getn(buf.get(), count).then(post_read);
                }
            }
        }

        /// <summary>
        /// Write the specified string to the output stream.
        /// </summary>
        /// <param name="str">Input string.</param>
        pplx::task<size_t> print(const std::basic_string<CharType>& str) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;

            if (str.empty())
            {
                return pplx::task_from_result<size_t>(0);
            }
            else
            {
                auto sharedStr = std::make_shared<std::basic_string<CharType>>(str);
                return helper()->m_buffer.putn_nocopy(sharedStr->c_str(), sharedStr->size()).then([sharedStr](size_t size) { return size; });
            }
        }

        /// <summary>
        /// Write a value of type <c>T</c> to the output stream.
        /// </summary>
        /// <typeparam name="T">
        /// The data type of the object to be written to the stream
        /// </typeparam>
        /// <param name="val">Input object.</param>
        template<typename T>
        pplx::task<size_t> print(const T& val) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
            // TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy
            // by putting the string on the heap before calling the print string overload.
            return print(details::Value2StringFormatter<CharType>::format(val));
        }

        /// <summary>
        /// Write a value of type <c>T</c> to the output stream and append a newline character.
        /// </summary>
        /// <typeparam name="T">
        /// The data type of the object to be written to the stream
        /// </typeparam>
        /// <param name="val">Input object.</param>
        template<typename T>
        pplx::task<size_t> print_line(const T& val) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
            auto str = details::Value2StringFormatter<CharType>::format(val);
            str.push_back(CharType('\n'));
            return print(str);
        }

        /// <summary>
        /// Flush any buffered output data.
        /// </summary>
        pplx::task<void> flush() const
        {
            pplx::task<void> result;
            if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
            return helper()->m_buffer.sync();
        }

        /// <summary>
        /// Seeks to the specified write position.
        /// </summary>
        /// <param name="pos">An offset relative to the beginning of the stream.</param>
        /// <returns>The new position in the stream.</returns>
        pos_type seek(pos_type pos) const
        {
            _verify_and_throw(details::_out_stream_msg);
            return helper()->m_buffer.seekpos(pos, std::ios_base::out);
        }

        /// <summary>
        /// Seeks to the specified write position.
        /// </summary>
        /// <param name="off">An offset relative to the beginning, current write position, or the end of the stream.</param>
        /// <param name="way">The starting point (beginning, current, end) for the seek.</param>
        /// <returns>The new position in the stream.</returns>
        pos_type seek(off_type off, std::ios_base::seekdir way) const
        {
            _verify_and_throw(details::_out_stream_msg);
            return helper()->m_buffer.seekoff(off, way, std::ios_base::out);
        }

        /// <summary>
        /// Get the current write position, i.e. the offset from the beginning of the stream.
        /// </summary>
        /// <returns>The current write position.</returns>
        pos_type tell() const
        {
            _verify_and_throw(details::_out_stream_msg);
            return helper()->m_buffer.getpos(std::ios_base::out);
        }

        /// <summary>
        /// <c>can_seek<c/> is used to determine whether the stream supports seeking.
        /// </summary>
        /// <returns><c>true</c> if the stream supports seeking, <c>false</c> otherwise.</returns>
        bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); }

        /// <summary>
        /// Test whether the stream has been initialized with a valid stream buffer.
        /// </summary>
        /// <returns><c>true</c> if the stream has been initialized with a valid stream buffer, <c>false</c> otherwise.</returns>
        bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); }

        /// <summary>
        /// Test whether the stream has been initialized or not.
        /// </summary>
        operator bool() const { return is_valid(); }

        /// <summary>
        /// Test whether the stream is open for writing.
        /// </summary>
        /// <returns><c>true</c> if the stream is open for writing, <c>false</c> otherwise.</returns>
        bool is_open() const { return is_valid() && m_helper->m_buffer.can_write(); }

        /// <summary>
        /// Get the underlying stream buffer.
        /// </summary>
        /// <returns>The underlying stream buffer.</returns>
        concurrency::streams::streambuf<CharType> streambuf() const
        {
            return helper()->m_buffer;
        }

    protected:

        void set_helper(std::shared_ptr<details::basic_ostream_helper<CharType>> helper)
        {
            m_helper = helper;
        }

    private:

        template<typename T>
        bool _verify_and_return_task(const char *msg, pplx::task<T> &tsk) const
        {
            auto buffer = helper()->m_buffer;
            if ( !(buffer.exception() == nullptr) )
            {
                tsk = pplx::task_from_exception<T>(buffer.exception());
                return false;
            }
            if ( !buffer.can_write() )
            {
                tsk = pplx::task_from_exception<T>(std::make_exception_ptr(std::runtime_error(msg)));
                return false;
            }
            return true;
        }

        void _verify_and_throw(const char *msg) const
        {
            auto buffer = helper()->m_buffer;
            if ( !(buffer.exception() == nullptr) )
                std::rethrow_exception(buffer.exception());
            if ( !buffer.can_write() )
                throw std::runtime_error(msg);
        }

        std::shared_ptr<details::basic_ostream_helper<CharType>> helper() const
        {
            if ( !m_helper )
                throw std::logic_error("uninitialized stream object");
            return m_helper;
        }

        std::shared_ptr<details::basic_ostream_helper<CharType>> m_helper;
    };

    template<typename int_type>
    struct _type_parser_integral_traits
    {
        typedef std::false_type _is_integral;
        typedef std::false_type _is_unsigned;
    };

#ifdef _WIN32
#define _INT_TRAIT(_t,_low,_high)  template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::false_type _is_unsigned;static const int64_t _min = _low;static const int64_t _max = _high;};
#define _UINT_TRAIT(_t,_low,_high) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::true_type  _is_unsigned;static const uint64_t _max = _high;};

    _INT_TRAIT(char,INT8_MIN,INT8_MAX)
    _INT_TRAIT(signed char,INT8_MIN,INT8_MAX)
    _INT_TRAIT(short,INT16_MIN,INT16_MAX)
    _INT_TRAIT(utf16char,INT16_MIN,INT16_MAX)
    _INT_TRAIT(int,INT32_MIN,INT32_MAX)
    _INT_TRAIT(long, LONG_MIN, LONG_MAX)
    _INT_TRAIT(long long, LLONG_MIN, LLONG_MAX)
    _UINT_TRAIT(unsigned char,UINT8_MIN,UINT8_MAX)
    _UINT_TRAIT(unsigned short,UINT16_MIN,UINT16_MAX)
    _UINT_TRAIT(unsigned int,UINT32_MIN,UINT32_MAX)
    _UINT_TRAIT(unsigned long, ULONG_MIN, ULONG_MAX)
    _UINT_TRAIT(unsigned long long, ULLONG_MIN, ULLONG_MAX)
#else
#define _INT_TRAIT(_t)  template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::false_type _is_unsigned;static const int64_t _min = std::numeric_limits<_t>::min();static const int64_t _max = (std::numeric_limits<_t>::max)();};
#define _UINT_TRAIT(_t) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::true_type  _is_unsigned;static const uint64_t _max = (std::numeric_limits<_t>::max)();};

    _INT_TRAIT(char)
    _INT_TRAIT(signed char)
    _INT_TRAIT(short)
    _INT_TRAIT(utf16char)
    _INT_TRAIT(int)
    _INT_TRAIT(long)
    _INT_TRAIT(long long)
    _UINT_TRAIT(unsigned char)
    _UINT_TRAIT(unsigned short)
    _UINT_TRAIT(unsigned int)
    _UINT_TRAIT(unsigned long)
    _UINT_TRAIT(unsigned long long)
#endif

    template<typename CharType>
    class _type_parser_base
    {
    public:
        typedef typename ::concurrency::streams::char_traits<CharType>::int_type int_type;

        _type_parser_base()  { }

    protected:
        // Aid in parsing input: skipping whitespace characters.
        static pplx::task<void> _skip_whitespace(streams::streambuf<CharType> buffer);

        // Aid in parsing input: peek at a character at a time, call type-specific code to examine, extract value when done.
        // <remark>AcceptFunctor should model std::function<bool(std::shared_ptr<X>, int_type)></remark>
        // <remark>ExtractFunctor should model std::function<pplx::task<ReturnType>(std::shared_ptr<X>)></remark>
        template<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>
        static pplx::task<ReturnType> _parse_input(streams::streambuf<CharType> buffer, AcceptFunctor accept_character, ExtractFunctor extract);
    };

    /// <summary>
    /// Class used to handle asychronous parsing for basic_istream::extract. To support new
    /// types create a new template specialization and implement the parse function.
    /// </summary>
    template<typename CharType, typename T>
    class type_parser
    {
    public:
        static pplx::task<T> parse(streams::streambuf<CharType> buffer)
        {
            typename _type_parser_integral_traits<T>::_is_integral ii;
            typename _type_parser_integral_traits<T>::_is_unsigned ui;
            return _parse(buffer, ii, ui);
        }
    private:
        static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::false_type, std::false_type)
        {
            _parse_floating_point(buffer);
        }

        static pplx::task<T> _parse(streams::streambuf<CharType>, std::false_type, std::true_type)
        {
#ifdef _WIN32
            static_assert(false, "type is not supported for extraction from a stream");
#else
            throw std::runtime_error("type is not supported for extraction from a stream");
#endif
        }

        static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::true_type, std::false_type)
        {
            return type_parser<CharType,int64_t>::parse(buffer).then(
                [] (pplx::task<int64_t> op) -> T
                {
                    int64_t val = op.get();
                    if ( val <= _type_parser_integral_traits<T>::_max && val >= _type_parser_integral_traits<T>::_min )
                        return (T)val;
                    else
                        throw std::range_error("input out of range for target type");
                });
        }

        static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::true_type, std::true_type)
        {
            return type_parser<CharType,uint64_t>::parse(buffer).then(
                [] (pplx::task<uint64_t> op) -> T
                {
                    uint64_t val = op.get();
                    if ( val <= _type_parser_integral_traits<T>::_max )
                        return (T)val;
                    else
                        throw std::range_error("input out of range for target type");
                });
        }
    };

    /// <summary>
    /// Base interface for all asynchronous input streams.
    /// </summary>
    template<typename CharType>
    class basic_istream
    {
    public:

        typedef char_traits<CharType> traits;
        typedef typename char_traits<CharType>::int_type int_type;
        typedef typename traits::pos_type pos_type;
        typedef typename traits::off_type off_type;


        /// <summary>
        /// Default constructor
        /// </summary>
        basic_istream() {}

        /// <summary>
        /// Constructor
        /// </summary>
        /// <typeparam name="CharType">
        /// The data type of the basic element of the stream.
        /// </typeparam>
        /// <param name="buffer">A stream buffer.</param>
        basic_istream(streams::streambuf<CharType> buffer) : m_helper(std::make_shared<details::basic_istream_helper<CharType>>(buffer))
        {
            _verify_and_throw(details::_in_streambuf_msg);
        }

        /// <summary>
        /// Copy constructor
        /// </summary>
        /// <param name="other">The source object</param>
        basic_istream(const basic_istream &other) : m_helper(other.m_helper) { }

        /// <summary>
        /// Assignment operator
        /// </summary>
        /// <param name="other">The source object</param>
        /// <returns>A reference to the stream object that contains the result of the assignment.</returns>
        basic_istream & operator =(const basic_istream &other)
        {
            m_helper = other.m_helper;
            return *this;
        }

        /// <summary>
        /// Close the stream, preventing further read operations.
        /// </summary>
        pplx::task<void> close() const
        {
            return is_valid() ?
                helper()->m_buffer.close(std::ios_base::in) :
                pplx::task_from_result();
        }

        /// <summary>
        /// Close the stream with exception, preventing further read operations.
        /// </summary>
        /// <param name="eptr">Pointer to the exception.</param>
        pplx::task<void> close(std::exception_ptr eptr) const
        {
            return is_valid() ?
                m_helper->m_buffer.close(std::ios_base::in, eptr) :
                pplx::task_from_result();
        }

        /// <summary>
        /// Tests whether last read cause the stream reach EOF.
        /// </summary>
        /// <returns>True if the read head has reached the end of the stream, false otherwise.</returns>
        bool is_eof() const
        {
            return is_valid() ? m_helper->m_buffer.is_eof() : false;
        }

        /// <summary>
        /// Get the next character and return it as an int_type. Advance the read position.
        /// </summary>
        /// <returns>A <c>task</c> that holds the next character as an <c>int_type</c> on successful completion.</returns>
        pplx::task<int_type> read() const
        {
            pplx::task<int_type> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
            return helper()->m_buffer.bumpc();
        }

        /// <summary>
        /// Read a single value of "blittable" type T from the stream.
        /// </summary>
        /// <returns>A value of type T.</returns>
        /// <remarks>
        /// This is not a replacement for a proper binary serialization solution, but it may
        /// form the foundation for one. Reading data bit-wise to a stream is a primitive
        /// operation of binary serialization.
        /// Currently, no attention is paid to byte order. All data is read in the platform's
        /// native byte order, which means little-endian on all platforms that have been tested.
        /// This function is only available for streams using a single-byte character size.
        /// </remarks>
        template<typename T>
        CASABLANCA_DEPRECATED("Unsafe API that will be removed in future releases, use one of the other read overloads instead.")
        pplx::task<T> read() const
        {
            static_assert(sizeof(CharType) == 1, "binary read is only supported for single-byte streams");
            static_assert(std::is_trivial<T>::value, "unsafe to use with non-trivial types");

            pplx::task<T> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;

            auto copy = std::make_shared<T>();
            return helper()->m_buffer.getn((CharType*)copy.get(), sizeof(T)).then([copy](pplx::task<size_t>) -> T
            {
                return std::move(*copy);
            });
        }

        /// <summary>
        /// Reads up to <c>count</c> characters and place into the provided buffer.
        /// </summary>
        /// <param name="target">An async stream buffer supporting write operations.</param>
        /// <param name="count">The maximum number of characters to read</param>
        /// <returns>A <c>task</c> that holds the number of characters read. This number is 0 if the end of the stream is reached.</returns>
        pplx::task<size_t> read(streams::streambuf<CharType> target, size_t count) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
            if ( !target.can_write() )
                return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("target not set up for output of data")));

            // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.
            auto buffer = helper()->m_buffer;

            auto data = target.alloc(count);

            if ( data != nullptr )
            {
                auto post_read =
                    [target](pplx::task<size_t> op)-> pplx::task<size_t>
                    {
                        auto t = target;
                        t.commit(op.get());
                        return op;
                    };
                return buffer.getn(data, count).then(post_read);
            }
            else
            {
                size_t available = 0;

                const bool acquired = buffer.acquire(data, available);
                if (available >= count)
                {
                    auto post_write =
                        [buffer,data](pplx::task<size_t> op)-> pplx::task<size_t>
                        {
                            auto b = buffer;
                            b.release(data, op.get());
                            return op;
                        };
                    return target.putn_nocopy(data, count).then(post_write);
                }
                else
                {
                    // Always have to release if acquire returned true.
                    if(acquired)
                    {
                        buffer.release(data, 0);
                    }

                    std::shared_ptr<CharType> buf(new CharType[count], [](CharType *buf) { delete [] buf; });

                    auto post_write =
                        [buf](pplx::task<size_t> op) -> pplx::task<size_t>
                        {
                            return op;
                        };
                    auto post_read =
                        [buf,target,post_write](pplx::task<size_t> op) -> pplx::task<size_t>
                        {
                            auto trg = target;
                            return trg.putn_nocopy(buf.get(), op.get()).then(post_write);
                        };

                    return helper()->m_buffer.getn(buf.get(), count).then(post_read);
                }
            }
        }

        /// <summary>
        /// Get the next character and return it as an int_type. Do not advance the read position.
        /// </summary>
        /// <returns>A <c>task</c> that holds the character, widened to an integer. This character is EOF when the peek operation fails.</returns>
        pplx::task<int_type> peek() const
        {
            pplx::task<int_type> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
            return helper()->m_buffer.getc();
        }

        /// <summary>
        /// Read characters until a delimiter or EOF is found, and place them into the target.
        /// Proceed past the delimiter, but don't include it in the target buffer.
        /// </summary>
        /// <param name="target">An async stream buffer supporting write operations.</param>
        /// <param name="delim">The delimiting character to stop the read at.</param>
        /// <returns>A <c>task</c> that holds the number of characters read.</returns>
        pplx::task<size_t> read_to_delim(streams::streambuf<CharType> target, int_type delim) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
            if ( !target.can_write() )
                return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("target not set up for output of data")));

            // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.
            auto buffer = helper()->m_buffer;

            int_type req_async = ::concurrency::streams::char_traits<CharType>::requires_async();

            std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>();

            auto flush = [=]() mutable
            {
                return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable
                {
                    _locals->total += wrote;
                    _locals->write_pos = 0;
                    return target.sync();
                });
            };

            auto update = [=](int_type ch) mutable
                {
                    if (ch == ::concurrency::streams::char_traits<CharType>::eof()) return false;
                    if (ch == delim) return false;

                    _locals->outbuf[_locals->write_pos] = static_cast<CharType>(ch);
                    _locals->write_pos += 1;

                    if (_locals->is_full())
                    {
                        // Flushing synchronously because performance is terrible if we
                        // schedule an empty task. This isn't on a user's thread.
                        flush().get();
                    }

                    return true;
                };

            auto loop = pplx::details::do_while([=]() mutable -> pplx::task<bool>
                {
                    while (buffer.in_avail() > 0)
                    {
                        int_type ch = buffer.sbumpc();

                        if (ch == req_async)
                        {
                            break;
                        }

                        if (!update(ch))
                        {
                            return pplx::task_from_result(false);
                        }
                    }
                    return buffer.bumpc().then(update);
                });

            return loop.then([=](bool) mutable
            {
                return flush().then([=] { return _locals->total; });
            });
        }

        /// <summary>
        /// Read until reaching a newline character. The newline is not included in the target.
        /// </summary>
        /// <param name="target">An asynchronous stream buffer supporting write operations.</param>
        /// <returns>A <c>task</c> that holds the number of characters read. This number is 0 if the end of the stream is reached.</returns>
        pplx::task<size_t> read_line(streams::streambuf<CharType> target) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
            if ( !target.can_write() )
                return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("target not set up for receiving data")));

            // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.
            concurrency::streams::streambuf<CharType> buffer = helper()->m_buffer;

            typename concurrency::streams::char_traits<CharType>::int_type req_async = concurrency::streams::char_traits<CharType>::requires_async();

            std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>();

            auto flush = [=]() mutable
            {
                return target.putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](size_t wrote) mutable
                {
                    _locals->total += wrote;
                    _locals->write_pos = 0;
                    return target.sync();
                });
            };

            auto update = [=](typename concurrency::streams::char_traits<CharType>::int_type ch) mutable
                {
                    if (ch == concurrency::streams::char_traits<CharType>::eof()) return false;
                    if (ch == '\n') return false;
                    if (ch == '\r')
                    {
                        _locals->saw_CR = true;
                        return true;
                    }

                    _locals->outbuf[_locals->write_pos] = static_cast<CharType>(ch);
                    _locals->write_pos += 1;

                    if (_locals->is_full())
                    {
                        // Flushing synchronously because performance is terrible if we
                        // schedule an empty task. This isn't on a user's thread.
                        flush().wait();
                    }

                    return true;
                };

            auto update_after_cr = [=] (typename concurrency::streams::char_traits<CharType>::int_type ch) mutable -> pplx::task<bool>
                {
                    if (ch == concurrency::streams::char_traits<CharType>::eof()) return pplx::task_from_result(false);
                    if (ch == '\n')
                    {
						return buffer.bumpc().then([](
#ifndef _WIN32 // Required by GCC
							typename
#endif
							concurrency::streams::char_traits<CharType>::int_type) { return false; });
                    }
                    return pplx::task_from_result(false);
                };

            auto loop = pplx::details::do_while([=]() mutable -> pplx::task<bool>
                {
                    while ( buffer.in_avail() > 0 )
                    {
#ifndef _WIN32 // Required by GCC, because concurrency::streams::char_traits<CharType> is a dependent scope
                        typename
#endif
                        concurrency::streams::char_traits<CharType>::int_type ch;

                        if (_locals->saw_CR)
                        {
                            ch = buffer.sgetc();
                            if (ch == '\n')
                                buffer.sbumpc();
                            return pplx::task_from_result(false);
                        }

                        ch = buffer.sbumpc();

                        if (ch == req_async)
                            break;

                        if (!update(ch))
                        {
                            return pplx::task_from_result(false);
                        }
                    }

                    if (_locals->saw_CR)
                    {
                        return buffer.getc().then(update_after_cr);
                    }
                    return buffer.bumpc().then(update);
                });

            return loop.then([=](bool) mutable
            {
                return flush().then([=] { return _locals->total; });
            });
        }

        /// <summary>
        /// Read until reaching the end of the stream.
        /// </summary>
        /// <param name="target">An asynchronous stream buffer supporting write operations.</param>
        /// <returns>The number of characters read.</returns>
        pplx::task<size_t> read_to_end(streams::streambuf<CharType> target) const
        {
            pplx::task<size_t> result;
            if ( !_verify_and_return_task("stream not set up for output of data", result) ) return result;
            if ( !target.can_write() )
                return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data")));

            auto l_buffer = helper()->m_buffer;
            auto l_buf_size = this->buf_size;
            std::shared_ptr<_read_helper> l_locals = std::make_shared<_read_helper>();

            auto copy_to_target = [l_locals, target, l_buffer, l_buf_size]() mutable -> pplx::task<bool>
            {
                // We need to capture these, because the object itself may go away
                // before we're done processing the data.
                //auto locs = _locals;
                //auto trg = target;

                return l_buffer.getn(l_locals->outbuf, l_buf_size).then([=](size_t rd) mutable -> pplx::task<bool>
                {
                    if (rd == 0)
                        return pplx::task_from_result(false);

                    // Must be nested to capture rd
                    return target.putn_nocopy(l_locals->outbuf, rd).then([target, l_locals, rd](size_t wr) mutable -> pplx::task<bool>
                    {
                        l_locals->total += wr;

                        if (rd != wr)
                            // Number of bytes written is less than number of bytes received.
                            throw std::runtime_error("failed to write all bytes");

                        return target.sync().then([]() { return true; });
                    });
                });
            };

            auto loop = pplx::details::do_while(copy_to_target);

            return loop.then([=](bool) mutable -> size_t
                {
                    return l_locals->total;
                });
        }

        /// <summary>
        /// Seeks to the specified write position.
        /// </summary>
        /// <param name="pos">An offset relative to the beginning of the stream.</param>
        /// <returns>The new position in the stream.</returns>
        pos_type seek(pos_type pos) const
        {
            _verify_and_throw(details::_in_stream_msg);
            return helper()->m_buffer.seekpos(pos, std::ios_base::in);
        }

        /// <summary>
        /// Seeks to the specified write position.
        /// </summary>
        /// <param name="off">An offset relative to the beginning, current write position, or the end of the stream.</param>
        /// <param name="way">The starting point (beginning, current, end) for the seek.</param>
        /// <returns>The new position in the stream.</returns>
        pos_type seek(off_type off, std::ios_base::seekdir way) const
        {
            _verify_and_throw(details::_in_stream_msg);
            return helper()->m_buffer.seekoff(off, way, std::ios_base::in);
        }

        /// <summary>
        /// Get the current write position, i.e. the offset from the beginning of the stream.
        /// </summary>
        /// <returns>The current write position.</returns>
        pos_type tell() const
        {
            _verify_and_throw(details::_in_stream_msg);
            return helper()->m_buffer.getpos(std::ios_base::in);
        }

        /// <summary>
        /// <c>can_seek<c/> is used to determine whether the stream supports seeking.
        /// </summary>
        /// <returns><c>true</c> if the stream supports seeking, <c>false</c> otherwise.</returns>
        bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); }

        /// <summary>
        /// Test whether the stream has been initialized with a valid stream buffer.
        /// </summary>
        bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); }

        /// <summary>
        /// Test whether the stream has been initialized or not.
        /// </summary>
        operator bool() const { return is_valid(); }

        /// <summary>
        /// Test whether the stream is open for writing.
        /// </summary>
        /// <returns><c>true</c> if the stream is open for writing, <c>false</c> otherwise.</returns>
        bool is_open() const { return is_valid() && m_helper->m_buffer.can_read(); }

        /// <summary>
        /// Get the underlying stream buffer.
        /// </summary>
        concurrency::streams::streambuf<CharType> streambuf() const
        {
            return helper()->m_buffer;
        }

        /// <summary>
        /// Read a value of type <c>T</c> from the stream.
        /// </summary>
        /// <remarks>
        /// Supports the C++ primitive types. Can be expanded to additional types
        /// by adding template specializations for <c>type_parser</c>.
        /// </remarks>
        /// <typeparam name="T">
        /// The data type of the element to be read from the stream.
        /// </typeparam>
        /// <returns>A <c>task</c> that holds the element read from the stream.</returns>
        template<typename T>
        pplx::task<T> extract() const
        {
            pplx::task<T> result;
            if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
            return type_parser<CharType,T>::parse(helper()->m_buffer);
        }

    private:

        template<typename T>
        bool _verify_and_return_task(const char *msg, pplx::task<T> &tsk) const
        {
            auto buffer = helper()->m_buffer;
            if ( !(buffer.exception() == nullptr) )
            {
                tsk = pplx::task_from_exception<T>(buffer.exception());
                return false;
            }
            if ( !buffer.can_read() )
            {
                tsk = pplx::task_from_exception<T>(std::make_exception_ptr(std::runtime_error(msg)));
                return false;
            }
            return true;
        }

        void _verify_and_throw(const char *msg) const
        {
            auto buffer = helper()->m_buffer;
            if ( !(buffer.exception() == nullptr) )
                std::rethrow_exception(buffer.exception());
            if ( !buffer.can_read() )
                throw std::runtime_error(msg);
        }

        std::shared_ptr<details::basic_istream_helper<CharType>> helper() const
        {
            if ( !m_helper )
                throw std::logic_error("uninitialized stream object");
            return m_helper;
        }

        static const size_t buf_size = 16*1024;

        struct _read_helper
        {
            size_t total;
            CharType outbuf[buf_size];
            size_t write_pos;
            bool saw_CR;

            bool is_full() const
            {
                return write_pos == buf_size;
            }

            _read_helper() : total(0), write_pos(0), saw_CR(false)
            {
            }
        };

        std::shared_ptr<details::basic_istream_helper<CharType>> m_helper;
    };

    typedef basic_ostream<uint8_t> ostream;
    typedef basic_istream<uint8_t> istream;

    typedef basic_ostream<utf16char> wostream;
    typedef basic_istream<utf16char> wistream;

template<typename CharType>
pplx::task<void> concurrency::streams::_type_parser_base<CharType>::_skip_whitespace(streams::streambuf<CharType> buffer)
{
    int_type req_async = concurrency::streams::char_traits<CharType>::requires_async();

    auto update = [=] (int_type ch) mutable
        {
            if (isspace(ch))
            {
                if (buffer.sbumpc() == req_async)
                {
                    // Synchronously because performance is terrible if we
                    // schedule an empty task. This isn't on a user's thread.
                    buffer.nextc().wait();
                }
                return true;
            }

            return false;
        };

    auto loop = pplx::details::do_while([=]() mutable -> pplx::task<bool>
        {
            while (buffer.in_avail() > 0)
            {
                int_type ch = buffer.sgetc();

                if (ch == req_async)
                    break;

                if (!update(ch))
                {
                    return pplx::task_from_result(false);
                }
            }
            return buffer.getc().then(update);
        });

    return loop.then([=](pplx::task<bool> op)
        {
            op.wait();
        });
}

template<typename CharType>
template<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>
pplx::task<ReturnType> concurrency::streams::_type_parser_base<CharType>::_parse_input(
    concurrency::streams::streambuf<CharType> buffer,
    AcceptFunctor accept_character,
    ExtractFunctor extract)
{
    std::shared_ptr<StateType> state = std::make_shared<StateType>();

    auto update = [=] (pplx::task<int_type> op) -> pplx::task<bool>
    {
        int_type ch = op.get();
        if (ch == concurrency::streams::char_traits<CharType>::eof()) return pplx::task_from_result(false);
        bool accptd = accept_character(state, ch);
        if (!accptd)
            return pplx::task_from_result(false);
        // We peeked earlier, so now we must advance the position.
        concurrency::streams::streambuf<CharType> buf = buffer;
        return buf.bumpc().then([](int_type) { return true; });
    };

    auto peek_char = [=]() -> pplx::task<bool>
    {
        concurrency::streams::streambuf<CharType> buf = buffer;

        // If task results are immediately available, there's little need to use ".then(),"
        // so optimize for prompt values.

        auto get_op = buf.getc();
        while (get_op.is_done())
        {
            auto condition = update(get_op);
            if (!condition.is_done() || !condition.get())
                return condition;

            get_op = buf.getc();
        }

        return get_op.then(update);
    };

    auto finish =
        [=](pplx::task<bool> op) -> pplx::task<ReturnType>
        {
            op.wait();
            pplx::task<ReturnType> result = extract(state);
            return result;
        };

    return _skip_whitespace(buffer).then([=](pplx::task<void> op) -> pplx::task<ReturnType>
        {
            op.wait();
            return pplx::details::do_while(peek_char).then(finish);
        });
}

template<typename CharType>
class type_parser<CharType,std::basic_string<CharType>> : public _type_parser_base<CharType>
{
    typedef typename _type_parser_base<CharType>::int_type int_type;
public:
    static pplx::task<std::string> parse(streams::streambuf<CharType> buffer)
    {
        return concurrency::streams::_type_parser_base<CharType>::template _parse_input<std::basic_string<CharType>, std::string>(buffer, _accept_char, _extract_result);
    }

private:
    static bool _accept_char(std::shared_ptr<std::basic_string<CharType>> state, int_type ch)
    {
        if ( ch == concurrency::streams::char_traits<CharType>::eof() || isspace(ch)) return false;
        state->push_back(CharType(ch));
        return true;
    }
    static pplx::task<std::basic_string<CharType>> _extract_result(std::shared_ptr<std::basic_string<CharType>> state)
    {
        return pplx::task_from_result(*state);
    }
};

template<typename CharType>
class type_parser<CharType,int64_t> : public _type_parser_base<CharType>
{
public:
    typedef typename _type_parser_base<CharType>::int_type int_type;
    static pplx::task<int64_t> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::template _parse_input<_int64_state, int64_t>(buffer, _accept_char, _extract_result);
    }
private:
    struct _int64_state
    {
        _int64_state() : result(0), correct(false), minus(0) {}

        int64_t result;
        bool correct;
        char minus;       // 0 -- no sign, 1 -- plus, 2 -- minus
    };

    static bool _accept_char(std::shared_ptr<_int64_state> state, int_type ch)
    {
        if ( ch == concurrency::streams::char_traits<CharType>::eof()) return false;
        if ( state->minus == 0 )
        {
            // OK to find a sign.
            if ( !::isdigit(ch) && ch != int_type('+') && ch != int_type('-') )
                return false;
        }
        else
        {
            if ( !::isdigit(ch) ) return false;
        }

        // At least one digit was found.
        state->correct = true;

        if ( ch == int_type('+') )
        {
            state->minus = 1;
        }
        else if ( ch == int_type('-') )
        {
            state->minus = 2;
        }
        else
        {
            if (state->minus == 0) state->minus = 1;

            // Shift the existing value by 10, then add the new value.
            bool positive = state->result >= 0;

            state->result *= 10;
            state->result += int64_t(ch-int_type('0'));

            if ( (state->result >= 0) != positive )
            {
                state->correct = false;
                return false;
            }
        }
        return true;
    }

    static pplx::task<int64_t> _extract_result(std::shared_ptr<_int64_state> state)
    {
        if (!state->correct)
            throw std::range_error("integer value is too large to fit in 64 bits");

        int64_t result = (state->minus == 2) ? -state->result : state->result;
        return pplx::task_from_result<int64_t>(result);
    }
};

template <typename FloatingPoint>
struct _double_state
{
    _double_state() : result(0), minus(0), after_comma(0), exponent(false), exponent_number(0), exponent_minus(0), complete(false), p_exception_string() {}

    FloatingPoint result;
    char minus;             // 0 -- no sign, 1 -- plus, 2 -- minus
    int after_comma;
    bool exponent;
    int exponent_number;
    char exponent_minus;    // 0 -- no sign, 1 -- plus, 2 -- minus
    bool complete;
    std::string p_exception_string;
};

template <typename FloatingPoint, typename int_type>
static std::string create_exception_message(int_type ch, bool exponent)
{
    std::ostringstream os;
    os << "Invalid character '" << char(ch) << "'" << (exponent ? " in exponent" : "");
    return os.str();
}

template <typename FloatingPoint, typename int_type>
static bool _accept_char(std::shared_ptr<_double_state<FloatingPoint>> state, int_type ch)
{
    if ( state->minus == 0 )
    {
        if ( !::isdigit(ch) && ch != int_type('.') && ch != int_type('+') && ch != int_type('-') )
        {
            if (!state->complete)
                state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, false);
            return false;
        }
    }
    else
    {
        if (!state->exponent && !::isdigit(ch) && ch != int_type('.') && ch != int_type('E') && ch != int_type('e'))
        {
            if (!state->complete)
                state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, false);
            return false;
        }

        if (state->exponent && !::isdigit(ch) && ch != int_type('+') && ch != int_type('-'))
        {
            if (!state->complete)
                state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, true);
            return false;
        }
    }

    switch (ch)
    {
        case int_type('+') :
            state->complete = false;
            if (state->exponent)
            {
                if (state->exponent_minus != 0)
                {
                    state->p_exception_string = "The exponent sign already set";
                    return false;
                }
                state->exponent_minus = 1;
            }
            else
            {
                state->minus = 1;
            }
            break;
        case int_type('-') :
            state->complete = false;
            if (state->exponent)
            {
                if (state->exponent_minus != 0)
                {
                    state->p_exception_string = "The exponent sign already set";
                    return false;
                }

                state->exponent_minus = 2;
            }
            else
            {
                state->minus = 2;
            }
            break;
        case int_type('.') :
            state->complete = false;
            if (state->after_comma > 0)
                return false;

            state->after_comma = 1;
            break;
        case int_type('E') : case int_type('e') :
            state->complete = false;
            if (state->exponent)
                return false;
            state->exponent_number = 0;
            state->exponent = true;
            break;
        default:
            state->complete = true;
            if (!state->exponent)
            {
                if (state->minus == 0)
                    state->minus = 1;

                state->result *= 10;
                state->result += int64_t(ch-int_type('0'));

                if (state->after_comma > 0)
                    state->after_comma++;
            }
            else
            {
                if (state->exponent_minus == 0) state->exponent_minus = 1;
                state->exponent_number *= 10;
                state->exponent_number += int64_t(ch-int_type('0'));
            }
    }
    return true;
}

template <typename FloatingPoint>
static pplx::task<FloatingPoint> _extract_result(std::shared_ptr<_double_state<FloatingPoint>> state)
{
    if (state->p_exception_string.length() > 0)
        throw std::runtime_error(state->p_exception_string.c_str());

    if (!state->complete && state->exponent)
        throw std::runtime_error("Incomplete exponent");

    FloatingPoint result = static_cast<FloatingPoint>((state->minus == 2) ? -state->result : state->result);
    if (state->exponent_minus == 2)
        state->exponent_number = 0 - state->exponent_number;

    if (state->after_comma > 0)
        state->exponent_number -= state->after_comma-1;

    if (state->exponent_number >= 0)
    {
        result *= pow(FloatingPoint(10.0), state->exponent_number);

        #pragma push_macro ("max")
        #undef max

        if (result > std::numeric_limits<FloatingPoint>::max() || result < -std::numeric_limits<FloatingPoint>::max())
            throw std::overflow_error("The value is too big");
        #pragma pop_macro ("max")
    }
    else
    {
        bool is_zero = (result == 0);

        result /= pow(FloatingPoint(10.0), -state->exponent_number);

        if (!is_zero &&
            result > -std::numeric_limits<FloatingPoint>::denorm_min() &&
            result < std::numeric_limits<FloatingPoint>::denorm_min())
            throw std::underflow_error("The value is too small");
    }

    return pplx::task_from_result<FloatingPoint>(result);
}

template<typename CharType>
class type_parser<CharType,double> : public _type_parser_base<CharType>
{
public:
    typedef typename _type_parser_base<CharType>::int_type int_type;
    static pplx::task<double> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::template _parse_input<_double_state<double>, double>(buffer, _accept_char<double, int_type>, _extract_result<double>);
    }
protected:
};

template<typename CharType>
class type_parser<CharType,float> : public _type_parser_base<CharType>
{
public:
    typedef typename _type_parser_base<CharType>::int_type int_type;
    static pplx::task<float> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::template _parse_input<_double_state<float>, float>(buffer, _accept_char<float, int_type>, _extract_result<float>);
    }
protected:
};


template<typename CharType>
class type_parser<CharType,uint64_t> : public _type_parser_base<CharType>
{
public:
    typedef typename _type_parser_base<CharType>::int_type int_type;
    static pplx::task<uint64_t> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::template _parse_input<_uint64_state,uint64_t>(buffer, _accept_char, _extract_result);
    }

private:
    struct _uint64_state
    {
        _uint64_state() : result(0), correct(false) {}
        uint64_t result;
        bool correct;
    };

    static bool _accept_char(std::shared_ptr<_uint64_state> state, int_type ch)
    {
        if ( !::isdigit(ch) ) return false;

        // At least one digit was found.
        state->correct = true;

        // Shift the existing value by 10, then add the new value.
        state->result *= 10;
        state->result += uint64_t(ch-int_type('0'));

        return true;
    }

    static pplx::task<uint64_t> _extract_result(std::shared_ptr<_uint64_state> state)
    {
        if (!state->correct)
            throw std::range_error("integer value is too large to fit in 64 bits");
        return pplx::task_from_result(state->result);
    }
};

template<typename CharType>
class type_parser<CharType,bool> : public _type_parser_base<CharType>
{
public:
    typedef typename _type_parser_base<CharType>::int_type int_type;
    static pplx::task<bool> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::template _parse_input<_bool_state,bool>(buffer, _accept_char, _extract_result);
    }
private:
    struct _bool_state
    {
        _bool_state() : state(0) { }
        // { 0 -- not started, 1 -- 't', 2 -- 'tr', 3 -- 'tru', 4 -- 'f', 5 -- 'fa', 6 -- 'fal', 7 -- 'fals', 8 -- 'true', 9 -- 'false' }
        short state;
    };

    static bool _accept_char(std::shared_ptr<_bool_state> state, int_type ch)
    {
        switch (state->state)
        {
        case 0:
            if ( ch == int_type('t') ) state->state = 1;
            else if ( ch == int_type('f') ) state->state = 4;
            else if ( ch == int_type('1') ) state->state = 8;
            else if ( ch == int_type('0') ) state->state = 9;
            else return false;
            break;
        case 1:
            if ( ch == int_type('r') ) state->state = 2;
            else return false;
            break;
        case 2:
            if ( ch == int_type('u') ) state->state = 3;
            else return false;
            break;
        case 3:
            if ( ch == int_type('e') ) state->state = 8;
            else return false;
            break;
        case 4:
            if ( ch == int_type('a') ) state->state = 5;
            else return false;
            break;
        case 5:
            if ( ch == int_type('l') ) state->state = 6;
            else return false;
            break;
        case 6:
            if ( ch == int_type('s') ) state->state = 7;
            else return false;
            break;
        case 7:
            if ( ch == int_type('e') ) state->state = 9;
            else return false;
            break;
        case 8:
        case 9:
            return false;
        }
        return true;
    }
    static pplx::task<bool> _extract_result(std::shared_ptr<_bool_state> state)
    {
        bool correct = (state->state == 8 || state->state == 9);
        if (!correct)
        {
            std::runtime_error exc("cannot parse as Boolean value");
            throw exc;
        }
        return pplx::task_from_result(state->state == 8);
    }
};

template<typename CharType>
class type_parser<CharType,signed char> : public _type_parser_base<CharType>
{
    typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
public:
    static pplx::task<signed char> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::_skip_whitespace(buffer).then(
            [=](pplx::task<void> op) -> pplx::task<signed char>
            {
                op.wait();
                return type_parser<CharType,signed char>::_get_char(buffer);
            });
    }
private:
    static pplx::task<signed char> _get_char(streams::streambuf<CharType> buffer)
    {
        concurrency::streams::streambuf<CharType> buf = buffer;
        return buf.bumpc().then(
            [=](pplx::task<typename concurrency::streams::streambuf<CharType>::int_type> op) -> signed char
            {
                int_type val = op.get();
                if (val == concurrency::streams::char_traits<CharType>::eof())
                    throw std::runtime_error("reached end-of-stream while constructing a value");
                return static_cast<signed char>(val);
            });
    }
};

template<typename CharType>
class type_parser<CharType,unsigned char> : public _type_parser_base<CharType>
{
    typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
public:
    static pplx::task<unsigned char> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::_skip_whitespace(buffer).then(
            [=](pplx::task<void> op) -> pplx::task<unsigned char>
            {
                op.wait();
                return type_parser<CharType,unsigned char>::_get_char(buffer);
            });
    }
private:
    static pplx::task<unsigned char> _get_char(streams::streambuf<CharType> buffer)
    {
        concurrency::streams::streambuf<CharType> buf = buffer;
        return buf.bumpc().then(
            [=](pplx::task<typename concurrency::streams::streambuf<CharType>::int_type> op) -> unsigned char
            {
                int_type val = op.get();
                if (val == concurrency::streams::char_traits<CharType>::eof())
                    throw std::runtime_error("reached end-of-stream while constructing a value");
                return static_cast<unsigned char>(val);
            });
    }
};

template<typename CharType>
class type_parser<CharType,char> : public _type_parser_base<CharType>
{
    typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
public:
    static pplx::task<char> parse(streams::streambuf<CharType> buffer)
    {
        return _type_parser_base<CharType>::_skip_whitespace(buffer).then(
            [=](pplx::task<void> op) -> pplx::task<char>
            {
                op.wait();
                return _get_char(buffer);
            });
    }
private:
    static pplx::task<char> _get_char(streams::streambuf<CharType> buffer)
    {
        concurrency::streams::streambuf<CharType> buf = buffer;
        return buf.bumpc().then(
            [=](pplx::task<typename concurrency::streams::streambuf<CharType>::int_type> op) -> char
            {
                int_type val = op.get();
                if (val == concurrency::streams::char_traits<CharType>::eof())
                    throw std::runtime_error("reached end-of-stream while constructing a value");
                return char(val);
            });
    }
};

#ifdef _WIN32
template<>
class type_parser<char,std::basic_string<wchar_t>> : public _type_parser_base<char>
{
public:
    static pplx::task<std::wstring> parse(streams::streambuf<char> buffer)
    {
        return _parse_input<std::basic_string<char>,std::basic_string<wchar_t>>(buffer, _accept_char, _extract_result);
    }

private:
    static bool _accept_char(const std::shared_ptr<std::basic_string<char>> &state, int_type ch)
    {
        if ( ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;
        state->push_back(char(ch));
        return true;
    }
    static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)
    {
        return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));
    }
};

template<>
class type_parser<signed char,std::basic_string<wchar_t>> : public _type_parser_base<signed char>
{
public:
    static pplx::task<std::wstring> parse(streams::streambuf<signed char> buffer)
    {
        return _parse_input<std::basic_string<char>,std::basic_string<wchar_t>>(buffer, _accept_char, _extract_result);
    }

private:
    static bool _accept_char(const std::shared_ptr<std::basic_string<char>> &state, int_type ch)
    {
        if ( ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;
        state->push_back(char(ch));
        return true;
    }
    static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)
    {
        return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));
    }
};

template<>
class type_parser<unsigned char,std::basic_string<wchar_t>> : public _type_parser_base<unsigned char>
{
public:
    static pplx::task<std::wstring> parse(streams::streambuf<unsigned char> buffer)
    {
        return _parse_input<std::basic_string<char>,std::basic_string<wchar_t>>(buffer, _accept_char, _extract_result);
    }

private:
    static bool _accept_char(const std::shared_ptr<std::basic_string<char>> &state, int_type ch)
    {
        if ( ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;
        state->push_back(char(ch));
        return true;
    }
    static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)
    {
        return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));
    }
};
#endif //_WIN32

}}

#endif
