Program Listing for File value-serializer.hpp
↰ Return to documentation for file (zeep/value-serializer.hpp
)
// Copyright Maarten L. Hekkelman, 2014-2023
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
#include <zeep/config.hpp>
#include <charconv>
#include <cstdint>
#include <iomanip>
#include <map>
#include <regex>
#include <sstream>
#include <zeep/exception.hpp>
#if __has_include(<date/date.h>)
#include <date/date.h>
#endif
namespace zeep
{
// --------------------------------------------------------------------
template <typename T, typename = void>
struct value_serializer;
template <>
struct value_serializer<bool>
{
static constexpr const char *type_name() { return "xsd:boolean"; }
static std::string to_string(bool value) { return value ? "true" : "false"; }
static bool from_string(const std::string &value) { return value == "true" or value == "1" or value == "yes"; }
};
template <>
struct value_serializer<std::string>
{
static constexpr const char *type_name() { return "xsd:string"; }
static std::string to_string(const std::string &value) { return value; }
static std::string from_string(const std::string &value) { return value; }
};
template<typename T>
struct char_conv_serializer
{
using value_type = T;
static constexpr const char *derived_type_name()
{
using value_serializer_type = value_serializer<value_type>;
return value_serializer_type::type_name();
}
static std::string to_string(value_type value) { return std::to_string(value); }
static value_type from_string(const std::string &value)
{
value_type result{};
auto r = std::from_chars(value.data(), value.data() + value.length(), result);
if (r.ec != std::errc{} or r.ptr != value.data() + value.length())
throw std::system_error(std::make_error_code(r.ec), "Error converting value '" + value + "' to type " + derived_type_name());
return result;
}
};
template <>
struct value_serializer<int8_t> : char_conv_serializer<int8_t>
{
static constexpr const char *type_name() { return "xsd:byte"; }
};
template <>
struct value_serializer<uint8_t> : char_conv_serializer<uint8_t>
{
static constexpr const char *type_name() { return "xsd:unsignedByte"; }
};
template <>
struct value_serializer<int16_t> : char_conv_serializer<int16_t>
{
static constexpr const char *type_name() { return "xsd:short"; }
};
template <>
struct value_serializer<uint16_t> : char_conv_serializer<uint16_t>
{
static constexpr const char *type_name() { return "xsd:unsignedShort"; }
};
template <>
struct value_serializer<int32_t> : char_conv_serializer<int32_t>
{
static constexpr const char *type_name() { return "xsd:int"; }
};
template <>
struct value_serializer<uint32_t> : char_conv_serializer<uint32_t>
{
static constexpr const char *type_name() { return "xsd:unsignedInt"; }
};
template <>
struct value_serializer<int64_t> : char_conv_serializer<int64_t>
{
static constexpr const char *type_name() { return "xsd:long"; }
};
template <>
struct value_serializer<uint64_t> : char_conv_serializer<uint64_t>
{
static constexpr const char *type_name() { return "xsd:unsignedLong"; }
};
template <>
struct value_serializer<float>
{
static constexpr const char *type_name() { return "xsd:float"; }
// static std::string to_string(float value) { return std::to_string(value); }
static std::string to_string(float value)
{
std::ostringstream s;
s << value;
return s.str();
}
static float from_string(const std::string &value) { return std::stof(value); }
};
template <>
struct value_serializer<double>
{
static constexpr const char *type_name() { return "xsd:double"; }
// static std::string to_string(double value) { return std::to_string(value); }
static std::string to_string(double value)
{
std::ostringstream s;
s << value;
return s.str();
}
static double from_string(const std::string &value) { return std::stod(value); }
};
template <typename T>
struct value_serializer<T, std::enable_if_t<std::is_enum_v<T>>>
{
std::string m_type_name;
using value_map_type = std::map<T, std::string>;
using value_map_value_type = typename value_map_type::value_type;
value_map_type m_value_map;
static void init(const char *name, std::initializer_list<value_map_value_type> values)
{
instance(name).m_value_map = value_map_type(values);
}
static void init(std::initializer_list<value_map_value_type> values)
{
instance().m_value_map = value_map_type(values);
}
static value_serializer &instance(const char *name = nullptr)
{
static value_serializer s_instance;
if (name and s_instance.m_type_name.empty())
s_instance.m_type_name = name;
return s_instance;
}
value_serializer &operator()(T v, const std::string &name)
{
m_value_map[v] = name;
return *this;
}
value_serializer &operator()(const std::string &name, T v)
{
m_value_map[v] = name;
return *this;
}
static const char *type_name()
{
return instance().m_type_name;
}
static std::string to_string(T value)
{
return instance().m_value_map[value];
}
static T from_string(const std::string &value)
{
T result = {};
for (auto &t : instance().m_value_map)
if (t.second == value)
{
result = t.first;
break;
}
return result;
}
static bool empty()
{
return instance().m_value_map.empty();
}
};
// --------------------------------------------------------------------
// date/time support
// We're using Howard Hinands date functions here. If available...
#if __has_include(<date/date.h>)
template <>
struct value_serializer<std::chrono::system_clock::time_point>
{
using time_type = std::chrono::system_clock::time_point;
static constexpr const char *type_name() { return "xsd:dateTime"; }
static std::string to_string(const time_type &v)
{
std::ostringstream ss;
ss << date::format("%FT%TZ", v);
return ss.str();
}
static time_type from_string(const std::string &s)
{
time_type result;
std::regex kRX(R"(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(Z|[-+]\d{2}:\d{2})?)");
std::smatch m;
if (not std::regex_match(s, m, kRX))
throw std::runtime_error("Invalid date format");
std::istringstream is(s);
if (m[1].matched)
{
if (m[1] == "Z")
date::from_stream(is, "%FT%TZ", result);
else
date::from_stream(is, "%FT%T%0z", result);
}
else
date::from_stream(is, "%FT%T", result);
if (is.bad() or is.fail())
throw std::runtime_error("invalid formatted date");
return result;
}
};
template <>
struct value_serializer<date::sys_days>
{
static constexpr const char *type_name() { return "xsd:date"; }
static std::string to_string(const date::sys_days &v)
{
std::ostringstream ss;
date::to_stream(ss, "%F", v);
return ss.str();
}
static date::sys_days from_string(const std::string &s)
{
date::sys_days result;
std::istringstream is(s);
date::from_stream(is, "%F", result);
if (is.bad() or is.fail())
throw std::runtime_error("invalid formatted date");
return result;
}
};
#endif
} // namespace zeep