/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2018 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

#include "../std.hpp"

#include <cstddef>
#include <type_traits>

namespace cruft::types {
    //-------------------------------------------------------------------------
    enum class category {
        NONE,
        UNSIGNED,
        SIGNED,
        REAL,
    };

    //-------------------------------------------------------------------------
    struct description {
        enum category category;
        std::size_t width;
    };


    //-------------------------------------------------------------------------
    template <typename T>
    struct category_traits;

    template <> struct category_traits<u08> : public std::integral_constant<category,category::UNSIGNED> {};
    template <> struct category_traits<u16> : public std::integral_constant<category,category::UNSIGNED> {};
    template <> struct category_traits<u32> : public std::integral_constant<category,category::UNSIGNED> {};
    template <> struct category_traits<u64> : public std::integral_constant<category,category::UNSIGNED> {};

    template <> struct category_traits<i08> : public std::integral_constant<category,category::SIGNED> {};
    template <> struct category_traits<i16> : public std::integral_constant<category,category::SIGNED> {};
    template <> struct category_traits<i32> : public std::integral_constant<category,category::SIGNED> {};
    template <> struct category_traits<i64> : public std::integral_constant<category,category::SIGNED> {};

    template <> struct category_traits<f32> : public std::integral_constant<category,category::REAL> {};
    template <> struct category_traits<f64> : public std::integral_constant<category,category::REAL> {};

    template <typename T>
    constexpr auto category_traits_v = category_traits<T>::value;


    //-------------------------------------------------------------------------
    template <typename T>
    constexpr description
    make_description (void) noexcept
    {
        return {
            .category = category_traits_v<T>,
            .width = sizeof (T)
        };
    }
}

#include <iosfwd>
namespace cruft::types {
    std::ostream& operator<< (std::ostream&, category);
    std::ostream& operator<< (std::ostream&, description);
}