read.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "crucible/boba/read.hpp" #include "crucible/core/either.inl" #include "crucible/parsing/bytes.inl" #include "crucible/parsing/combinators.inl" #include "crucible/parsing/errors.inl" #include <cstddef> namespace crucible::boba::read { namespace { std::vector<std::byte> const BOBA_SIGNATURE { std::byte { 0x42 }, std::byte { 0x4f }, std::byte { 0x42 }, std::byte { 0x41 } }; std::vector<std::byte> const BOBA_VERSION { std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 } }; auto make_container(std::vector<container::Header> const &headers) -> container::Container { return { headers }; } auto make_header(std::pair<std::uint32_t, std::uint32_t> const &fields) -> container::Header { constexpr std::uint32_t DATA_SIZE_MASK { 0x00ffffff }; constexpr std::size_t DATA_SIZE_SHIFT { 0 }; return { fields.first, (fields.second & DATA_SIZE_MASK) >> DATA_SIZE_SHIFT }; } template<typename T> auto make_none(T &&) -> core::none::None { return {}; } template<typename T> auto unwrap_parsing_accept(parsing::errors::Accept<parsing::bytes::State, T> const &accept) -> T { return accept.get_value(); }; auto wrap_parsing_error(parsing::errors::Reject<parsing::bytes::State> const &reject) -> errors::BobaError { return errors::ParsingFailed { reject.get_error() }; } auto const boba_signature_validation_parser { parsing::bytes::make_exact(BOBA_SIGNATURE) }; auto const boba_version_validation_parser { parsing::bytes::make_exact(BOBA_VERSION) }; auto const validation_parser { parsing::combinators::make_map( parsing::combinators::make_pair( boba_signature_validation_parser, boba_version_validation_parser ), make_none<std::pair<std::vector<std::byte>, std::vector<std::byte>>> ) }; auto const header_count_parser { parsing::bytes::make_u32_be() }; auto const header_signature_parser { parsing::bytes::make_u32_be() }; auto const header_data_size_parser { parsing::bytes::make_u32_be() }; auto const header_parser { parsing::combinators::make_map( parsing::combinators::make_pair( header_signature_parser, header_data_size_parser ), make_header ) }; auto make_header_list_parser(std::uint32_t const header_list_info) -> parsing::combinators::SequenceOf<std::remove_cvref_t<decltype(header_parser)>> { constexpr std::uint32_t HEADER_COUNT_MASK { 0x000000ff }; std::uint32_t const header_count { (header_list_info & HEADER_COUNT_MASK) }; return parsing::combinators::make_sequence_of( header_parser, header_count ); } template<typename T, typename U> auto second(std::pair<T, U> const &pair) -> U { return pair.second; } auto const container_parser { parsing::combinators::make_map( parsing::combinators::make_pair( validation_parser, parsing::combinators::make_map( parsing::combinators::make_bind( header_count_parser, make_header_list_parser ), make_container ) ), second<core::none::None, container::Container> ) }; } auto from_bytes(std::vector<std::byte> const &bytes) -> errors::BobaResult<container::Container> { parsing::bytes::State initial_state { bytes }; auto const container { container_parser(initial_state) }; return container .map_lhs(wrap_parsing_error) .map_rhs(unwrap_parsing_accept<container::Container>); } }