Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions include/groov/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>

#include <concepts>
#include <optional>
#include <type_traits>
#include <utility>
Expand Down Expand Up @@ -84,9 +85,16 @@ consteval auto check_write_only() -> void {
L{}, Masks{});
}

template <typename T, typename Spec> consteval auto check_read_conversion() {
STATIC_ASSERT(
(std::convertible_to<Spec, T>),
"Cannot convert the result of read ({}) to {} -- are you reading "
"multiple paths?",
Spec, T);
}
} // namespace detail

template <typename Group, typename Paths>
template <typename T = void, typename Group, typename Paths>
constexpr auto read(read_spec<Group, Paths> const &s) -> async::sender auto {
using Spec = decltype(to_write_spec(s));

Expand All @@ -104,35 +112,43 @@ constexpr auto read(read_spec<Group, Paths> const &s) -> async::sender auto {
detail::check_write_only<typename Spec::bus_t, read_fields_per_reg_t,
field_masks_t>();

using R = stdx::conditional_t<std::is_void_v<T>, Spec, T>;
detail::check_read_conversion<R, Spec>();

return []<typename... Rs, typename... Ms>(stdx::tuple<Rs...>,
stdx::tuple<Ms...>) {
return async::when_all(detail::read<Rs, Group, Ms>()...) |
async::then(stdx::overload{
[](typename Rs::type_t... values) {
[](typename Rs::type_t... values) -> R {
return Spec{{}, {Rs{{}, values}...}};
},
[](std::optional<typename Rs::type_t>... values) {
[](std::optional<typename Rs::type_t>... values)
-> std::optional<R> {
return stdx::transform(
[](auto... vs) { return Spec{{}, {Rs{{}, vs}...}}; },
[](auto... vs) -> R {
return Spec{{}, {Rs{{}, vs}...}};
},
values...);
}});
}(typename Spec::value_t{}, field_masks_t{});
}

namespace _read {
struct pipeable {
template <typename T> struct pipeable {
private:
template <async::sender S>
friend constexpr auto operator|(S &&s, pipeable) -> async::sender auto {
return std::forward<S>(s) |
async::let_value([]<typename Spec>(Spec &&spec) {
return read(std::forward<Spec>(spec));
return read<T>(std::forward<Spec>(spec));
});
}
};
} // namespace _read

constexpr auto read() { return async::compose(_read::pipeable{}); }
template <typename T = void> constexpr auto read() {
return async::compose(_read::pipeable<T>{});
}

namespace _sync_read {
template <typename Behavior, async::sender S> [[nodiscard]] auto wait(S &&s) {
Expand Down
5 changes: 3 additions & 2 deletions test/fail/read/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND ${CMAKE_CXX_COMPILER_VERSION}
return()
endif()

add_fail_tests(read_from_wo_field_indirect_by_register
read_from_wo_field_direct read_from_wo_register_direct)
add_fail_tests(
read_from_wo_field_indirect_by_register read_from_wo_field_direct
read_from_wo_register_direct read_multi_conversion)
34 changes: 34 additions & 0 deletions test/fail/read/read_multi_conversion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "../dummy_bus.hpp"

#include <groov/config.hpp>
#include <groov/identity.hpp>
#include <groov/path.hpp>
#include <groov/read.hpp>

#include <async/concepts.hpp>
#include <async/just.hpp>

#include <cstdint>

// EXPECT: to int -- are you reading multiple paths

namespace {
struct read_bus : dummy_bus {
template <stdx::ct_string, auto>
static auto read(auto...) -> async::sender auto {
return async::just(42);
}
};

using F0 = groov::field<"f0", std::uint8_t, 0, 0>;
using F1 = groov::field<"f1", std::uint8_t, 1, 1>;

std::uint32_t data{};
using R = groov::reg<"reg", std::uint32_t, &data, groov::w::replace, F0, F1>;
using G = groov::group<"group", read_bus, R>;
} // namespace

auto main() -> int {
using namespace groov::literals;
[[maybe_unused]] auto x = read<int>(G{}("reg.f0"_f, "reg.f1"_f));
}
8 changes: 8 additions & 0 deletions test/read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ TEST_CASE("read a register", "[read]") {
CHECK(r["reg0"_r] == data0);
}

TEST_CASE("read a register and convert", "[read]") {
using namespace groov::literals;
data0 = 0xa5a5'a5a5u;
auto s = read<std::uint32_t>(grp / "reg0"_r);
auto r = get<0>(*(s | async::sync_wait()));
CHECK(r == data0);
}

TEST_CASE("sync_read a register", "[read]") {
using namespace groov::literals;
data0 = 0xa5a5'a5a5u;
Expand Down
Loading