str/conv: Add basic functions

We need some basic templates for formatting into a buffer or fmtlib to
make other conversions straightforward.

Change-Id: I8c13175394f6b4fd4a55edf8d653e98a1562cc64
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/meson.build b/include/meson.build
index 5909aa0..979478e 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -19,6 +19,7 @@
   'stdplus/str/buf.hpp',
   'stdplus/str/cat.hpp',
   'stdplus/str/cexpr.hpp',
+  'stdplus/str/conv.hpp',
   'stdplus/str/maps.hpp',
   'stdplus/util/cexec.hpp',
   'stdplus/util/string.hpp',
diff --git a/include/stdplus/str/conv.hpp b/include/stdplus/str/conv.hpp
new file mode 100644
index 0000000..cbf79d3
--- /dev/null
+++ b/include/stdplus/str/conv.hpp
@@ -0,0 +1,157 @@
+#pragma once
+#include <fmt/core.h>
+
+#include <stdplus/str/buf.hpp>
+
+#include <array>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+namespace stdplus
+{
+
+template <typename T>
+struct ToStr;
+
+template <typename T>
+struct FromStr;
+
+template <typename T>
+constexpr T fromStr(const auto& str)
+{
+    return FromStr<T>{}(
+        std::basic_string_view<std::remove_cvref_t<decltype(*std::begin(str))>>{
+            str});
+}
+
+namespace detail
+{
+
+template <typename T>
+concept ToStrStatic =
+    !std::is_void_v<decltype(std::declval<T>().template operator()<char>(
+        std::declval<typename T::type>()))>;
+
+template <typename T>
+concept ToStrFixed = !std::is_void_v<decltype(std::declval<T>()(
+    std::declval<char*>(), std::declval<typename T::type>()))>;
+
+} // namespace detail
+
+template <typename T>
+struct ToStrAdap : T
+{};
+
+template <detail::ToStrStatic T>
+struct ToStrAdap<T> : T
+{
+    using T::operator();
+
+    template <typename CharT>
+    constexpr CharT* operator()(CharT* base, const T::type& t) const
+    {
+        auto sv = (*this).template operator()<CharT>(t);
+        return std::copy(sv.begin(), sv.end(), base);
+    }
+
+    template <typename CharT>
+    constexpr void operator()(stdplus::BasicStrBuf<CharT>& buf,
+                              const T::type& t) const
+    {
+        auto ptr = buf.append(T::buf_size);
+        buf.shrink(T::buf_size - ((*this)(ptr, t) - ptr));
+    }
+};
+
+template <detail::ToStrFixed T>
+struct ToStrAdap<T> : T
+{
+    using T::operator();
+
+    template <typename CharT>
+    constexpr void operator()(stdplus::BasicStrBuf<CharT>& buf,
+                              const T::type& t) const
+    {
+        auto ptr = buf.append(T::buf_size);
+        buf.shrink(T::buf_size - ((*this)(ptr, t) - ptr));
+    }
+};
+
+template <typename T, typename CharT = char>
+struct ToStrHandle
+{
+  private:
+    stdplus::BasicStrBuf<CharT> buf;
+
+  public:
+    constexpr std::basic_string_view<CharT> operator()(const T::type& v)
+    {
+        buf.reset();
+        T{}(buf, v);
+        return buf;
+    }
+};
+
+template <detail::ToStrStatic T, typename CharT>
+struct ToStrHandle<T, CharT>
+{
+    static_assert(T::buf_size > 0);
+
+    constexpr std::basic_string_view<CharT>
+        operator()(const T::type& v) noexcept(
+            noexcept(std::declval<T>().template operator()<CharT>(
+                std::declval<typename T::type>())))
+    {
+        return T{}.template operator()<CharT>(v);
+    }
+};
+
+template <detail::ToStrFixed T, typename CharT>
+struct ToStrHandle<T, CharT>
+{
+  private:
+    std::array<CharT, T::buf_size> buf;
+
+  public:
+    constexpr std::basic_string_view<CharT>
+        operator()(const T::type& v) noexcept(noexcept(std::declval<T>()(
+            std::declval<CharT*>(), std::declval<typename T::type>())))
+    {
+        return {buf.data(), T{}(buf.data(), v)};
+    }
+};
+
+template <typename T, typename CharT>
+struct Format
+{
+  private:
+    fmt::formatter<std::basic_string_view<CharT>> formatter;
+
+  public:
+    template <typename ParseContext>
+    constexpr auto parse(ParseContext& ctx)
+    {
+        return ctx.begin();
+    }
+
+    template <typename FormatContext>
+    auto format(auto v, FormatContext& ctx) const
+    {
+        return formatter.format(ToStrHandle<T, CharT>{}(v), ctx);
+    }
+};
+
+template <typename CharT, typename T>
+constexpr auto toBasicStr(const T& t)
+{
+    return std::basic_string<CharT>(ToStrHandle<ToStr<T>, CharT>{}(t));
+}
+
+template <typename T>
+constexpr auto toStr(const T& t)
+{
+    return toBasicStr<char>(t);
+}
+
+} // namespace stdplus