Program Listing for File matini.hpp

Return to documentation for file (/home/runner/work/Legion-Engine/Legion-Engine/legion/engine/rendering/util/matini.hpp)

#pragma once

#include <inih/ini.h>
#include <tuple>
#include <sstream>
#include <vector>
namespace legion::rendering {

    struct material_handle;

    namespace detail
    {
        class IniBuilder
        {
        public:
            IniBuilder& glyph(const std::string& glyph)
            {
                m_contents += glyph;
                return *this;
            }

            IniBuilder& section(const std::string& v)   { return glyph("[" + v + "]\n"); }
            IniBuilder& eq()                            { return glyph("= "); }
            IniBuilder& comment(const std::string& v)   { return glyph("; " + v + "\n"); }

            IniBuilder& value(float v)                  { return glyph(std::to_string(v) + " "); }
            IniBuilder& value(int v)                    { return glyph(std::to_string(v) + " "); }
            IniBuilder& value(math::vec3 v)             { return value(v.x).value(v.y).value(v.z); }
            IniBuilder& value(math::ivec3 v)            { return value(v.x).value(v.y).value(v.z); }
            IniBuilder& value(math::vec4 v)             { return value(v.x).value(v.y).value(v.z).value(v.w); }
            IniBuilder& value(math::ivec4 v)            { return value(v.x).value(v.y).value(v.z).value(v.w); }
            IniBuilder& value(bool b)                   { return glyph(b ? "true " : "false "); }
            IniBuilder& value(const std::string& v)     { return glyph(v + " "); }

            IniBuilder& finish_entry()                  { return glyph("\n"); }

            IniBuilder& push_state()                    { m_copy = m_contents; return *this; }
            IniBuilder& pop_state()                     { m_contents = m_copy; return *this;}


            L_NODISCARD std::string get() const noexcept { return m_contents; }

        private:
            std::string m_contents;
            std::string m_copy;
        };

        class handler_to_cpp
        {
        public:
            //a place to store the data? maybe, not used
            static int handle(void* user, const char* section, const char* name, const char* value)
            {
                auto& self = *static_cast<handler_to_cpp*>(user);
                self.m_parsed.emplace(section, std::make_pair<std::string, std::string>(name, value));
                return 1;
            }

            //function to go through each value in a section
            template <class Func>
            void for_each_value_in_section(const std::string& section, Func&& f)
            {
                auto range = pair_range(m_parsed.equal_range(section));

                for (auto& [key, value] : values_only(range))
                {
                    if (std::invoke(f, key, value)) return;
                }
            }

        private:
            std::unordered_multimap<std::string, std::pair<std::string, std::string>> m_parsed;

        };
#pragma region ConversionShit
        template <class T>
        std::pair<bool, T> convert(const std::string& str)
        {
            std::istringstream iss(str);
            T dummy;
            iss >> dummy;
            return { iss && iss.eof(),dummy };
        }

        template <class T>
        auto convert_stream(std::istringstream* iss)
        {
            T dummy;
            (*iss) >> dummy;
            return dummy;
        }


        template <class T, unsigned long N>
        struct convert_tuple {};

        template <class T>
        struct convert_tuple<T, 2>
        {

            static auto convert(const std::string& str) ->decltype(auto)
            {
                std::istringstream iss(str);
                std::tuple<T, T> results = { convert_stream<T>(&iss),convert_stream<T>(&iss) };
                return std::tuple<bool, std::tuple<T, T>>{iss&& iss.eof(), results};
            }
        };
        template <class T>
        struct convert_tuple<T, 3>
        {

            static auto convert(const std::string& str) ->decltype(auto)
            {
                std::istringstream iss(str);
                std::tuple<T, T, T> results = { convert_stream<T>(&iss),convert_stream<T>(&iss),convert_stream<T>(&iss) };
                return std::tuple<bool, std::tuple<T, T, T>>{iss&& iss.eof(), results};
            }
        };
        template <class T>
        struct convert_tuple<T, 4>
        {

            static auto convert(const std::string& str) ->decltype(auto)
            {
                std::istringstream iss(str);
                std::tuple<T, T, T, T> results = { convert_stream<T>(&iss),convert_stream<T>(&iss),convert_stream<T>(&iss),convert_stream<T>(&iss) };
                return std::tuple<bool, std::tuple<T, T, T, T>>{iss&& iss.eof(), results};
            }
        };
#pragma endregion

    }


    inline std::string extract_string(const std::string& section, const std::string& key, fs::view file)
    {
        detail::handler_to_cpp handler;

        const auto str = file.get().except([](auto err)
            {
                log::warn("Unable to open {}, could not load ini settings!");
                return fs::basic_resource("");
            }).to_string();

            const char* const cstr = str.c_str();
            ini_parse_string(cstr, &detail::handler_to_cpp::handle, &handler);//parses the ini data into a usable form.

            std::string v;

            handler.for_each_value_in_section(section, [&](const std::string& k, const std::string& value)
                {
                    if (k == key)
                    {
                        v = value;
                        return true;
                    }
                    return false;
                });
            return v;
    }


    //material_handle | material: the material handle for the material that will have its paramters set.
    //std::string | section: the section of the ini file that we are going to parse.
    //fs::view | file: the path to the ini file we are parsing.
    extern void apply_material_conf(material_handle& material, const std::string& section, fs::view file);

}