diff --git a/source/mijin/types/script_value.hpp b/source/mijin/types/script_value.hpp new file mode 100644 index 0000000..55bf671 --- /dev/null +++ b/source/mijin/types/script_value.hpp @@ -0,0 +1,208 @@ + +#pragma once + +#ifndef MIJIN_TYPES_SCRIPT_VALUE_HPP_INCLUDED +#define MIJIN_TYPES_SCRIPT_VALUE_HPP_INCLUDED 1 + +#include +#include +#include +#include + +#include "../container/optional.hpp" + +namespace mijin +{ +// +// public types +// + +struct ArrayValue +{ + std::vector values; + + bool operator==(const ArrayValue& other) const; + inline bool operator!=(const ArrayValue& other) const { + return !(*this == other); + } + std::partial_ordering operator<=>(const ArrayValue& other) const; +}; + +struct UndefinedValue +{ + auto operator<=>(const UndefinedValue&) const = default; +}; + +inline constexpr UndefinedValue UNDEFINED_VALUE; + +using script_int_t = long long; +using script_float_t = double; +using script_value_base_t = std::variant< + UndefinedValue, + bool, + script_int_t, + script_float_t, + std::string, + ArrayValue +>; + +class ScriptValue +{ +private: + script_value_base_t base_; +public: + ScriptValue() noexcept = default; + ScriptValue(const ScriptValue&) noexcept = default; + ScriptValue(ScriptValue&&) noexcept = default; + template + ScriptValue(TValue&& value); + + ScriptValue& operator=(const ScriptValue&) = default; + ScriptValue& operator=(ScriptValue&&) noexcept = default; + + std::partial_ordering operator<=>(const ScriptValue& other) const = default; + + template + auto visit(TFunction&& function) const + { + using result_t = std::invoke_result_t; + + if constexpr (std::is_same_v) + { + std::visit(function, base_); + } + else + { + return std::visit(function, base_); + } + } + + [[nodiscard]] + Optional toInt() const noexcept + { + return visit([&](auto&& value) -> Optional + { + using type_t = std::decay_t; + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + { + return static_cast(value); + } + else if constexpr (std::is_same_v) + { + script_int_t result = 0; + const std::from_chars_result fromCharsResult = std::from_chars(&*value.begin(), &*value.end(), result); + if (fromCharsResult.ec != std::errc{}) + { + return NULL_OPTIONAL; + } + return result; + } + else + { + return NULL_OPTIONAL; + } + }); + } + + [[nodiscard]] + Optional toFloat() const noexcept + { + return visit([&](auto&& value) -> Optional + { + using type_t = std::decay_t; + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + { + return static_cast(value); + } + else if constexpr (std::is_same_v) + { + script_float_t result = 0; + const std::from_chars_result fromCharsResult = std::from_chars(&*value.begin(), &*value.end(), result); + if (fromCharsResult.ec != std::errc{}) + { + return NULL_OPTIONAL; + } + return result; + } + else + { + return NULL_OPTIONAL; + } + }); + } + + [[nodiscard]] + Optional toString() const noexcept + { + return visit([](auto&& value) -> Optional + { + using type_t = std::decay_t; + if constexpr (std::is_same_v) + { + return std::string(""); + } + else if constexpr (std::is_same_v) + { + return std::string(value ? "true" : "false"); + } + else if constexpr (std::is_same_v || std::is_same_v) + { + return std::to_string(value); + } + else if constexpr (std::is_same_v) + { + return value; + } + else + { + return NULL_OPTIONAL; + } + }); + } + + template + [[nodiscard]] + Optional> to() const noexcept + { + using type_t = std::decay_t; + if constexpr (std::is_same_v) + { + return toInt(); + } + else if constexpr (std::is_integral_v) + { + return toInt().then([](script_int_t val) { return static_cast(val); }); + } + else if constexpr (std::is_same_v) + { + return toFloat(); + } + else if constexpr (std::is_floating_point_v) + { + return toFloat().then([](script_float_t val) { return static_cast(val); }); + } + else if constexpr (std::is_same_v) + { + return toString(); + } + else if constexpr (std::is_same_v) + { + return *this; + } + else + { + static_assert(mijin::always_false_v, "Cannot convert to this type."); + } + } +}; + +// +// public functions +// +template +ScriptValue::ScriptValue(TValue&& value) : base_(std::forward(value)) +{ +} +} // namespace mijin + +#endif // MIJIN_TYPES_SCRIPT_VALUE_HPP_INCLUDED