#pragma once #include "deimos/core/base.h" namespace deimos { class IWriter; struct CustomFormatter { using Callback = void (*)(IWriter*, const void* payload); const void* payload; Callback callback; }; struct FormatArg { enum Type : uint8_t { kInteger, kUnsignedInteger, kString, kCustom, }; Type type; union { int64_t integer; uint64_t unsigned_integer; StringView string; CustomFormatter custom; }; constexpr explicit FormatArg(std::signed_integral auto value) : type{kInteger}, integer{value} {} constexpr explicit FormatArg(std::unsigned_integral auto value) : type{kUnsignedInteger}, unsigned_integer{value} {} constexpr explicit FormatArg(StringView value) : type{kString}, string{value} {} template constexpr explicit FormatArg(const T& payload, CustomFormatter::Callback callback) : type{kCustom}, custom{CustomFormatter{&payload, callback}} {} }; template deimos::FormatArg DeimosMakeFormatArg(T&& value) requires std::is_constructible_v { return deimos::FormatArg(value); } template concept Formattable = std::same_as()))>; void FormatVa(IWriter*, gsl::czstring fmt, Span); template void Format(IWriter* writer, gsl::czstring fmt, Args&&... args) { FormatVa(writer, fmt, { DeimosMakeFormatArg(std::forward(args))... }); } } // namespace deimos