#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
#include "dynamic_string.hpp"
#include "object.hpp"
#include "object_type.hpp"
namespace ddwaf {
namespace matcher {
class base {
public:
base() = default;
virtual ~base() = default;
base(const base &) = default;
base(base &&) noexcept = default;
base &operator=(const base &) = default;
base &operator=(base &&) noexcept = default;
[[nodiscard]] virtual std::string_view name() const = 0;
[[nodiscard]] virtual std::string_view negated_name() const = 0;
[[nodiscard]] virtual std::string_view to_string() const = 0;
[[nodiscard]] virtual bool is_supported_type(object_type type) const = 0;
[[nodiscard]] virtual std::pair<bool, dynamic_string> match(std::string_view str) const = 0;
[[nodiscard]] virtual std::pair<bool, dynamic_string> match(object_view obj) const = 0;
};
template <typename T> class base_impl : public base {
public:
base_impl() = default;
~base_impl() override = default;
base_impl(const base_impl &) = default;
base_impl(base_impl &&) noexcept = default;
base_impl &operator=(const base_impl &) = default;
base_impl &operator=(base_impl &&) noexcept = default;
[[nodiscard]] std::string_view name() const override { return T::matcher_name; }
[[nodiscard]] std::string_view negated_name() const override { return T::negated_matcher_name; }
[[nodiscard]] std::string_view to_string() const override
{
return static_cast<const T *>(this)->to_string_impl();
}
[[nodiscard]] bool is_supported_type(object_type type) const override
{
return T::is_supported_type_impl(type);
}
template <typename U> [[nodiscard]] std::pair<bool, dynamic_string> match(const U &data) const
{
if constexpr (is_type_in_set_v<U, owned_object, borrowed_object>) {
return match(object_view{data});
} else {
return static_cast<const T *>(this)->match_impl(data);
}
}
[[nodiscard]] std::pair<bool, dynamic_string> match(std::string_view str) const override
{
const auto *ptr = static_cast<const T *>(this);
if constexpr (T::is_supported_type_impl(object_type::string)) {
return ptr->match_impl(str);
}
return {false, {}};
}
[[nodiscard]] std::pair<bool, dynamic_string> match(object_view obj) const override
{
const auto *ptr = static_cast<const T *>(this);
if constexpr (T::is_supported_type_impl(object_type::string)) {
if (obj.is_string()) {
return ptr->match_impl(obj.as<std::string_view>());
}
}
if constexpr (T::is_supported_type_impl(object_type::int64)) {
if (obj.type() == object_type::int64) {
return ptr->match_impl(obj.as<int64_t>());
}
}
if constexpr (T::is_supported_type_impl(object_type::int64)) {
if (obj.type() == object_type::uint64) {
return ptr->match_impl(obj.as<uint64_t>());
}
}
if constexpr (T::is_supported_type_impl(object_type::boolean)) {
if (obj.type() == object_type::boolean) {
return ptr->match_impl(obj.as<bool>());
}
}
if constexpr (T::is_supported_type_impl(object_type::float64)) {
if (obj.type() == object_type::float64) {
return ptr->match_impl(obj.as<double>());
}
}
return {false, {}};
}
};
}
using matcher_mapper = std::unordered_map<std::string, std::unique_ptr<matcher::base>>;
}