1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.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/cppalliance/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_HTTP_RFC_IMPL_LIST_RULE_HPP
10  
#ifndef BOOST_HTTP_RFC_IMPL_LIST_RULE_HPP
11  
#define BOOST_HTTP_RFC_IMPL_LIST_RULE_HPP
11  
#define BOOST_HTTP_RFC_IMPL_LIST_RULE_HPP
12  

12  

13  
#include <boost/http/rfc/detail/ws.hpp>
13  
#include <boost/http/rfc/detail/ws.hpp>
14  

14  

15  
#include <boost/url/grammar/parse.hpp>
15  
#include <boost/url/grammar/parse.hpp>
16  
#include <boost/url/grammar/charset.hpp>
16  
#include <boost/url/grammar/charset.hpp>
17  
#include <boost/url/grammar/range_rule.hpp>
17  
#include <boost/url/grammar/range_rule.hpp>
18  
#include <boost/core/empty_value.hpp>
18  
#include <boost/core/empty_value.hpp>
19  

19  

20  
namespace boost {
20  
namespace boost {
21  
namespace http {
21  
namespace http {
22  

22  

23  
namespace detail {
23  
namespace detail {
24  

24  

25  
/*  Peter:
25  
/*  Peter:
26  

26  

27  
    So, to put everything together, this is what I propose
27  
    So, to put everything together, this is what I propose
28  

28  

29  
    - make range2_rule that takes first and next with
29  
    - make range2_rule that takes first and next with
30  
      value types of optional<E> rather than E like the current rule
30  
      value types of optional<E> rather than E like the current rule
31  
    - make variant_rule produce an optional<X> when otherwise
31  
    - make variant_rule produce an optional<X> when otherwise
32  
      the value type would have been variant<void, void, X, void>
32  
      the value type would have been variant<void, void, X, void>
33  
    - add operators for combining the rules so that one can
33  
    - add operators for combining the rules so that one can
34  
      write *( OWS >> !literal(",") >> -( OWS >> element ) )
34  
      write *( OWS >> !literal(",") >> -( OWS >> element ) )
35  
    - profit
35  
    - profit
36  
*/
36  
*/
37  

37  

38  
// *( OWS "," )
38  
// *( OWS "," )
39  
struct ows_comma_t
39  
struct ows_comma_t
40  
{
40  
{
41  
    using value_type = void;
41  
    using value_type = void;
42  

42  

43  
    auto
43  
    auto
44  
    parse(
44  
    parse(
45  
        char const*& it,
45  
        char const*& it,
46  
        char const* end) const noexcept ->
46  
        char const* end) const noexcept ->
47  
            system::result<value_type>
47  
            system::result<value_type>
48  
    {
48  
    {
49  
        auto it1 = it;
49  
        auto it1 = it;
50  
        while(it != end)
50  
        while(it != end)
51  
        {
51  
        {
52  
            // SP / HT
52  
            // SP / HT
53  
            if( *it == ' ' ||
53  
            if( *it == ' ' ||
54  
                *it == '\t')
54  
                *it == '\t')
55  
            {
55  
            {
56  
                ++it;
56  
                ++it;
57  
                continue;
57  
                continue;
58  
            }
58  
            }
59  
            if(*it != ',')
59  
            if(*it != ',')
60  
                break;
60  
                break;
61  
            // ","
61  
            // ","
62  
            it1 = ++it;
62  
            it1 = ++it;
63  
        }
63  
        }
64  
        it = it1;
64  
        it = it1;
65  
        return {};
65  
        return {};
66  
    }
66  
    }
67  
};
67  
};
68  

68  

69  
constexpr ows_comma_t ows_comma{};
69  
constexpr ows_comma_t ows_comma{};
70  

70  

71  
} // detail
71  
} // detail
72  

72  

73  
/*
73  
/*
74  
    #element    => [ ( "," / element ) *( OWS "," [ OWS element ] ) ]
74  
    #element    => [ ( "," / element ) *( OWS "," [ OWS element ] ) ]
75  

75  

76  
    #element    => first *next
76  
    #element    => first *next
77  
    first       => [ element / ( "," *( OWS "," ) [ OWS element ] ) ]
77  
    first       => [ element / ( "," *( OWS "," ) [ OWS element ] ) ]
78  
    next        => "" / ( 1*( OWS "," ) [ OWS element ] )
78  
    next        => "" / ( 1*( OWS "," ) [ OWS element ] )
79  
*/
79  
*/
80  

80  

81  
namespace implementation_defined {
81  
namespace implementation_defined {
82  
template<class Rule>
82  
template<class Rule>
83  
struct list_rule_t<Rule>::
83  
struct list_rule_t<Rule>::
84  
    first_rule : empty_value<Rule>
84  
    first_rule : empty_value<Rule>
85  
{
85  
{
86  
    using value_type =
86  
    using value_type =
87  
        typename Rule::value_type;
87  
        typename Rule::value_type;
88  

88  

89  
    constexpr
89  
    constexpr
90  
    explicit
90  
    explicit
91  
    first_rule(
91  
    first_rule(
92  
        Rule const& r) noexcept
92  
        Rule const& r) noexcept
93  
        : empty_value<Rule>(
93  
        : empty_value<Rule>(
94  
            empty_init, r)
94  
            empty_init, r)
95  
    {
95  
    {
96  
    }
96  
    }
97  

97  

98  
    auto
98  
    auto
99  
    parse(
99  
    parse(
100  
        char const*& it,
100  
        char const*& it,
101  
        char const* end) const ->
101  
        char const* end) const ->
102  
            system::result<value_type>
102  
            system::result<value_type>
103  
    {
103  
    {
104  
    //  first       => [ element / ( "," *( OWS "," ) [ OWS element ] ) ]
104  
    //  first       => [ element / ( "," *( OWS "," ) [ OWS element ] ) ]
105  

105  

106  
        if(it == end)
106  
        if(it == end)
107  
            return grammar::error::end_of_range;
107  
            return grammar::error::end_of_range;
108  
        {
108  
        {
109  
            // element
109  
            // element
110  
            auto it0 = it;
110  
            auto it0 = it;
111  
            auto rv = this->get().parse(it, end);
111  
            auto rv = this->get().parse(it, end);
112  
            if(rv)
112  
            if(rv)
113  
                return std::move(*rv);
113  
                return std::move(*rv);
114  
            it = it0;
114  
            it = it0;
115  
        }
115  
        }
116  
        // ","
116  
        // ","
117  
        if(*it != ',')
117  
        if(*it != ',')
118  
            return grammar::error::end_of_range;
118  
            return grammar::error::end_of_range;
119  
        ++it;
119  
        ++it;
120  
        // *( OWS "," )
120  
        // *( OWS "," )
121  
        detail::ows_comma.parse(it, end);
121  
        detail::ows_comma.parse(it, end);
122  
        auto it1 = it;
122  
        auto it1 = it;
123  
        // OWS
123  
        // OWS
124  
        it = grammar::find_if_not(
124  
        it = grammar::find_if_not(
125  
            it, end, detail::ws);
125  
            it, end, detail::ws);
126  
        // element
126  
        // element
127  
        auto rv = this->get().parse(it, end);
127  
        auto rv = this->get().parse(it, end);
128  
        if(rv)
128  
        if(rv)
129  
            return std::move(*rv);
129  
            return std::move(*rv);
130  
        it = it1;
130  
        it = it1;
131  
        return grammar::error::end_of_range;
131  
        return grammar::error::end_of_range;
132  
    }
132  
    }
133  
};
133  
};
134  

134  

135  
template<class Rule>
135  
template<class Rule>
136  
struct list_rule_t<Rule>::
136  
struct list_rule_t<Rule>::
137  
    next_rule : empty_value<Rule>
137  
    next_rule : empty_value<Rule>
138  
{
138  
{
139  
    using value_type =
139  
    using value_type =
140  
        typename Rule::value_type;
140  
        typename Rule::value_type;
141  

141  

142  
    constexpr
142  
    constexpr
143  
    explicit
143  
    explicit
144  
    next_rule(
144  
    next_rule(
145  
        Rule const& r) noexcept
145  
        Rule const& r) noexcept
146  
        : empty_value<Rule>(
146  
        : empty_value<Rule>(
147  
            empty_init, r)
147  
            empty_init, r)
148  
    {
148  
    {
149  
    }
149  
    }
150  

150  

151  
    auto
151  
    auto
152  
    parse(
152  
    parse(
153  
        char const*& it,
153  
        char const*& it,
154  
        char const* end) const ->
154  
        char const* end) const ->
155  
            system::result<value_type>
155  
            system::result<value_type>
156  
    {
156  
    {
157  
    //  next        => "" / ( 1*( OWS "," ) [ OWS element ] )
157  
    //  next        => "" / ( 1*( OWS "," ) [ OWS element ] )
158  

158  

159  
        // ""
159  
        // ""
160  
        if(it == end)
160  
        if(it == end)
161  
            return grammar::error::end_of_range;
161  
            return grammar::error::end_of_range;
162  

162  

163  
        // 1*( OWS "," )
163  
        // 1*( OWS "," )
164  
        {
164  
        {
165  
            auto it0 = it;
165  
            auto it0 = it;
166  
            detail::ows_comma.parse(it, end);
166  
            detail::ows_comma.parse(it, end);
167  
            if(it == it0)
167  
            if(it == it0)
168  
                return grammar::error::end_of_range;
168  
                return grammar::error::end_of_range;
169  
        }
169  
        }
170  
        auto it1 = it;
170  
        auto it1 = it;
171  
        // OWS
171  
        // OWS
172  
        it = grammar::find_if_not(
172  
        it = grammar::find_if_not(
173  
            it, end, detail::ws);
173  
            it, end, detail::ws);
174  
        auto rv = this->get().parse(it, end);
174  
        auto rv = this->get().parse(it, end);
175  
        if(rv)
175  
        if(rv)
176  
            return std::move(*rv);
176  
            return std::move(*rv);
177  
        it = it1;
177  
        it = it1;
178  
        return grammar::error::end_of_range;
178  
        return grammar::error::end_of_range;
179  
    }
179  
    }
180  
};
180  
};
181  

181  

182  
template<class Rule>
182  
template<class Rule>
183  
auto
183  
auto
184  
list_rule_t<Rule>::
184  
list_rule_t<Rule>::
185  
parse(
185  
parse(
186  
    char const*& it,
186  
    char const*& it,
187  
    char const* end) const ->
187  
    char const* end) const ->
188  
        system::result<value_type>
188  
        system::result<value_type>
189  
{
189  
{
190  
    return grammar::parse(it, end,
190  
    return grammar::parse(it, end,
191  
        grammar::range_rule(
191  
        grammar::range_rule(
192  
            first_rule{this->get()},
192  
            first_rule{this->get()},
193  
            next_rule{this->get()},
193  
            next_rule{this->get()},
194  
                n_, m_));
194  
                n_, m_));
195  
}
195  
}
196  
} // implementation_defined
196  
} // implementation_defined
197  

197  

198  
} // http
198  
} // http
199  
} // boost
199  
} // boost
200  

200  

201  
#endif
201  
#endif