1  
//
1  
//
2  
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_URL_GRAMMAR_TUPLE_RULE_HPP
10  
#ifndef BOOST_URL_GRAMMAR_TUPLE_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_TUPLE_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_TUPLE_RULE_HPP
12  

12  

13  
#include <boost/url/detail/config.hpp>
13  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/error_types.hpp>
14  
#include <boost/url/error_types.hpp>
15  
#include <boost/url/grammar/error.hpp>
15  
#include <boost/url/grammar/error.hpp>
16  
#include <boost/url/grammar/detail/tuple.hpp>
16  
#include <boost/url/grammar/detail/tuple.hpp>
17  
#include <boost/url/grammar/type_traits.hpp>
17  
#include <boost/url/grammar/type_traits.hpp>
18  
#include <boost/mp11/algorithm.hpp>
18  
#include <boost/mp11/algorithm.hpp>
19  
#include <boost/core/detail/static_assert.hpp>
19  
#include <boost/core/detail/static_assert.hpp>
20  
#include <boost/core/empty_value.hpp>
20  
#include <boost/core/empty_value.hpp>
21  
#include <tuple>
21  
#include <tuple>
22  

22  

23  
namespace boost {
23  
namespace boost {
24  
namespace urls {
24  
namespace urls {
25  
namespace grammar {
25  
namespace grammar {
26  

26  

27  
namespace implementation_defined {
27  
namespace implementation_defined {
28  
template<
28  
template<
29  
    class R0,
29  
    class R0,
30  
    class... Rn>
30  
    class... Rn>
31  
class tuple_rule_t
31  
class tuple_rule_t
32  
    : empty_value<
32  
    : empty_value<
33  
        detail::tuple<R0, Rn...>>
33  
        detail::tuple<R0, Rn...>>
34  
{
34  
{
35  
    using T = mp11::mp_remove<
35  
    using T = mp11::mp_remove<
36  
        std::tuple<
36  
        std::tuple<
37  
            typename R0::value_type,
37  
            typename R0::value_type,
38  
            typename Rn::value_type...>,
38  
            typename Rn::value_type...>,
39  
        void>;
39  
        void>;
40  
    static constexpr bool IsList =
40  
    static constexpr bool IsList =
41  
        mp11::mp_size<T>::value != 1;
41  
        mp11::mp_size<T>::value != 1;
42  

42  

43  
public:
43  
public:
44  
    using value_type =
44  
    using value_type =
45  
        mp11::mp_eval_if_c<IsList,
45  
        mp11::mp_eval_if_c<IsList,
46  
            T, mp11::mp_first, T>;
46  
            T, mp11::mp_first, T>;
47  

47  

48  
    constexpr
48  
    constexpr
49  
    tuple_rule_t(
49  
    tuple_rule_t(
50  
        R0 const& r0,
50  
        R0 const& r0,
51  
        Rn const&... rn) noexcept
51  
        Rn const&... rn) noexcept
52  
        : empty_value<
52  
        : empty_value<
53  
            detail::tuple<R0, Rn...>>(
53  
            detail::tuple<R0, Rn...>>(
54  
                empty_init,
54  
                empty_init,
55  
                r0, rn...)
55  
                r0, rn...)
56  
    {
56  
    {
57  
    }
57  
    }
58  

58  

59  
    system::result<value_type>
59  
    system::result<value_type>
60  
    parse(
60  
    parse(
61  
        char const*& it,
61  
        char const*& it,
62  
        char const* end) const;
62  
        char const* end) const;
63  

63  

64  
};
64  
};
65  
} // implementation_defined
65  
} // implementation_defined
66  

66  

67  
/** Match a series of rules in order
67  
/** Match a series of rules in order
68  

68  

69  
    This matches a series of rules in the
69  
    This matches a series of rules in the
70  
    order specified. Upon success the input
70  
    order specified. Upon success the input
71  
    is adjusted to point to the first
71  
    is adjusted to point to the first
72  
    unconsumed character. There is no
72  
    unconsumed character. There is no
73  
    implicit specification of linear white
73  
    implicit specification of linear white
74  
    space between each rule.
74  
    space between each rule.
75  

75  

76  
    @par Value Type
76  
    @par Value Type
77  
    @code
77  
    @code
78  
    using value_type = __see_below__;
78  
    using value_type = __see_below__;
79  
    @endcode
79  
    @endcode
80  

80  

81  
    The sequence rule usually returns a
81  
    The sequence rule usually returns a
82  
    `std::tuple` containing the the `value_type`
82  
    `std::tuple` containing the the `value_type`
83  
    of each corresponding rule in the sequence,
83  
    of each corresponding rule in the sequence,
84  
    except that `void` values are removed.
84  
    except that `void` values are removed.
85  
    However, if there is exactly one non-void
85  
    However, if there is exactly one non-void
86  
    value type `T`, then the sequence rule
86  
    value type `T`, then the sequence rule
87  
    returns `system::result<T>` instead of
87  
    returns `system::result<T>` instead of
88  
    `system::result<tuple<...>>`.
88  
    `system::result<tuple<...>>`.
89  

89  

90  
    @par Example
90  
    @par Example
91  
    Rules are used with the function @ref parse.
91  
    Rules are used with the function @ref parse.
92  
    @code
92  
    @code
93  
    system::result< std::tuple< unsigned char, unsigned char, unsigned char, unsigned char > > rv =
93  
    system::result< std::tuple< unsigned char, unsigned char, unsigned char, unsigned char > > rv =
94  
        parse( "192.168.0.1",
94  
        parse( "192.168.0.1",
95  
            tuple_rule(
95  
            tuple_rule(
96  
                dec_octet_rule,
96  
                dec_octet_rule,
97  
                squelch( delim_rule('.') ),
97  
                squelch( delim_rule('.') ),
98  
                dec_octet_rule,
98  
                dec_octet_rule,
99  
                squelch( delim_rule('.') ),
99  
                squelch( delim_rule('.') ),
100  
                dec_octet_rule,
100  
                dec_octet_rule,
101  
                squelch( delim_rule('.') ),
101  
                squelch( delim_rule('.') ),
102  
                dec_octet_rule ) );
102  
                dec_octet_rule ) );
103  
    @endcode
103  
    @endcode
104  

104  

105  
    @par BNF
105  
    @par BNF
106  
    @code
106  
    @code
107  
    sequence     = rule1 rule2 rule3...
107  
    sequence     = rule1 rule2 rule3...
108  
    @endcode
108  
    @endcode
109  

109  

110  
    @par Specification
110  
    @par Specification
111  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.1"
111  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.1"
112  
        >3.1.  Concatenation (rfc5234)</a>
112  
        >3.1.  Concatenation (rfc5234)</a>
113  

113  

114  
    @param r0 The first rule to match
114  
    @param r0 The first rule to match
115  
    @param rn A list of one or more rules to match
115  
    @param rn A list of one or more rules to match
116  
    @return The sequence rule
116  
    @return The sequence rule
117  

117  

118  
    @see
118  
    @see
119  
        @ref dec_octet_rule,
119  
        @ref dec_octet_rule,
120  
        @ref delim_rule,
120  
        @ref delim_rule,
121  
        @ref parse,
121  
        @ref parse,
122  
        @ref squelch.
122  
        @ref squelch.
123  
*/
123  
*/
124  
template<
124  
template<
125  
    BOOST_URL_CONSTRAINT(Rule) R0,
125  
    BOOST_URL_CONSTRAINT(Rule) R0,
126  
    BOOST_URL_CONSTRAINT(Rule)... Rn>
126  
    BOOST_URL_CONSTRAINT(Rule)... Rn>
127  
constexpr
127  
constexpr
128  
auto
128  
auto
129  
tuple_rule(
129  
tuple_rule(
130  
    R0 const& r0,
130  
    R0 const& r0,
131  
    Rn const&... rn) noexcept ->
131  
    Rn const&... rn) noexcept ->
132  
        implementation_defined::tuple_rule_t<
132  
        implementation_defined::tuple_rule_t<
133  
            R0, Rn...>
133  
            R0, Rn...>
134  
{
134  
{
135  
    BOOST_CORE_STATIC_ASSERT(
135  
    BOOST_CORE_STATIC_ASSERT(
136  
        mp11::mp_all<
136  
        mp11::mp_all<
137  
            is_rule<R0>,
137  
            is_rule<R0>,
138  
            is_rule<Rn>...>::value);
138  
            is_rule<Rn>...>::value);
139  
    return { r0, rn... };
139  
    return { r0, rn... };
140  
}
140  
}
141  

141  

142  
namespace implementation_defined {
142  
namespace implementation_defined {
143  

143  

144  
template<class Rule>
144  
template<class Rule>
145  
struct squelch_rule_t
145  
struct squelch_rule_t
146  
    : empty_value<Rule>
146  
    : empty_value<Rule>
147  
{
147  
{
148  
    using value_type = void;
148  
    using value_type = void;
149  

149  

150  
    constexpr
150  
    constexpr
151  
    squelch_rule_t(
151  
    squelch_rule_t(
152  
        Rule const& r) noexcept
152  
        Rule const& r) noexcept
153  
        : empty_value<Rule>(
153  
        : empty_value<Rule>(
154  
            empty_init, r)
154  
            empty_init, r)
155  
    {
155  
    {
156  
    }
156  
    }
157  

157  

158  
    system::result<value_type>
158  
    system::result<value_type>
159  
    parse(
159  
    parse(
160  
        char const*& it,
160  
        char const*& it,
161  
        char const* end) const
161  
        char const* end) const
162  
    {
162  
    {
163  
        auto rv = this->get().parse(it, end);
163  
        auto rv = this->get().parse(it, end);
164  
        if(rv.error())
164  
        if(rv.error())
165  
            return rv.error();
165  
            return rv.error();
166  
        return {}; // void
166  
        return {}; // void
167  
    }
167  
    }
168  
};
168  
};
169  

169  

170  
} // implementation_defined
170  
} // implementation_defined
171  

171  

172  
/** Squelch the value of a rule
172  
/** Squelch the value of a rule
173  

173  

174  
    This function returns a new rule which
174  
    This function returns a new rule which
175  
    matches the specified rule, and converts
175  
    matches the specified rule, and converts
176  
    its value type to `void`. This is useful
176  
    its value type to `void`. This is useful
177  
    for matching delimiters in a grammar,
177  
    for matching delimiters in a grammar,
178  
    where the value for the delimiter is not
178  
    where the value for the delimiter is not
179  
    needed.
179  
    needed.
180  

180  

181  
    @par Value Type
181  
    @par Value Type
182  
    @code
182  
    @code
183  
    using value_type = void;
183  
    using value_type = void;
184  
    @endcode
184  
    @endcode
185  

185  

186  
    @par Example 1
186  
    @par Example 1
187  
    With `squelch`:
187  
    With `squelch`:
188  
    @code
188  
    @code
189  
    system::result< std::tuple< decode_view, core::string_view > > rv = parse(
189  
    system::result< std::tuple< decode_view, core::string_view > > rv = parse(
190  
        "www.example.com:443",
190  
        "www.example.com:443",
191  
        tuple_rule(
191  
        tuple_rule(
192  
            pct_encoded_rule(unreserved_chars + '-' + '.'),
192  
            pct_encoded_rule(unreserved_chars + '-' + '.'),
193  
            squelch( delim_rule( ':' ) ),
193  
            squelch( delim_rule( ':' ) ),
194  
            token_rule( digit_chars ) ) );
194  
            token_rule( digit_chars ) ) );
195  
    @endcode
195  
    @endcode
196  

196  

197  
    @par Example 2
197  
    @par Example 2
198  
    Without `squelch`:
198  
    Without `squelch`:
199  
    @code
199  
    @code
200  
    system::result< std::tuple< decode_view, core::string_view, core::string_view > > rv = parse(
200  
    system::result< std::tuple< decode_view, core::string_view, core::string_view > > rv = parse(
201  
        "www.example.com:443",
201  
        "www.example.com:443",
202  
        tuple_rule(
202  
        tuple_rule(
203  
            pct_encoded_rule(unreserved_chars + '-' + '.'),
203  
            pct_encoded_rule(unreserved_chars + '-' + '.'),
204  
            delim_rule( ':' ),
204  
            delim_rule( ':' ),
205  
            token_rule( digit_chars ) ) );
205  
            token_rule( digit_chars ) ) );
206  
    @endcode
206  
    @endcode
207  

207  

208  
    @param r The rule to squelch
208  
    @param r The rule to squelch
209  
    @return The squelched rule
209  
    @return The squelched rule
210  

210  

211  
    @see
211  
    @see
212  
        @ref delim_rule,
212  
        @ref delim_rule,
213  
        @ref digit_chars,
213  
        @ref digit_chars,
214  
        @ref parse,
214  
        @ref parse,
215  
        @ref tuple_rule,
215  
        @ref tuple_rule,
216  
        @ref token_rule,
216  
        @ref token_rule,
217  
        @ref decode_view,
217  
        @ref decode_view,
218  
        @ref pct_encoded_rule,
218  
        @ref pct_encoded_rule,
219  
        @ref unreserved_chars.
219  
        @ref unreserved_chars.
220  
*/
220  
*/
221  
template<BOOST_URL_CONSTRAINT(Rule) R>
221  
template<BOOST_URL_CONSTRAINT(Rule) R>
222  
constexpr
222  
constexpr
223  
BOOST_URL_IMPLEMENTATION_DEFINED(implementation_defined::squelch_rule_t<R>)
223  
BOOST_URL_IMPLEMENTATION_DEFINED(implementation_defined::squelch_rule_t<R>)
224  
squelch( R const& r ) noexcept
224  
squelch( R const& r ) noexcept
225  
{
225  
{
226  
    BOOST_CORE_STATIC_ASSERT(is_rule<R>::value);
226  
    BOOST_CORE_STATIC_ASSERT(is_rule<R>::value);
227  
    return { r };
227  
    return { r };
228  
}
228  
}
229  

229  

230  
} // grammar
230  
} // grammar
231  
} // urls
231  
} // urls
232  
} // boost
232  
} // boost
233  

233  

234  
#include <boost/url/grammar/impl/tuple_rule.hpp>
234  
#include <boost/url/grammar/impl/tuple_rule.hpp>
235  

235  

236  
#endif
236  
#endif