29#ifndef SER20_ARCHIVES_YAML_HPP_
30#define SER20_ARCHIVES_YAML_HPP_
32#include <ser20/details/util.hpp>
33#include <ser20/external/base64.hpp>
34#include <ser20/ser20.hpp>
36#include <yaml-cpp/yaml.h>
49 :
public OutputArchive<YAMLOutputArchive>
50 ,
public traits::TextArchive
66 nodeStack.push(NodeType::StartObject);
71 if(nodeStack.top() == NodeType::InObject)
73 emitter << YAML::EndMap;
75 else if(nodeStack.top() == NodeType::InArray)
77 emitter << YAML::EndSeq;
80 out << emitter.c_str();
91 auto base64string = base64::encode(
reinterpret_cast<const unsigned char*
>(data),
size);
109 nodeStack.push(NodeType::StartObject);
121 switch(nodeStack.top())
123 case NodeType::StartArray:
124 emitter << YAML::BeginSeq;
125 case NodeType::InArray:
126 emitter << YAML::EndSeq;
128 case NodeType::StartObject:
129 emitter << YAML::BeginMap;
130 case NodeType::InObject:
131 emitter << YAML::EndMap;
197 inline void saveLong(T l)
198 requires(
sizeof(T) ==
sizeof(std::int32_t) && std::is_signed_v<T>)
205 inline void saveLong(T l)
206 requires(
sizeof(T) !=
sizeof(std::int32_t) && std::is_signed_v<T>)
213 inline void saveLong(T lu)
214 requires(
sizeof(T) ==
sizeof(std::int32_t) && std::is_unsigned_v<T>)
216 saveValue(
static_cast<std::uint32_t
>(lu));
221 inline void saveLong(T lu)
222 requires(
sizeof(T) !=
sizeof(std::int32_t) && std::is_unsigned_v<T>)
224 saveValue(
static_cast<std::uint64_t
>(lu));
228#if defined(_MSC_VER) && _MSC_VER < 1916
238 requires(std::is_same_v<T, long> && !std::is_same_v<T, int> && !std::is_same_v<T, std::int64_t>)
246 requires(std::is_same_v<T, unsigned long> && !std::is_same_v<T, unsigned> && !std::is_same_v<T, std::uint64_t>)
257 requires(std::is_arithmetic_v<T> && !std::is_same_v<T, long> && !std::is_same_v<T, unsigned long> &&
258 !std::is_same_v<T, std::int64_t> && !std::is_same_v<T, std::uint64_t> &&
259 !std::is_same_v<T, long long> && !std::is_same_v<T, unsigned long long> &&
260 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long)))
262 std::stringstream ss;
263 ss.precision(std::numeric_limits<long double>::max_digits10);
283 NodeType& nodeType = nodeStack.top();
286 if(nodeType == NodeType::StartArray)
288 emitter << YAML::BeginSeq;
289 nodeType = NodeType::InArray;
291 else if(nodeType == NodeType::StartObject)
293 emitter << YAML::BeginMap;
294 nodeType = NodeType::InObject;
298 if(nodeType == NodeType::InArray)
303 emitter << YAML::Key;
305 if(nextName ==
nullptr)
307 std::string
name =
"value" + std::to_string(nameCounter.top()++) +
"\0";
316 emitter << YAML::Value;
322 nodeStack.top() = NodeType::StartArray;
329 YAML::Emitter emitter;
330 char const* nextName;
331 std::stack<uint32_t> nameCounter;
332 std::stack<NodeType> nodeStack;
337 :
public InputArchive<YAMLInputArchive>
338 ,
public traits::TextArchive
340 typedef YAML::const_iterator YAMLIterator;
345 , itsNextName(nullptr)
346 , itsDocument(YAML::Load(stream))
348 if(itsDocument.IsSequence())
350 itsIteratorStack.emplace_back(itsDocument.begin(), itsDocument.end(), Iterator::Type::Value);
355 itsIteratorStack.emplace_back(itsDocument.begin(), itsDocument.end(), Iterator::Type::Member);
373 auto decoded = base64::decode(encoded);
377 throw Exception(
"Decoded binary data size does not match specified size");
380 std::memcpy(data, decoded.data(), decoded.size());
381 itsNextName =
nullptr;
402 Iterator() : itsType(Null_)
406 Iterator(YAMLIterator begin, YAMLIterator end, Type
type)
409 , itsItCurrent(
begin)
412 if(std::distance(begin, end) == 0)
417 if(itsType == Member && itsItCurrent != itsItEnd)
419 currentName = itsItCurrent->first.as<std::string>();
424 Iterator& operator++()
427 if(itsType == Member && itsItCurrent != itsItEnd)
429 currentName = itsItCurrent->first.as<std::string>();
440 return *itsItCurrent;
442 return itsItCurrent->second;
444 throw ser20::Exception(
445 "YAMLInputArchive internal error: null or empty iterator to object or array!");
450 const char* name()
const
452 if(currentName !=
"")
454 return currentName.c_str();
464 inline void search(
const char* searchName)
467 const auto len = std::strlen(searchName);
468 for(itsItCurrent = itsItBegin; itsItCurrent != itsItEnd; ++itsItCurrent, ++index)
470 currentName = itsItCurrent->first.as<std::string>();
471 if((std::strncmp(searchName, currentName.c_str(), len) == 0) &&
472 (std::strlen(currentName.c_str()) == len))
478 throw Exception(
"YAML Parsing failed - provided NVP (" + std::string(searchName) +
") not found");
482 YAMLIterator itsItBegin, itsItEnd;
483 YAMLIterator itsItCurrent;
484 std::string currentName;
503 auto const actualName = itsIteratorStack.back().name();
506 if(!actualName || std::strcmp(itsNextName, actualName) != 0)
508 itsIteratorStack.back().search(itsNextName);
512 itsNextName =
nullptr;
530 auto value = itsIteratorStack.back().value();
532 if(value.IsSequence())
534 itsIteratorStack.emplace_back(value.begin(), value.end(), Iterator::Type::Value);
538 itsIteratorStack.emplace_back(value.begin(), value.end(), Iterator::Type::Member);
545 itsIteratorStack.pop_back();
546 ++itsIteratorStack.back();
553 return itsIteratorStack.back().name();
565 requires(std::is_signed<T>::value &&
sizeof(T) <
sizeof(int64_t))
569 val =
static_cast<T
>(itsIteratorStack.back().value().as<int>());
570 ++itsIteratorStack.back();
576 requires(std::is_unsigned<T>::value &&
sizeof(T) <
sizeof(uint64_t) && !std::is_same<bool, T>::value)
580 val =
static_cast<T
>(itsIteratorStack.back().value().as<unsigned int>());
581 ++itsIteratorStack.back();
588 val = itsIteratorStack.back().value().as<
bool>();
589 ++itsIteratorStack.back();
595 val = itsIteratorStack.back().value().as<int64_t>();
596 ++itsIteratorStack.back();
602 val = itsIteratorStack.back().value().as<uint64_t>();
603 ++itsIteratorStack.back();
609 val =
static_cast<float>(itsIteratorStack.back().value().as<float>());
610 ++itsIteratorStack.back();
616 val = itsIteratorStack.back().value().as<
double>();
617 ++itsIteratorStack.back();
623 val = itsIteratorStack.back().value().as<std::string>();
624 ++itsIteratorStack.back();
630 ++itsIteratorStack.back();
639 inline typename std::enable_if<
sizeof(T) ==
sizeof(std::int32_t) && std::is_signed<T>::value,
void>
::type loadLong(
642 loadValue(
reinterpret_cast<std::int32_t&
>(l));
647 inline typename std::enable_if<
sizeof(T) ==
sizeof(std::int64_t) && std::is_signed<T>::value,
void>
::type loadLong(
650 loadValue(
reinterpret_cast<std::int64_t&
>(l));
655 inline typename std::enable_if<
sizeof(T) ==
sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>
::type
658 loadValue(
reinterpret_cast<std::uint32_t&
>(lu));
663 inline typename std::enable_if<
sizeof(T) ==
sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>
::type
666 loadValue(
reinterpret_cast<std::uint64_t&
>(lu));
672 inline typename std::enable_if<std::is_same<T, long>::value &&
sizeof(T) >=
sizeof(std::int64_t) &&
673 !std::is_same<T, std::int64_t>::value,
682 inline typename std::enable_if<std::is_same<T, unsigned long>::value &&
sizeof(T) >=
sizeof(std::uint64_t) &&
683 !std::is_same<T, std::uint64_t>::value,
693 void stringToNumber(std::string
const& str,
long long& val)
695 val = std::stoll(str);
698 void stringToNumber(std::string
const& str,
unsigned long long& val)
700 val = std::stoull(str);
703 void stringToNumber(std::string
const& str,
long double& val)
705 val = std::stold(str);
712 requires(std::is_arithmetic<T>::value && !std::is_same<T, long>::value &&
713 !std::is_same<T, unsigned long>::value && !std::is_same<T, std::int64_t>::value &&
714 !std::is_same<T, std::uint64_t>::value &&
715 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long)))
719 stringToNumber(encoded, val);
725 if(itsIteratorStack.size() == 1)
727 size = itsDocument.size();
731 size = (itsIteratorStack.rbegin() + 1)->value().
size();
738 const char* itsNextName;
739 std::vector<Iterator> itsIteratorStack;
740 YAML::Node itsDocument;
815 requires(!std::is_arithmetic_v<T> &&
816 !traits::has_minimal_base_class_serialization<T,
817 traits::has_minimal_output_serialization,
819 !traits::has_minimal_output_serialization<T, YAMLOutputArchive>::value)
827 requires(!std::is_arithmetic_v<T> &&
828 !traits::has_minimal_base_class_serialization<T,
829 traits::has_minimal_input_serialization,
831 !traits::has_minimal_input_serialization<T, YAMLInputArchive>::value)
843 requires(!std::is_arithmetic_v<T> &&
844 !traits::has_minimal_base_class_serialization<T,
845 traits::has_minimal_output_serialization,
847 !traits::has_minimal_output_serialization<T, YAMLOutputArchive>::value)
855 requires(!std::is_arithmetic_v<T> &&
856 !traits::has_minimal_base_class_serialization<T,
857 traits::has_minimal_input_serialization,
859 !traits::has_minimal_input_serialization<T, YAMLInputArchive>::value)
891 requires(std::is_arithmetic_v<T>)
899 requires(std::is_arithmetic_v<T>)
907 requires(std::is_arithmetic_v<T>)
914 requires(std::is_arithmetic_v<T>)
920template<
class CharT,
class Traits,
class Alloc>
927template<
class CharT,
class Traits,
class Alloc>
934template<
class CharT,
class Traits,
class Alloc>
940template<
class CharT,
class Traits,
class Alloc>
978 requires(std::is_arithmetic_v<T>)
986 requires(std::is_arithmetic_v<T>)
992template<
class CharT,
class Traits,
class Alloc>
999template<
class CharT,
class Traits,
class Alloc>
void saveBinaryValue(const void *data, size_t size, const char *name=nullptr)
Saves some binary data, encoded as a base64 string, with an optional name.
void saveValue(T t)
Serialize an unsigned long if it would not be caught otherwise.
void startNode()
Starts a new node in the YAML output.
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
void saveValue(int i)
Saves an int to the current node.
void saveValue(std::string const &s)
Saves a string to the current node.
void saveValue(int64_t i64)
Saves an int64 to the current node.
void makeArray()
Designates that the current node should be output as an array, not an object.
static constexpr bool is_binary
void saveValue(T t)
Serialize a long if it would not be caught otherwise.
YAMLOutputArchive(std::ostream &stream)
void saveValue(bool b)
Saves a bool to the current node.
~YAMLOutputArchive() noexcept
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
void setNextName(const char *name)
Sets the name for the next node created with startNode.
void finishNode()
Designates the most recently added node as finished.
void saveValue(double d)
Saves a double to the current node.
void saveValue(unsigned u)
Saves a uint to the current node.
void writeName()
Write the name of the upcoming node and prepare object/array state.
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
void saveValue(char const *s)
Saves a const char * to the current node.
void end(encoder *_encoder)
void prologue(YAMLOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for YAML archives.
void SER20_LOAD_FUNCTION_NAME(YAMLInputArchive &ar, NameValuePair< T > &t)
void SER20_SAVE_FUNCTION_NAME(YAMLOutputArchive &ar, NameValuePair< T > const &t)
Serializing NVP types to YAML.
void epilogue(YAMLOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for YAML archives.