diff --git a/docs/read_write.adoc b/docs/read_write.adoc index e77a9d3..33b09eb 100644 --- a/docs/read_write.adoc +++ b/docs/read_write.adoc @@ -53,7 +53,9 @@ auto w_spec = grp / ("reg"_r = 42); assert(w_spec == 42); // implicit conversion ---- -=== Read +=== Reading + +==== `read` The `read` function takes a `read_spec` and produces a https://intel.github.io/cpp-baremetal-senders-and-receivers/[sender]. @@ -77,6 +79,22 @@ Read can also be piped in a chain of senders. auto r = async::just(grp / "reg"_r) | groov::read() | async::sync_wait(); ---- +==== `read_as` + +The `read_as` function behaves like `read`, except that it takes a template +(type) argument: the read value will be converted to this type before being +sent. This works when reading one value only. + +[source,cpp] +---- +auto r = groov::read_as(grp / "reg"_r); +---- + +Here, the type of `"reg"_r` must be +https://cppreference.com/cpp/concepts/convertible_to[`convertible_to`] `bool`. + +==== `sync_read` + To do a simple read from a bus that is synchronous (e.g. an MMIO bus), `sync_read` may be called: @@ -88,7 +106,9 @@ auto r = async::just(grp / "reg"_r) | groov::sync_read(); NOTE: `sync_read` automatically assumes that the operation will succeed and returns the resulting `write_spec`. -=== Write +=== Writing + +==== `write` The `write` function takes a `write_spec` and produces a https://intel.github.io/cpp-baremetal-senders-and-receivers/[sender]. @@ -111,6 +131,8 @@ Write can also be piped in a chain of senders. auto r = async::just(grp("reg"_r = 42)) | groov::write() | async::sync_wait(); ---- +==== `sync_write` + To do a simple write to a bus that is synchronous (e.g. an MMIO bus), `sync_write` may be called: diff --git a/docs/synopsis.adoc b/docs/synopsis.adoc index 03b14c4..9a1c7d3 100644 --- a/docs/synopsis.adoc +++ b/docs/synopsis.adoc @@ -147,6 +147,7 @@ No identifiers: this is an omnibus header that includes other headers. ==== https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read.hpp[read.hpp] * `read` - a function that takes a `read_spec` and produces a sender that produces a `write_spec` +* `read_as` - a function template that takes a `read_spec` and produces a sender that produces a `T` * `sync_read` - a function that takes a `read_spec` and blocks, producing the `write_spec` ==== https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read_spec.hpp[read_spec.hpp] @@ -195,6 +196,7 @@ No public identifiers: this header contains metaprogramming helpers. * `mmio_bus` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/mmio_bus.hpp[`#include `] * `path` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/path.hpp[`#include `] * `read` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read.hpp[`#include `] +* `read_as` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read.hpp[`#include `] * `read_only` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/identity.hpp[`#include `] * `read_spec` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/read_spec.hpp[`#include `] * `register` - https://github.com/intel/generic-register-operation-optimizer/blob/main/include/groov/config.hpp[`#include `] diff --git a/include/groov/read.hpp b/include/groov/read.hpp index 71fd08f..367d31c 100644 --- a/include/groov/read.hpp +++ b/include/groov/read.hpp @@ -94,8 +94,8 @@ template consteval auto check_read_conversion() { } } // namespace detail -template -constexpr auto read(read_spec const &s) -> async::sender auto { +template +constexpr auto read_as(read_spec const &s) -> async::sender auto { using Spec = decltype(to_write_spec(s)); using fields_per_reg_t = boost::mp11::mp_transform_q< @@ -140,16 +140,23 @@ template struct pipeable { friend constexpr auto operator|(S &&s, pipeable) -> async::sender auto { return std::forward(s) | async::let_value([](Spec &&spec) { - return read(std::forward(spec)); + return read_as(std::forward(spec)); }); } }; } // namespace _read -template constexpr auto read() { +template constexpr auto read_as() { return async::compose(_read::pipeable{}); } +template +constexpr auto read(read_spec const &s) -> decltype(auto) { + return read_as(s); +} + +constexpr inline auto read() { return async::compose(_read::pipeable{}); } + namespace _sync_read { template [[nodiscard]] auto wait(S &&s) { static_assert(async::trivially_sync_waitable or diff --git a/test/fail/read/read_multi_conversion.cpp b/test/fail/read/read_multi_conversion.cpp index 65aaae3..c82d181 100644 --- a/test/fail/read/read_multi_conversion.cpp +++ b/test/fail/read/read_multi_conversion.cpp @@ -30,5 +30,5 @@ using G = groov::group<"group", read_bus, R>; auto main() -> int { using namespace groov::literals; - [[maybe_unused]] auto x = read(G{}("reg.f0"_f, "reg.f1"_f)); + [[maybe_unused]] auto x = read_as(G{}("reg.f0"_f, "reg.f1"_f)); } diff --git a/test/read.cpp b/test/read.cpp index 053c829..ab61f80 100644 --- a/test/read.cpp +++ b/test/read.cpp @@ -58,14 +58,22 @@ TEST_CASE("read a register", "[read]") { CHECK(r["reg0"_r] == data0); } -TEST_CASE("read a register and convert", "[read]") { +TEST_CASE("read a register and convert to its type", "[read]") { using namespace groov::literals; data0 = 0xa5a5'a5a5u; - auto s = read(grp / "reg0"_r); + auto s = read_as(grp / "reg0"_r); auto r = get<0>(*(s | async::sync_wait())); CHECK(r == data0); } +TEST_CASE("read a register and convert to different type", "[read]") { + using namespace groov::literals; + data0 = 0xa5a5'a5a5u; + auto s = read_as(grp / "reg0"_r); + auto r = get<0>(*(s | async::sync_wait())); + CHECK(r); +} + TEST_CASE("sync_read a register", "[read]") { using namespace groov::literals; data0 = 0xa5a5'a5a5u;