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

9  

10  
#ifndef BOOST_CAPY_EX_IMMEDIATE_HPP
10  
#ifndef BOOST_CAPY_EX_IMMEDIATE_HPP
11  
#define BOOST_CAPY_EX_IMMEDIATE_HPP
11  
#define BOOST_CAPY_EX_IMMEDIATE_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/ex/io_env.hpp>
14  
#include <boost/capy/ex/io_env.hpp>
15  
#include <boost/capy/io_result.hpp>
15  
#include <boost/capy/io_result.hpp>
16  

16  

17  
#include <coroutine>
17  
#include <coroutine>
18  
#include <stop_token>
18  
#include <stop_token>
19  
#include <utility>
19  
#include <utility>
20  

20  

21  
namespace boost {
21  
namespace boost {
22  
namespace capy {
22  
namespace capy {
23  

23  

24  
/** An awaitable that completes immediately with a value.
24  
/** An awaitable that completes immediately with a value.
25  

25  

26  
    This awaitable wraps a synchronous result so it can be used in
26  
    This awaitable wraps a synchronous result so it can be used in
27  
    contexts that require an awaitable type. It never suspends - 
27  
    contexts that require an awaitable type. It never suspends - 
28  
    `await_ready()` always returns `true`, so the coroutine machinery
28  
    `await_ready()` always returns `true`, so the coroutine machinery
29  
    is optimized away by the compiler.
29  
    is optimized away by the compiler.
30  

30  

31  
    Use this to adapt synchronous operations to satisfy async concepts
31  
    Use this to adapt synchronous operations to satisfy async concepts
32  
    like @ref IoAwaitable without the overhead of a full coroutine frame.
32  
    like @ref IoAwaitable without the overhead of a full coroutine frame.
33  

33  

34  
    @tparam T The result type to wrap.
34  
    @tparam T The result type to wrap.
35  

35  

36  
    @par Example
36  
    @par Example
37  
    @code
37  
    @code
38  
    // Wrap a sync operation as an awaitable
38  
    // Wrap a sync operation as an awaitable
39  
    immediate<int> get_value()
39  
    immediate<int> get_value()
40  
    {
40  
    {
41  
        return {42};
41  
        return {42};
42  
    }
42  
    }
43  

43  

44  
    task<void> example()
44  
    task<void> example()
45  
    {
45  
    {
46  
        int x = co_await get_value();  // No suspension, returns 42
46  
        int x = co_await get_value();  // No suspension, returns 42
47  
    }
47  
    }
48  
    @endcode
48  
    @endcode
49  

49  

50  
    @par Satisfying WriteSink with sync operations
50  
    @par Satisfying WriteSink with sync operations
51  
    @code
51  
    @code
52  
    struct my_sync_sink
52  
    struct my_sync_sink
53  
    {
53  
    {
54  
        template<ConstBufferSequence CB>
54  
        template<ConstBufferSequence CB>
55  
        immediate<io_result<std::size_t>>
55  
        immediate<io_result<std::size_t>>
56  
        write(CB buffers)
56  
        write(CB buffers)
57  
        {
57  
        {
58  
            auto n = process_sync(buffers);
58  
            auto n = process_sync(buffers);
59  
            return {{{}, n}};
59  
            return {{{}, n}};
60  
        }
60  
        }
61  

61  

62  
        immediate<io_result<>>
62  
        immediate<io_result<>>
63  
        write_eof()
63  
        write_eof()
64  
        {
64  
        {
65  
            return {{}};
65  
            return {{}};
66  
        }
66  
        }
67  
    };
67  
    };
68  
    @endcode
68  
    @endcode
69  

69  

70  
    @see ready, io_result
70  
    @see ready, io_result
71  
*/
71  
*/
72  
template<class T>
72  
template<class T>
73  
struct immediate
73  
struct immediate
74  
{
74  
{
75  
    /** The wrapped value. */
75  
    /** The wrapped value. */
76  
    T value_;
76  
    T value_;
77  

77  

78  
    /** Always returns true - this awaitable never suspends. */
78  
    /** Always returns true - this awaitable never suspends. */
79  
    constexpr bool
79  
    constexpr bool
80  
    await_ready() const noexcept
80  
    await_ready() const noexcept
81  
    {
81  
    {
82  
        return true;
82  
        return true;
83  
    }
83  
    }
84  

84  

85  
    /** IoAwaitable protocol overload.
85  
    /** IoAwaitable protocol overload.
86  

86  

87  
        This overload allows `immediate` to satisfy the @ref IoAwaitable
87  
        This overload allows `immediate` to satisfy the @ref IoAwaitable
88  
        concept. Since the result is already available, the environment
88  
        concept. Since the result is already available, the environment
89  
        is unused.
89  
        is unused.
90  

90  

91  
        @param h The coroutine handle (unused).
91  
        @param h The coroutine handle (unused).
92  
        @param env The execution environment (unused).
92  
        @param env The execution environment (unused).
93  

93  

94  
        @return `std::noop_coroutine()` to indicate no suspension.
94  
        @return `std::noop_coroutine()` to indicate no suspension.
95  
    */
95  
    */
96  
    std::coroutine_handle<>
96  
    std::coroutine_handle<>
97  
    await_suspend(
97  
    await_suspend(
98  
        std::coroutine_handle<> h,
98  
        std::coroutine_handle<> h,
99  
        io_env const* env) const noexcept
99  
        io_env const* env) const noexcept
100  
    {
100  
    {
101  
        (void)h;
101  
        (void)h;
102  
        (void)env;
102  
        (void)env;
103  
        return std::noop_coroutine();
103  
        return std::noop_coroutine();
104  
    }
104  
    }
105  

105  

106  
    /** Returns the wrapped value.
106  
    /** Returns the wrapped value.
107  

107  

108  
        @return The stored value, moved if non-const.
108  
        @return The stored value, moved if non-const.
109  
    */
109  
    */
110  
    constexpr T
110  
    constexpr T
111  
    await_resume() noexcept
111  
    await_resume() noexcept
112  
    {
112  
    {
113  
        return std::move(value_);
113  
        return std::move(value_);
114  
    }
114  
    }
115  

115  

116  
    /** Returns the wrapped value (const overload). */
116  
    /** Returns the wrapped value (const overload). */
117  
    constexpr T const&
117  
    constexpr T const&
118  
    await_resume() const noexcept
118  
    await_resume() const noexcept
119  
    {
119  
    {
120  
        return value_;
120  
        return value_;
121  
    }
121  
    }
122  
};
122  
};
123  

123  

124  
/** Create an immediate awaitable for a successful io_result.
124  
/** Create an immediate awaitable for a successful io_result.
125  

125  

126  
    This helper creates an @ref immediate wrapping an @ref io_result
126  
    This helper creates an @ref immediate wrapping an @ref io_result
127  
    with no error and the provided values.
127  
    with no error and the provided values.
128  

128  

129  
    @par Example
129  
    @par Example
130  
    @code
130  
    @code
131  
    immediate<io_result<std::size_t>>
131  
    immediate<io_result<std::size_t>>
132  
    write(const_buffer buf)
132  
    write(const_buffer buf)
133  
    {
133  
    {
134  
        auto n = write_sync(buf);
134  
        auto n = write_sync(buf);
135  
        return ready(n);  // success with n bytes
135  
        return ready(n);  // success with n bytes
136  
    }
136  
    }
137  

137  

138  
    immediate<io_result<>>
138  
    immediate<io_result<>>
139  
    connect()
139  
    connect()
140  
    {
140  
    {
141  
        connect_sync();
141  
        connect_sync();
142  
        return ready();  // void success
142  
        return ready();  // void success
143  
    }
143  
    }
144  
    @endcode
144  
    @endcode
145  

145  

146  
    @return An immediate awaitable containing a successful io_result.
146  
    @return An immediate awaitable containing a successful io_result.
147  

147  

148  
    @see immediate, io_result
148  
    @see immediate, io_result
149  
*/
149  
*/
150  
inline
150  
inline
151  
immediate<io_result<>>
151  
immediate<io_result<>>
152  
ready() noexcept
152  
ready() noexcept
153  
{
153  
{
154  
    return {{}};
154  
    return {{}};
155  
}
155  
}
156  

156  

157  
/** Create an immediate awaitable for a successful io_result with one value.
157  
/** Create an immediate awaitable for a successful io_result with one value.
158  

158  

159  
    @param t1 The result value.
159  
    @param t1 The result value.
160  

160  

161  
    @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
161  
    @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
162  
*/
162  
*/
163  
template<class T1>
163  
template<class T1>
164  
immediate<io_result<T1>>
164  
immediate<io_result<T1>>
165  
ready(T1 t1)
165  
ready(T1 t1)
166  
{
166  
{
167  
    return {{{}, std::move(t1)}};
167  
    return {{{}, std::move(t1)}};
168  
}
168  
}
169  

169  

170  
/** Create an immediate awaitable for a successful io_result with two values.
170  
/** Create an immediate awaitable for a successful io_result with two values.
171  

171  

172  
    @param t1 The first result value.
172  
    @param t1 The first result value.
173  
    @param t2 The second result value.
173  
    @param t2 The second result value.
174  

174  

175  
    @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
175  
    @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
176  
*/
176  
*/
177  
template<class T1, class T2>
177  
template<class T1, class T2>
178  
immediate<io_result<T1, T2>>
178  
immediate<io_result<T1, T2>>
179  
ready(T1 t1, T2 t2)
179  
ready(T1 t1, T2 t2)
180  
{
180  
{
181  
    return {{{}, std::move(t1), std::move(t2)}};
181  
    return {{{}, std::move(t1), std::move(t2)}};
182  
}
182  
}
183  

183  

184  
/** Create an immediate awaitable for a successful io_result with three values.
184  
/** Create an immediate awaitable for a successful io_result with three values.
185  

185  

186  
    @param t1 The first result value.
186  
    @param t1 The first result value.
187  
    @param t2 The second result value.
187  
    @param t2 The second result value.
188  
    @param t3 The third result value.
188  
    @param t3 The third result value.
189  

189  

190  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
190  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
191  
*/
191  
*/
192  
template<class T1, class T2, class T3>
192  
template<class T1, class T2, class T3>
193  
immediate<io_result<T1, T2, T3>>
193  
immediate<io_result<T1, T2, T3>>
194  
ready(T1 t1, T2 t2, T3 t3)
194  
ready(T1 t1, T2 t2, T3 t3)
195  
{
195  
{
196  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
196  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
197  
}
197  
}
198  

198  

199  
/** Create an immediate awaitable for a failed io_result.
199  
/** Create an immediate awaitable for a failed io_result.
200  

200  

201  
    This helper creates an @ref immediate wrapping an @ref io_result
201  
    This helper creates an @ref immediate wrapping an @ref io_result
202  
    with an error code.
202  
    with an error code.
203  

203  

204  
    @par Example
204  
    @par Example
205  
    @code
205  
    @code
206  
    immediate<io_result<std::size_t>>
206  
    immediate<io_result<std::size_t>>
207  
    write(const_buffer buf)
207  
    write(const_buffer buf)
208  
    {
208  
    {
209  
        auto ec = write_sync(buf);
209  
        auto ec = write_sync(buf);
210  
        if(ec)
210  
        if(ec)
211  
            return ready(ec, std::size_t{0});
211  
            return ready(ec, std::size_t{0});
212  
        return ready(buffer_size(buf));
212  
        return ready(buffer_size(buf));
213  
    }
213  
    }
214  
    @endcode
214  
    @endcode
215  

215  

216  
    @param ec The error code.
216  
    @param ec The error code.
217  

217  

218  
    @return An immediate awaitable containing a failed io_result.
218  
    @return An immediate awaitable containing a failed io_result.
219  

219  

220  
    @see immediate, io_result
220  
    @see immediate, io_result
221  
*/
221  
*/
222  
inline
222  
inline
223  
immediate<io_result<>>
223  
immediate<io_result<>>
224  
ready(std::error_code ec) noexcept
224  
ready(std::error_code ec) noexcept
225  
{
225  
{
226  
    return {{ec}};
226  
    return {{ec}};
227  
}
227  
}
228  

228  

229  
/** Create an immediate awaitable for an io_result with error and one value.
229  
/** Create an immediate awaitable for an io_result with error and one value.
230  

230  

231  
    @param ec The error code.
231  
    @param ec The error code.
232  
    @param t1 The result value.
232  
    @param t1 The result value.
233  

233  

234  
    @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
234  
    @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
235  
*/
235  
*/
236  
template<class T1>
236  
template<class T1>
237  
immediate<io_result<T1>>
237  
immediate<io_result<T1>>
238  
ready(std::error_code ec, T1 t1)
238  
ready(std::error_code ec, T1 t1)
239  
{
239  
{
240  
    return {{ec, std::move(t1)}};
240  
    return {{ec, std::move(t1)}};
241  
}
241  
}
242  

242  

243  
/** Create an immediate awaitable for an io_result with error and two values.
243  
/** Create an immediate awaitable for an io_result with error and two values.
244  

244  

245  
    @param ec The error code.
245  
    @param ec The error code.
246  
    @param t1 The first result value.
246  
    @param t1 The first result value.
247  
    @param t2 The second result value.
247  
    @param t2 The second result value.
248  

248  

249  
    @return An immediate awaitable containing `io_result<T1,T2>{ec, t1, t2}`.
249  
    @return An immediate awaitable containing `io_result<T1,T2>{ec, t1, t2}`.
250  
*/
250  
*/
251  
template<class T1, class T2>
251  
template<class T1, class T2>
252  
immediate<io_result<T1, T2>>
252  
immediate<io_result<T1, T2>>
253  
ready(std::error_code ec, T1 t1, T2 t2)
253  
ready(std::error_code ec, T1 t1, T2 t2)
254  
{
254  
{
255  
    return {{ec, std::move(t1), std::move(t2)}};
255  
    return {{ec, std::move(t1), std::move(t2)}};
256  
}
256  
}
257  

257  

258  
/** Create an immediate awaitable for an io_result with error and three values.
258  
/** Create an immediate awaitable for an io_result with error and three values.
259  

259  

260  
    @param ec The error code.
260  
    @param ec The error code.
261  
    @param t1 The first result value.
261  
    @param t1 The first result value.
262  
    @param t2 The second result value.
262  
    @param t2 The second result value.
263  
    @param t3 The third result value.
263  
    @param t3 The third result value.
264  

264  

265  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
265  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
266  
*/
266  
*/
267  
template<class T1, class T2, class T3>
267  
template<class T1, class T2, class T3>
268  
immediate<io_result<T1, T2, T3>>
268  
immediate<io_result<T1, T2, T3>>
269  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
269  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
270  
{
270  
{
271  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
271  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
272  
}
272  
}
273  

273  

274  
} // namespace capy
274  
} // namespace capy
275  
} // namespace boost
275  
} // namespace boost
276  

276  

277  
#endif
277  
#endif