#ifndef RFL_PARSING_PARSER_OPTIONAL_HPP_ #define RFL_PARSING_PARSER_OPTIONAL_HPP_ #include #include #include #include "../Ref.hpp" #include "../Result.hpp" #include "../always_false.hpp" #include "Parent.hpp" #include "Parser_base.hpp" #include "schema/Type.hpp" #include "schemaful/IsSchemafulReader.hpp" #include "schemaful/IsSchemafulWriter.hpp" #include "schemaful/OptionalReader.hpp" namespace rfl { namespace parsing { template requires AreReaderAndWriter> struct Parser, ProcessorsType> { using InputVarType = typename R::InputVarType; using ParentType = Parent; static Result> read(const R& _r, const InputVarType& _var) noexcept { if constexpr (schemaful::IsSchemafulReader) { using O = schemaful::OptionalReader, ProcessorsType>; const auto to_optional = [&](const auto& _u) -> Result> { return _r.template read_union, O>(_u); }; return _r.to_union(_var).and_then(to_optional); } else { if (_r.is_empty(_var)) { return std::optional(); } const auto to_opt = [](auto&& _t) { return std::make_optional(std::forward(_t)); }; return Parser, ProcessorsType>::read(_r, _var) .transform(to_opt); } } template static void write(const W& _w, const std::optional& _o, const P& _parent) { if constexpr (schemaful::IsSchemafulWriter) { auto u = ParentType::add_union(_w, _parent); using UnionType = typename ParentType::template Union; auto p = UnionType{.index_ = static_cast(_o ? 0 : 1), .union_ = &u}; if (_o) { Parser, ProcessorsType>::write(_w, *_o, p); } else { ParentType::add_null(_w, p); } } else { if (_o) { Parser, ProcessorsType>::write(_w, *_o, _parent); } else { ParentType::add_null(_w, _parent); } } } static schema::Type to_schema( std::map* _definitions) { using U = std::remove_cvref_t; return schema::Type{schema::Type::Optional{Ref::make( Parser::to_schema(_definitions))}}; } }; } // namespace parsing } // namespace rfl #endif