Skip to content

Commit

Permalink
Add parseType to select a type from a list and pass it to a generic f…
Browse files Browse the repository at this point in the history
…unction
  • Loading branch information
PJutch committed Jun 29, 2024
1 parent b6b228c commit 86ca5f9
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 1 deletion.
1 change: 1 addition & 0 deletions include/JutchsON.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "JutchsON/parse/struct.hpp"
#include "JutchsON/parse/variant.hpp"
#include "JutchsON/parse/optional.hpp"
#include "JutchsON/parse/type.hpp"

#include "JutchsON/write/num.hpp"
#include "JutchsON/write/list.hpp"
Expand Down
29 changes: 29 additions & 0 deletions include/JutchsON/parse/type.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef JUTCHSON_PARSE_TYPE_HPP_
#define JUTCHSON_PARSE_TYPE_HPP_

#include "../type.hpp"

#include "../ParseResult.hpp"
#include "../StringView.hpp"

namespace JutchsON {
template <typename GenericF, typename Typenames>
using InvokeOnTagsResult = std::invoke_result_t<GenericF, typename std::tuple_element_t<0, Typenames>::TagType>;

template <size_t i = 0, typename Typenames, typename GenericF>
ParseResult<InvokeOnTagsResult<GenericF, Typenames>> parseType(
JutchsON::StringView s, const Typenames& typenames, GenericF&& genericF
) {
if constexpr (i >= std::tuple_size_v<Typenames>) {
return ParseResult<InvokeOnTagsResult<GenericF, Typenames>>
::makeError(s.location(), std::format("Unknown type {}", s.asStd()));
} else {
if (s == std::get<i>(typenames).value) {
return genericF(std::get<i>(typenames).tag());
}
return parseType<i + 1>(s, typenames, genericF);
}
}
}

#endif
30 changes: 30 additions & 0 deletions include/JutchsON/type.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef JUTCHSON_TYPE_HPP_
#define JUTCHSON_TYPE_HPP_

#include <type_traits>

namespace JutchsON {
template <typename T, typename Value = void>
struct TaggedValue {
using type = T;
using TagType = TaggedValue<T>;

Value value;

TagType tag() const {
return {};
}
};

template <typename T>
struct TaggedValue<T, void> {
using type = T;
};

template <typename T>
using PayloadType = typename std::remove_cvref_t<T>::type;
}

#define JUTCHSON_TAGGED_TYPE_NAME(T) (JutchsON::TaggedValue<T, std::string>{#T})

#endif
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ add_executable(JutchsON_tests "Location.cpp" "ParseResult.cpp" "escape.cpp" "St
"parse/num.cpp" "write/num.cpp" "parse/list.cpp" "write/list.cpp" "parse/dict.cpp" "write/dict.cpp"
"parse/bool.cpp" "write/bool.cpp" "parse/str.cpp" "write/str.cpp"
"parse/tuple.cpp" "parse/struct.cpp" "write/tuple.cpp" "write/struct.cpp"
"parse/variant.cpp" "write/variant.cpp" "parse/optional.cpp" "write/optional.cpp")
"parse/variant.cpp" "write/variant.cpp" "parse/optional.cpp" "write/optional.cpp" "parse/type.cpp")

target_link_libraries(JutchsON_tests JutchsON JutchsON_test_dependencies)
setDefaultCompilerOptions(JutchsON_tests PRIVATE)
Expand Down
41 changes: 41 additions & 0 deletions tests/parse/type.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "JutchsON.hpp"

#include <gtest/gtest.h>

namespace {
struct TestType1 {};
struct TestType2 {};
}

TEST(Type, parseType) {
std::tuple typenames{
JUTCHSON_TAGGED_TYPE_NAME(TestType1),
JUTCHSON_TAGGED_TYPE_NAME(TestType2)
};

EXPECT_TRUE(*parseType("TestType1", typenames, [](auto tag) {
return std::same_as<JutchsON::PayloadType<decltype(tag)>, TestType1>;
}));
}

TEST(Type, parseTypeSecond) {
std::tuple typenames{
JUTCHSON_TAGGED_TYPE_NAME(TestType1),
JUTCHSON_TAGGED_TYPE_NAME(TestType2)
};

EXPECT_TRUE(*parseType("TestType2", typenames, [](auto tag) {
return std::same_as<JutchsON::PayloadType<decltype(tag)>, TestType2>;
}));
}

TEST(Type, parseTypeUnknown) {
std::tuple typenames{
JUTCHSON_TAGGED_TYPE_NAME(TestType1),
JUTCHSON_TAGGED_TYPE_NAME(TestType2)
};

EXPECT_EQ(parseType("garbage", typenames, [](auto tag) {
return std::same_as<JutchsON::PayloadType<decltype(tag)>, TestType1>;
}), JutchsON::ParseResult<bool>::makeError({0, 0}, "Unknown type garbage"));
}

0 comments on commit 86ca5f9

Please sign in to comment.