-
Notifications
You must be signed in to change notification settings - Fork 179
Add support for reading from a byte-container for cbor and ubjson #469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| #ifndef RFL_CONCEPTS_HPP_ | ||
| #define RFL_CONCEPTS_HPP_ | ||
|
|
||
| #include <concepts> | ||
| #include <type_traits> | ||
| #include <cstdint> | ||
| #include <cstddef> | ||
| #include <iterator> | ||
|
|
||
| namespace rfl { | ||
|
|
||
| /// @brief Concept for byte-like types that can be used in contiguous containers | ||
| /// Includes char, signed char, unsigned char, std::byte, and uint8_t | ||
| template<typename T> | ||
| concept ByteLike = std::same_as<T, char> || | ||
| std::same_as<T, signed char> || | ||
| std::same_as<T, unsigned char> || | ||
| std::same_as<T, std::uint8_t> || | ||
| std::same_as<T, std::byte>; | ||
|
|
||
| /// @brief Concept for containers with a contiguous sequence of byte-like types | ||
| /// Requires: | ||
| /// - Container has a value_type that is byte-like | ||
| /// - Container provides data() method returning a pointer to contiguous memory | ||
| /// - Container provides size() method returning the number of elements | ||
| /// - Container supports range-based for loops (begin/end) | ||
| template<typename Container> | ||
| concept ContiguousByteContainer = requires(const Container& c) { | ||
| typename Container::value_type; | ||
| { c.data() } -> std::convertible_to<const typename Container::value_type*>; | ||
| { c.size() } -> std::convertible_to<std::size_t>; | ||
| { c.begin() } -> std::input_iterator; | ||
| { c.end() } -> std::input_iterator; | ||
| requires ByteLike<typename Container::value_type>; | ||
| requires std::contiguous_iterator<decltype(c.begin())>; | ||
| }; | ||
|
|
||
| /// @brief Concept for mutable containers with a contiguous sequence of byte-like types | ||
| /// Extends ContiguousByteContainer with mutable access requirements | ||
| template<typename Container> | ||
| concept MutableContiguousByteContainer = ContiguousByteContainer<Container> && requires(Container& c) { | ||
| { c.data() } -> std::convertible_to<typename Container::value_type*>; | ||
| { c.begin() } -> std::output_iterator<typename Container::value_type>; | ||
| { c.end() } -> std::output_iterator<typename Container::value_type>; | ||
| }; | ||
|
|
||
| /// @brief Concept for back-insertable byte containers (like std::vector<uint8_t>) | ||
| /// Useful for containers that can grow dynamically during serialization | ||
| template<typename Container> | ||
| concept BackInsertableByteContainer = ContiguousByteContainer<Container> && requires(Container& c, typename Container::value_type v) { | ||
| c.push_back(v); | ||
| c.reserve(std::size_t{}); | ||
| { c.capacity() } -> std::convertible_to<std::size_t>; | ||
| }; | ||
|
|
||
| /// @brief Concept for byte spans or views (read-only, non-owning containers) | ||
| /// Includes std::span<const uint8_t>, std::string_view when used with char data, etc. | ||
| template<typename Container> | ||
| concept ByteSpanLike = ContiguousByteContainer<Container> && | ||
| std::is_trivially_copyable_v<Container> && | ||
| std::is_trivially_destructible_v<Container>; | ||
|
|
||
| } // namespace rfl | ||
|
|
||
| #endif // RFL_CONCEPTS_HPP_ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| #include <algorithm> | ||
| #include <array> | ||
| #include <rfl/cbor.hpp> | ||
|
|
||
| #include <gtest/gtest.h> | ||
|
|
||
| // Make sure things still compile when | ||
| // rfl.hpp is included after rfl/cbor.hpp. | ||
| #include <rfl.hpp> | ||
|
|
||
| namespace test_read_byte_containers | ||
| { | ||
|
|
||
| struct TestBox | ||
| { | ||
| int length; | ||
| int width; | ||
| int height; | ||
| }; | ||
|
|
||
| // TODO: Apparently the jsoncons trait is_byte_sequence<T> is not working for std::span. | ||
| // TEST(cbor, test_read_from_char_span) | ||
| // { | ||
|
|
||
| // TestBox b = { | ||
| // .length = 1, | ||
| // .width = 2, | ||
| // .height = 3, | ||
| // }; | ||
|
|
||
|
|
||
| // std::vector<char> rfl_buffer = rfl::cbor::write(s); | ||
|
|
||
| // // I don't want to be forced to copy to a std::vector<char> if that's not what data strucure I use. | ||
| // // So, allow reading from a std::span | ||
| // std::span<char> span(rfl_buffer.data(), rfl_buffer.size()); | ||
|
|
||
| // auto result = rfl::cbor::read<TestBox>(span); | ||
| // EXPECT_TRUE(result); | ||
| // EXPECT_EQ(result->one, 1); | ||
| // EXPECT_EQ(result->two, 2); | ||
| // } | ||
|
|
||
| TEST(cbor, test_read_from_byte_view) | ||
| { | ||
| TestBox b = { | ||
| .length = 1, | ||
| .width = 2, | ||
| .height = 3, | ||
| }; | ||
|
|
||
| // TODO: Write directly into desired container, once rfl::cbor::write supports it. | ||
| std::vector<char> rfl_buffer = rfl::cbor::write(b); | ||
|
|
||
| std::array<std::byte, 64> my_buffer; | ||
| std::transform(rfl_buffer.begin(), rfl_buffer.end(), my_buffer.begin(), | ||
| [](char c) { return static_cast<std::byte>(c); }); | ||
|
|
||
| std::basic_string_view<std::byte> byte_view(my_buffer.data(), rfl_buffer.size()); | ||
|
|
||
| auto result = rfl::cbor::read<TestBox>(byte_view); | ||
| EXPECT_TRUE(result); | ||
| EXPECT_EQ(result->length, 1); | ||
| EXPECT_EQ(result->width, 2); | ||
| EXPECT_EQ(result->height, 3); | ||
| } | ||
|
|
||
| TEST(cbor, test_read_from_uint8_array) | ||
| { | ||
| TestBox b = { | ||
| .length = 4, | ||
| .width = 5, | ||
| .height = 6, | ||
| }; | ||
|
|
||
| // TODO: Write directly into desired container, once rfl::cbor::write supports it. | ||
| std::vector<char> rfl_buffer = rfl::cbor::write(b); | ||
|
|
||
| std::array<std::uint8_t, 64> my_buffer; | ||
| std::transform(rfl_buffer.begin(), rfl_buffer.end(), my_buffer.begin(), | ||
| [](char c) { return static_cast<std::uint8_t>(c); }); | ||
|
|
||
| auto result = rfl::cbor::read<TestBox>(my_buffer); | ||
| EXPECT_TRUE(result); | ||
| EXPECT_EQ(result->length, 4); | ||
| EXPECT_EQ(result->width, 5); | ||
| EXPECT_EQ(result->height, 6); | ||
| } | ||
|
|
||
| } // namespace test_read_byte_containers |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #include <vector> | ||
| #include <array> | ||
| #include <string> | ||
| #include <cassert> | ||
| #include <rfl/concepts.hpp> | ||
|
|
||
| #include "write_and_read.hpp" | ||
|
|
||
| namespace test_byte_container_concepts { | ||
|
|
||
| TEST(generic, test_byte_container_concepts) { | ||
| // Test various container types | ||
| std::vector<std::uint8_t> vec_uint8{1, 2, 3, 4}; | ||
| std::vector<char> vec_char{'a', 'b', 'c'}; | ||
| std::array<std::uint8_t, 4> arr_uint8{1, 2, 3, 4}; | ||
| std::string str_data{"hello"}; | ||
| std::string_view str_view{"world"}; | ||
| std::array<std::byte, 5> arr_byte{std::byte{5}, std::byte{4}, std::byte{3}, std::byte{2}, std::byte{1}}; | ||
| std::span<std::byte> byte_span = arr_byte; | ||
|
|
||
| // Test with concepts | ||
| static_assert(rfl::ByteLike<std::uint8_t>); | ||
| static_assert(rfl::ByteLike<char>); | ||
| static_assert(rfl::ByteLike<unsigned char>); | ||
| static_assert(rfl::ByteLike<std::byte>); | ||
| static_assert(!rfl::ByteLike<int>); | ||
| static_assert(!rfl::ByteLike<float>); | ||
|
|
||
| static_assert(rfl::ContiguousByteContainer<decltype(vec_uint8)>); | ||
| static_assert(rfl::ContiguousByteContainer<decltype(vec_char)>); | ||
| static_assert(rfl::ContiguousByteContainer<decltype(arr_uint8)>); | ||
| static_assert(rfl::ContiguousByteContainer<decltype(str_data)>); | ||
| static_assert(rfl::ContiguousByteContainer<decltype(str_view)>); | ||
| static_assert(rfl::ContiguousByteContainer<decltype(arr_byte)>); | ||
| static_assert(rfl::ContiguousByteContainer<decltype(byte_span)>); | ||
|
|
||
| static_assert(rfl::MutableContiguousByteContainer<decltype(vec_uint8)>); | ||
| static_assert(rfl::MutableContiguousByteContainer<decltype(vec_char)>); | ||
| static_assert(rfl::MutableContiguousByteContainer<decltype(arr_uint8)>); | ||
| static_assert(rfl::MutableContiguousByteContainer<decltype(str_data)>); | ||
| static_assert(!rfl::MutableContiguousByteContainer<decltype(str_view)>); | ||
| static_assert(rfl::MutableContiguousByteContainer<decltype(arr_byte)>); | ||
| static_assert(rfl::MutableContiguousByteContainer<decltype(byte_span)>); | ||
|
|
||
| static_assert(rfl::BackInsertableByteContainer<decltype(vec_uint8)>); | ||
| static_assert(rfl::BackInsertableByteContainer<decltype(vec_char)>); | ||
| static_assert(!rfl::BackInsertableByteContainer<decltype(arr_uint8)>); | ||
| static_assert(rfl::BackInsertableByteContainer<decltype(str_data)>); | ||
| static_assert(!rfl::BackInsertableByteContainer<decltype(str_view)>); | ||
| static_assert(!rfl::BackInsertableByteContainer<decltype(arr_byte)>); | ||
| static_assert(!rfl::BackInsertableByteContainer<decltype(byte_span)>); | ||
| } | ||
|
|
||
| } // namespace test_byte_container_concepts |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| #include <algorithm> | ||
| #include <array> | ||
| #include <rfl/ubjson.hpp> | ||
|
|
||
| #include <gtest/gtest.h> | ||
|
|
||
| // Make sure things still compile when | ||
| // rfl.hpp is included after rfl/ubjson.hpp. | ||
| #include <rfl.hpp> | ||
|
|
||
| namespace test_read_byte_containers | ||
| { | ||
|
|
||
| struct TestBall | ||
| { | ||
| float radius; | ||
| float mass; | ||
| }; | ||
|
|
||
| TEST(ubjson, test_read_from_byte_view) | ||
| { | ||
| TestBall b = { | ||
| .radius = 1.5f, | ||
| .mass = 2.5f, | ||
| }; | ||
|
|
||
| // TODO: Write directly into desired container, once rfl::ubjson::write supports it. | ||
| std::vector<char> rfl_buffer = rfl::ubjson::write(b); | ||
|
|
||
| std::array<std::byte, 64> my_buffer; | ||
| std::transform(rfl_buffer.begin(), rfl_buffer.end(), my_buffer.begin(), | ||
| [](char c) { return static_cast<std::byte>(c); }); | ||
|
|
||
| std::basic_string_view<std::byte> byte_view(my_buffer.data(), rfl_buffer.size()); | ||
|
|
||
| auto result = rfl::ubjson::read<TestBall>(byte_view); | ||
| EXPECT_TRUE(result); | ||
| EXPECT_EQ(result->radius, 1.5f); | ||
| EXPECT_EQ(result->mass, 2.5f); | ||
| } | ||
|
|
||
| TEST(ubjson, test_read_from_uint8_array) | ||
| { | ||
| TestBall b = { | ||
| .radius = 4.5f, | ||
| .mass = 5.5f, | ||
| }; | ||
|
|
||
| // TODO: Write directly into desired container, once rfl::ubjson::write supports it. | ||
| std::vector<char> rfl_buffer = rfl::ubjson::write(b); | ||
|
|
||
| std::array<std::uint8_t, 64> my_buffer; | ||
| std::transform(rfl_buffer.begin(), rfl_buffer.end(), my_buffer.begin(), | ||
| [](char c) { return static_cast<std::uint8_t>(c); }); | ||
|
|
||
| auto result = rfl::ubjson::read<TestBall>(my_buffer); | ||
| EXPECT_TRUE(result); | ||
| EXPECT_EQ(result->radius, 4.5f); | ||
| EXPECT_EQ(result->mass, 5.5f); | ||
| } | ||
|
|
||
| } // namespace test_read_byte_containers |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
MutableContiguousByteContainerconcept extendsContiguousByteContainerand adds requirements for mutable access. However, the checks forstd::output_iteratoronc.begin()andc.end()might be redundant and semantically confusing, as one cannot typically write to anenditerator. Relying on the non-constdata()method on line 42 might be a clearer way to ensure mutability.