#pragma once
#include <compare>
#include <cstdint>
#include <string>
#include <string_view>
#include <type_traits>
namespace ddwaf {
enum class object_type : uint8_t {
invalid = 0x00, null = 0x01, boolean = 0x02, int64 = 0x04, uint64 = 0x06, float64 = 0x08, string = 0x10, literal_string = 0x12, small_string = 0x14, array = 0x20, map = 0x40, hash_map = 0x60,
large_array = 0xA0, large_map = 0xC0, };
constexpr uint8_t logical_container_type_mask = 0x7f;
template <typename T>
constexpr object_type operator|(object_type left, T right)
requires std::is_same_v<T, object_type> || std::is_integral_v<T>
{
using utype = std::underlying_type_t<object_type>;
return static_cast<object_type>(static_cast<utype>(left) | static_cast<utype>(right));
}
template <typename T>
constexpr object_type operator&(object_type left, T right)
requires std::is_same_v<T, object_type> || std::is_integral_v<T>
{
using utype = std::underlying_type_t<object_type>;
return static_cast<object_type>(static_cast<utype>(left) & static_cast<utype>(right));
}
template <typename T>
constexpr auto operator<=>(object_type left, T right)
requires std::is_same_v<T, object_type> || std::is_integral_v<T>
{
using utype = std::underlying_type_t<object_type>;
return static_cast<utype>(left) <=> static_cast<utype>(right);
}
template <typename T>
constexpr bool operator==(object_type left, T right)
requires std::is_same_v<T, object_type> || std::is_integral_v<T>
{
using utype = std::underlying_type_t<object_type>;
return static_cast<utype>(left) == static_cast<utype>(right);
}
inline bool is_scalar(object_type type)
{
return (type & (object_type::boolean | object_type::int64 | object_type::uint64 |
object_type::float64 | object_type::string | object_type::literal_string |
object_type::small_string)) != 0;
}
inline bool is_array(object_type type)
{
return (static_cast<uint8_t>(type) & logical_container_type_mask) ==
static_cast<uint8_t>(object_type::array);
}
inline bool is_map(object_type type)
{
return (static_cast<uint8_t>(type) & logical_container_type_mask) ==
static_cast<uint8_t>(object_type::map);
}
inline bool is_container(object_type type)
{
return is_array(type) || is_map(type) || type == object_type::hash_map;
}
template <typename T> inline bool is_compatible_type(object_type ) { return false; }
template <typename T>
inline bool is_compatible_type(object_type type)
requires std::is_same_v<T, bool>
{
return type == object_type::boolean;
}
template <typename T>
inline bool is_compatible_type(object_type type)
requires std::is_same_v<T, uint64_t>
{
return type == object_type::uint64;
}
template <typename T>
inline bool is_compatible_type(object_type type)
requires std::is_same_v<T, int64_t>
{
return type == object_type::int64;
}
template <typename T>
inline bool is_compatible_type(object_type type)
requires std::is_same_v<T, double>
{
return type == object_type::float64;
}
template <typename T>
inline bool is_compatible_type(object_type type)
requires std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view> ||
std::is_same_v<T, const char *>
{
return (type & object_type::string) != 0;
}
template <typename T>
T object_type_to_string(object_type type)
requires std::is_constructible_v<T, const char *>
{
switch (type) {
case object_type::map:
case object_type::large_map:
return "map";
case object_type::array:
case object_type::large_array:
return "array";
case object_type::string:
case object_type::literal_string:
case object_type::small_string:
return "string";
case object_type::boolean:
return "bool";
case object_type::uint64:
return "unsigned";
case object_type::int64:
return "signed";
case object_type::float64:
return "float";
case object_type::null:
return "null";
case object_type::invalid:
default:
break;
}
return "unknown";
}
}