    // Copyright (C) 2016  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_uNSERIALIZE_Hh_
    #define DLIB_uNSERIALIZE_Hh_

    #include "unserialize_abstract.h"

    #include "../serialize.h"
    #include "../algs.h"
    #include "vectorstream.h"

    namespace dlib
    {
        class unserialize : public std::istream
        {
            class mystreambuf : public std::streambuf
            {
                typedef std::vector<char>::size_type size_type;
                size_type read_pos; // buffer[read_pos] == next byte to read from buffer
            public:
                std::vector<char> buffer;
                std::istream& str;

                template <typename T>
                mystreambuf(
                    const T& item,
                    std::istream& str_
                ) :
                    read_pos(0),
                    str(str_)
                {
                    // put the item into our buffer.
                    vectorstream vstr(buffer);
                    serialize(item, vstr);
                }

                // ------------------------ INPUT FUNCTIONS ------------------------

                int_type underflow(
                )
                {
                    if (read_pos < buffer.size())
                        return static_cast<unsigned char>(buffer[read_pos]);
                    else
                        return str.peek();
                }

                int_type uflow(
                )
                {
                    if (read_pos < buffer.size())
                        return static_cast<unsigned char>(buffer[read_pos++]);
                    else
                        return str.get();
                }

                std::streamsize xsgetn (
                    char* s,
                    std::streamsize n
                )
                {
                    if (read_pos < buffer.size())
                    {
                        const size_type num = std::min<size_type>(n, buffer.size()-read_pos);
                        std::memcpy(s, &buffer[read_pos], num);
                        read_pos += num;
                        return num;
                    }
                    else
                    {
                        return str.rdbuf()->sgetn(s,n);
                    }
                    return 0;
                }

            };

        public:

            template <typename T>
            unserialize (
                const T& item,
                std::istream& str
            ) :
                std::istream(&buf),
                buf(item, str)
            {}

        private:
            mystreambuf buf;
        };
    }

    #endif // DLIB_uNSERIALIZE_Hh_