Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:51:36

0001 //
0002 // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MQTT5_BASE_DECODERS_HPP
0009 #define BOOST_MQTT5_BASE_DECODERS_HPP
0010 
0011 #include <boost/mqtt5/property_types.hpp>
0012 
0013 #include <boost/mqtt5/detail/traits.hpp>
0014 
0015 #include <boost/fusion/adapted/std_tuple.hpp>
0016 #include <boost/fusion/container/deque.hpp>
0017 #include <boost/optional/optional.hpp>
0018 #include <boost/spirit/home/x3.hpp>
0019 #include <boost/spirit/home/x3/binary/binary.hpp>
0020 
0021 #include <cstdint>
0022 #include <string>
0023 #include <utility>
0024 
0025 namespace boost::mqtt5::decoders {
0026 
0027 namespace x3 = boost::spirit::x3;
0028 
0029 template <typename T>
0030 struct convert { using type = T; };
0031 
0032 template <typename ...Args>
0033 struct convert<boost::fusion::deque<Args...>> {
0034     using type = std::tuple<typename convert<Args>::type...>;
0035 };
0036 
0037 template <typename T>
0038 struct convert<boost::optional<T>> {
0039     using type = std::optional<T>;
0040 };
0041 
0042 template <typename T>
0043 struct convert<std::vector<T>> {
0044     using type = std::vector<typename convert<T>::type>;
0045 };
0046 
0047 template <typename T, typename Parser>
0048 constexpr auto as(Parser&& p) {
0049     return x3::rule<struct _, T>{} = std::forward<Parser>(p);
0050 }
0051 
0052 
0053 template <typename It, typename Parser>
0054 auto type_parse(It& first, const It last, const Parser& p) {
0055     using ctx_type = decltype(x3::make_context<struct _>(std::declval<Parser&>()));
0056     using attr_type = typename x3::traits::attribute_of<Parser, ctx_type>::type;
0057 
0058     using rv_type = typename convert<attr_type>::type;
0059 
0060     std::optional<rv_type> rv;
0061     rv_type value {};
0062     if (x3::phrase_parse(first, last, as<rv_type>(p), x3::eps(false), value))
0063         rv = std::move(value);
0064     return rv;
0065 }
0066 
0067 
0068 template <typename AttributeType, typename It, typename Parser>
0069 auto type_parse(It& first, const It last, const Parser& p) {
0070     std::optional<AttributeType> rv;
0071     AttributeType value {};
0072     if (x3::phrase_parse(first, last, as<AttributeType>(p), x3::eps(false), value))
0073         rv = std::move(value);
0074     return rv;
0075 }
0076 
0077 namespace basic {
0078 
0079 template <typename T>
0080 constexpr auto to(T& arg) {
0081     return [&](auto& ctx) {
0082         using ctx_type = decltype(ctx);
0083         using attr_type = decltype(x3::_attr(std::declval<const ctx_type&>()));
0084         if constexpr (detail::is_boost_iterator<attr_type>)
0085             arg = T { x3::_attr(ctx).begin(), x3::_attr(ctx).end() };
0086         else
0087             arg = x3::_attr(ctx);
0088     };
0089 }
0090 
0091 template <typename LenParser, typename Subject, typename Enable = void>
0092 class scope_limit {};
0093 
0094 template <typename LenParser, typename Subject>
0095 class scope_limit<
0096     LenParser, Subject,
0097     std::enable_if_t<x3::traits::is_parser<LenParser>::value>
0098 > :
0099     public x3::unary_parser<Subject, scope_limit<LenParser, Subject>>
0100 {
0101     using base_type = x3::unary_parser<Subject, scope_limit<LenParser, Subject>>;
0102     LenParser _lp;
0103 public:
0104     using ctx_type =
0105         decltype(x3::make_context<struct _>(std::declval<Subject&>()));
0106     using attribute_type =
0107         typename x3::traits::attribute_of<Subject, ctx_type>::type;
0108 
0109     static bool const has_attribute = true;
0110 
0111     scope_limit(const LenParser& lp, const Subject& subject) :
0112         base_type(subject), _lp(lp)
0113     {}
0114 
0115     template <typename It, typename Ctx, typename RCtx, typename Attr>
0116     bool parse(
0117         It& first, const It last,
0118         const Ctx& ctx, RCtx& rctx, Attr& attr
0119     ) const {
0120 
0121         It iter = first;
0122         typename x3::traits::attribute_of<LenParser, Ctx>::type len;
0123         if (!_lp.parse(iter, last, ctx, rctx, len))
0124             return false;
0125         if (iter + len > last)
0126             return false;
0127 
0128         if (!base_type::subject.parse(iter, iter + len, ctx, rctx, attr))
0129             return false;
0130 
0131         first = iter;
0132         return true;
0133     }
0134 };
0135 
0136 template <typename Size, typename Subject>
0137 class scope_limit<
0138     Size, Subject,
0139     std::enable_if_t<std::is_arithmetic_v<Size>>
0140 > :
0141     public x3::unary_parser<Subject, scope_limit<Size, Subject>>
0142 {
0143     using base_type = x3::unary_parser<Subject, scope_limit<Size, Subject>>;
0144     size_t _limit;
0145 public:
0146     using ctx_type =
0147         decltype(x3::make_context<struct _>(std::declval<Subject&>()));
0148     using attribute_type =
0149         typename x3::traits::attribute_of<Subject, ctx_type>::type;
0150 
0151     static bool const has_attribute = true;
0152 
0153     scope_limit(Size limit, const Subject& subject) :
0154         base_type(subject), _limit(limit)
0155     {}
0156 
0157     template <typename It, typename Ctx, typename RCtx, typename Attr>
0158     bool parse(
0159         It& first, const It last,
0160         const Ctx& ctx, RCtx& rctx, Attr& attr
0161     ) const {
0162 
0163         It iter = first;
0164         if (iter + _limit > last)
0165             return false;
0166 
0167         if (!base_type::subject.parse(iter, iter + _limit, ctx, rctx, attr))
0168             return false;
0169 
0170         first = iter;
0171         return true;
0172     }
0173 };
0174 
0175 template <typename LenParser, typename Enable = void>
0176 struct scope_limit_gen {
0177     template <typename Subject>
0178     auto operator[](const Subject& p) const {
0179         return scope_limit<LenParser, Subject> { _lp, x3::as_parser(p) };
0180     }
0181     LenParser _lp;
0182 };
0183 
0184 template <typename Size>
0185 struct scope_limit_gen<
0186     Size,
0187     std::enable_if_t<std::is_arithmetic_v<Size>>
0188 > {
0189     template <typename Subject>
0190     auto operator[](const Subject& p) const {
0191         return scope_limit<Size, Subject> { limit, x3::as_parser(p) };
0192     }
0193     Size limit;
0194 };
0195 
0196 template <
0197     typename Parser,
0198     std::enable_if_t<x3::traits::is_parser<Parser>::value, bool> = true
0199 >
0200 scope_limit_gen<Parser> scope_limit_(const Parser& p) {
0201     return { p };
0202 }
0203 
0204 template <
0205     typename Size,
0206     std::enable_if_t<std::is_arithmetic_v<Size>, bool> = true
0207 >
0208 scope_limit_gen<Size> scope_limit_(Size limit) {
0209     return { limit };
0210 }
0211 
0212 struct verbatim_parser : x3::parser<verbatim_parser> {
0213     using attribute_type = std::string;
0214     static bool const has_attribute = true;
0215 
0216     template <typename It, typename Ctx, typename RCtx, typename Attr>
0217     bool parse(It& first, const It last, const Ctx&, RCtx&, Attr& attr) const {
0218         attr = std::string { first, last };
0219         first = last;
0220         return true;
0221     }
0222 };
0223 
0224 constexpr auto verbatim_ = verbatim_parser{};
0225 
0226 struct varint_parser : x3::parser<varint_parser> {
0227     using attribute_type = int32_t;
0228     static bool const has_attribute = true;
0229 
0230     template <typename It, typename Ctx, typename RCtx, typename Attr>
0231     bool parse(
0232         It& first, const It last,
0233         const Ctx& ctx, RCtx&, Attr& attr
0234     ) const {
0235 
0236         It iter = first;
0237         x3::skip_over(iter, last, ctx);
0238 
0239         if (iter == last)
0240             return false;
0241 
0242         int32_t result = 0; unsigned bit_shift = 0;
0243 
0244         for (; iter != last && bit_shift < sizeof(int32_t) * 7; ++iter) {
0245             auto val = *iter;
0246             if (val & 0b1000'0000u) {
0247                 result |= (val & 0b0111'1111u) << bit_shift;
0248                 bit_shift += 7;
0249             }
0250             else {
0251                 result |= (static_cast<int32_t>(val) << bit_shift);
0252                 bit_shift = 0;
0253                 break;
0254             }
0255         }
0256         if (bit_shift)
0257             return false;
0258 
0259         attr = result;
0260         first = ++iter;
0261         return true;
0262     }
0263 };
0264 
0265 constexpr varint_parser varint_{};
0266 
0267 struct len_prefix_parser : x3::parser<len_prefix_parser> {
0268     using attribute_type = std::string;
0269     static bool const has_attribute = true;
0270 
0271     template <typename It, typename Ctx, typename RCtx, typename Attr>
0272     bool parse(
0273         It& first, const It last,
0274         const Ctx& ctx, RCtx& rctx, Attr& attr
0275     ) const {
0276         It iter = first;
0277         x3::skip_over(iter, last, ctx);
0278 
0279         typename x3::traits::attribute_of<decltype(x3::big_word), Ctx>::type len;
0280         if (x3::big_word.parse(iter, last, ctx, rctx, len)) {
0281             if (std::distance(iter, last) < len)
0282                 return false;
0283         }
0284         else
0285             return false;
0286 
0287         attr = std::string(iter, iter + len);
0288         first = iter + len;
0289         return true;
0290     }
0291 };
0292 
0293 constexpr len_prefix_parser utf8_ {};
0294 constexpr len_prefix_parser binary_ {};
0295 
0296 /*
0297      Boost Spirit incorrectly deduces atribute type for a parser of the form
0298          (eps(a) | parser1) >> (eps(b) | parser)
0299     and we had to create if_ parser to remedy the issue
0300 */
0301 
0302 template <typename Subject>
0303 class conditional_parser :
0304     public x3::unary_parser<Subject, conditional_parser<Subject>> {
0305 
0306     using base_type = x3::unary_parser<Subject, conditional_parser<Subject>>;
0307     bool _condition;
0308 public:
0309     using ctx_type =
0310         decltype(x3::make_context<struct _>(std::declval<Subject&>()));
0311     using subject_attr_type =
0312         typename x3::traits::attribute_of<Subject, ctx_type>::type;
0313 
0314     using attribute_type = boost::optional<subject_attr_type>;
0315     static bool const has_attribute = true;
0316 
0317     conditional_parser(const Subject& s, bool condition) :
0318         base_type(s), _condition(condition) {}
0319 
0320     template <typename It, typename Ctx, typename RCtx, typename Attr>
0321     bool parse(
0322         It& first, const It last,
0323         const Ctx& ctx, RCtx& rctx, Attr& attr
0324     ) const {
0325         if (!_condition)
0326             return true;
0327 
0328         It iter = first;
0329         subject_attr_type sattr {};
0330         if (!base_type::subject.parse(iter, last, ctx, rctx, sattr))
0331             return false;
0332 
0333         attr.emplace(std::move(sattr));
0334         first = iter;
0335         return true;
0336     }
0337 };
0338 
0339 struct conditional_gen {
0340     bool _condition;
0341 
0342     template <typename Subject>
0343     auto operator[](const Subject& p) const {
0344         return conditional_parser<Subject> { p, _condition };
0345     }
0346 };
0347 
0348 inline conditional_gen if_(bool condition) {
0349     return { condition };
0350 }
0351 
0352 } // end namespace basic
0353 
0354 
0355 namespace prop {
0356 
0357 namespace basic = boost::mqtt5::decoders::basic;
0358 
0359 namespace detail {
0360 
0361 template <typename It, typename Ctx, typename RCtx, typename Prop>
0362 bool parse_to_prop(
0363     It& iter, const It last,
0364     const Ctx& ctx, RCtx& rctx, Prop& prop
0365 ) {
0366     using namespace boost::mqtt5::detail;
0367     using prop_type = std::remove_reference_t<decltype(prop)>;
0368 
0369     bool rv = false;
0370 
0371     if constexpr (std::is_same_v<prop_type, uint8_t>)
0372         rv = x3::byte_.parse(iter, last, ctx, rctx, prop);
0373     else if constexpr (std::is_same_v<prop_type, uint16_t>)
0374         rv = x3::big_word.parse(iter, last, ctx, rctx, prop);
0375     else if constexpr (std::is_same_v<prop_type, int32_t>)
0376         rv = basic::varint_.parse(iter, last, ctx, rctx, prop);
0377     else if constexpr (std::is_same_v<prop_type, uint32_t>)
0378         rv = x3::big_dword.parse(iter, last, ctx, rctx, prop);
0379     else if constexpr (std::is_same_v<prop_type, std::string>)
0380         rv = basic::utf8_.parse(iter, last, ctx, rctx, prop);
0381 
0382     else if constexpr (is_optional<prop_type>) {
0383         typename prop_type::value_type val;
0384         rv = parse_to_prop(iter, last, ctx, rctx, val);
0385         if (rv) prop.emplace(std::move(val));
0386     }
0387 
0388     else if constexpr (is_pair<prop_type>) {
0389         rv = parse_to_prop(iter, last, ctx, rctx, prop.first);
0390         rv = parse_to_prop(iter, last, ctx, rctx, prop.second);
0391     }
0392 
0393     else if constexpr (is_vector<prop_type> || is_small_vector<prop_type>) {
0394         typename std::remove_reference_t<prop_type>::value_type value;
0395         rv = parse_to_prop(iter, last, ctx, rctx, value);
0396         if (rv) prop.push_back(std::move(value));
0397     }
0398 
0399     return rv;
0400 }
0401 
0402 } // end namespace detail
0403 
0404 template <typename Props>
0405 class prop_parser : public x3::parser<prop_parser<Props>> {
0406 public:
0407     using attribute_type = Props;
0408     static bool const has_attribute = true;
0409 
0410     template <typename It, typename Ctx, typename RCtx, typename Attr>
0411     bool parse(
0412         It& first, const It last,
0413         const Ctx& ctx, RCtx& rctx, Attr& attr
0414     ) const {
0415 
0416         It iter = first;
0417         x3::skip_over(iter, last, ctx);
0418 
0419         if (iter == last)
0420             return true;
0421 
0422         int32_t props_length;
0423         if (!basic::varint_.parse(iter, last, ctx, rctx, props_length))
0424             return false;
0425 
0426         const It scoped_last = iter + props_length;
0427         // attr = Props{};
0428 
0429         while (iter < scoped_last) {
0430             uint8_t prop_id = *iter++;
0431             bool rv = true;
0432             It saved = iter;
0433 
0434             attr.apply_on(
0435                 prop_id,
0436                 [&rv, &iter, scoped_last, &ctx, &rctx](auto& prop) {
0437                     rv = detail::parse_to_prop(
0438                         iter, scoped_last, ctx, rctx, prop
0439                     );
0440                 }
0441             );
0442 
0443             // either rv = false or property with prop_id was not found
0444             if (!rv || iter == saved)
0445                 return false;
0446         }
0447 
0448         first = iter;
0449         return true;
0450     }
0451 };
0452 
0453 
0454 template <typename Props>
0455 constexpr auto props_ = prop_parser<Props> {};
0456 
0457 } // end namespace prop
0458 
0459 
0460 } // end namespace boost::mqtt5::decoders
0461 
0462 #endif // !BOOST_MQTT5_BASE_DECODERS_HPP