Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 38 additions & 73 deletions .cursor/rules/portable-headers.mdc
Original file line number Diff line number Diff line change
@@ -1,116 +1,81 @@
---
description: No non-portable header includes in public headers
description: No non-portable header includes in type-erased public headers
alwaysApply: false
---
# Portable Headers Rule

**All headers in `include/boost/corosio/` (including all subdirectories) MUST NOT include platform-specific headers.**
**Headers in `include/boost/corosio/` and `include/boost/corosio/detail/` MUST NOT include platform-specific headers.**

## Scope

**Public headers**: ANY header file in `include/boost/corosio/` or any of its subdirectories.
The `native/` subtree (`include/boost/corosio/native/`) is exempt — it is the direct/native API that deliberately exposes platform types.

Examples:
- `include/boost/corosio/endpoint.hpp`
- `include/boost/corosio/detail/config.hpp`
- `include/boost/corosio/concept/...`
## Scope

The entire `include/` tree is considered public API. This includes `detail/`, `concept/`, and any other subdirectories.
**Type-erased headers** (platform includes FORBIDDEN):
- `include/boost/corosio/*.hpp`
- `include/boost/corosio/detail/*.hpp`
- `include/boost/corosio/concept/*.hpp`

## Prohibited Headers
**Native/direct headers** (platform includes ALLOWED):
- `include/boost/corosio/native/*.hpp`
- `include/boost/corosio/native/detail/**/*.hpp`

The following types of headers are **FORBIDDEN** in public headers:
## Prohibited Headers (in type-erased scope)

### Windows-specific
- `<windows.h>`
- `<WinSock2.h>`
- `<Ws2tcpip.h>`
- `<MSWSock.h>`
- `<windows.h>`, `<WinSock2.h>`, `<Ws2tcpip.h>`, `<MSWSock.h>`
- Any other Windows SDK headers

### Unix/POSIX-specific
- `<sys/socket.h>`
- `<netinet/in.h>`
- `<arpa/inet.h>`
- `<unistd.h>`
- `<sys/types.h>`
- `<sys/socket.h>`, `<netinet/in.h>`, `<arpa/inet.h>`, `<unistd.h>`, `<sys/types.h>`
- `<errno.h>` when used for platform-specific constants (e.g., `ECANCELED`)
- Any other POSIX/Unix-specific headers

### Platform-specific macros and types
- Any macros or types that require platform-specific headers
- Platform-specific constants (e.g., `AF_INET`, `INADDR_ANY`)
- Constants like `AF_INET`, `INADDR_ANY`, `ECANCELED`, `ERROR_OPERATION_ABORTED`
- Types like `sockaddr_in`, `sockaddr_in6`, `sockaddr_storage`, `SOCKET`

## Allowed Locations
## Allowed Locations for Platform-Specific Code

Platform-specific code is **ONLY** allowed in:

- Implementation files in `src/`
- Platform abstraction layers in `src/`
- `include/boost/corosio/native/` and `include/boost/corosio/native/detail/` (direct API)
- Implementation files in `src/` (compilation firewall)

## Rationale

1. **Portability**: Public headers should compile on any platform without platform-specific dependencies
2. **Maintainability**: Platform-specific code should be isolated in implementation files
3. **User Experience**: Users should not be exposed to platform-specific types or headers
4. **Clean API**: The public API should be platform-agnostic
The library has two API layers:
1. **Type-erased** (`corosio/` and `corosio/detail/`): portable, no platform headers leak to users
2. **Native/direct** (`corosio/native/`): opt-in, exposes platform types for zero-overhead access

## Examples

### Bad (in public header)
### Bad (platform header in type-erased scope)
```cpp
// include/boost/corosio/endpoint.hpp
#ifdef _WIN32
#include <WinSock2.h>
#else
// include/boost/corosio/detail/endpoint_convert.hpp ← WRONG location
#include <sys/socket.h>
#include <netinet/in.h>
#endif
```

class endpoint {
sockaddr_in to_sockaddr_in() const; // Platform-specific type
};
### Good (platform header in native scope)
```cpp
// include/boost/corosio/native/detail/endpoint_convert.hpp ← correct
#include <sys/socket.h>
#include <netinet/in.h>
```

### Good (in public header)
### Good (type-erased public header)
```cpp
// include/boost/corosio/endpoint.hpp
#include <boost/url/ipv4_address.hpp>
#include <cstdint>

class endpoint {
urls::ipv4_address v4_address() const noexcept;
ipv4_address v4_address() const noexcept;
std::uint16_t port() const noexcept;
};
```

### ✅ Good (in implementation file)
```cpp
// src/src/detail/endpoint_convert.hpp
#ifdef _WIN32
#include <WinSock2.h>
#else
#include <netinet/in.h>
#endif

#include <boost/corosio/endpoint.hpp>

namespace boost {
namespace corosio {
namespace detail {

sockaddr_in to_sockaddr_in(endpoint const& ep) {
// Platform-specific conversion logic
}

} // namespace detail
} // namespace corosio
} // namespace boost
```

## Enforcement

When adding or modifying public headers:
When adding or modifying headers in the type-erased scope:

1. Check all `#include` directives
2. Ensure no platform-specific headers are included
3. Move any platform-specific code to `src/` implementation files
4. Use platform abstraction utilities in `src/src/detail/` for conversions
1. Check all `#include` directives for platform-specific headers
2. If platform types are needed, the header belongs in `native/detail/`
3. Type-erased code reaches platform APIs only through `src/` compiled translation units
2 changes: 1 addition & 1 deletion doc/design/physical-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public:
virtual std::coroutine_handle<> read_some(
std::coroutine_handle<>,
capy::executor_ref,
io_buffer_param,
buffer_param,
std::stop_token,
std::error_code*,
std::size_t* ) = 0;
Expand Down
8 changes: 4 additions & 4 deletions doc/modules/ROOT/pages/4.guide/4n.buffers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,15 @@ consuming.consume(n); // Advance by bytes read

This is used internally by `read()` and `write()` but can be used directly.

== io_buffer_param
== buffer_param

The `io_buffer_param` class type-erases buffer sequences:
The `buffer_param` class type-erases buffer sequences:

[source,cpp]
----
#include <boost/corosio/io_buffer_param.hpp>
#include <boost/corosio/io/buffer_param.hpp>

void accept_any_buffer(corosio::io_buffer_param buffers)
void accept_any_buffer(corosio::buffer_param buffers)
{
capy::mutable_buffer temp[8];
std::size_t n = buffers.copy_to(temp, 8);
Expand Down
1 change: 0 additions & 1 deletion include/boost/corosio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include <boost/corosio/backend.hpp>
#include <boost/corosio/cancel.hpp>
#include <boost/corosio/endpoint.hpp>
#include <boost/corosio/io_buffer_param.hpp>
#include <boost/corosio/io_context.hpp>
#include <boost/corosio/ipv4_address.hpp>
#include <boost/corosio/ipv6_address.hpp>
Expand Down
34 changes: 12 additions & 22 deletions include/boost/corosio/cancel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,10 @@ namespace boost::corosio {

@see cancel_after
*/
auto cancel_at(
capy::IoAwaitable auto&& op,
timer& t,
timer::time_point deadline)
auto
cancel_at(capy::IoAwaitable auto&& op, timer& t, timer::time_point deadline)
{
return detail::cancel_at_awaitable<
std::decay_t<decltype(op)>, timer>(
return detail::cancel_at_awaitable<std::decay_t<decltype(op)>, timer>(
std::forward<decltype(op)>(op), t, deadline);
}

Expand Down Expand Up @@ -110,14 +107,11 @@ auto cancel_at(

@see cancel_at
*/
auto cancel_after(
capy::IoAwaitable auto&& op,
timer& t,
timer::duration timeout)
auto
cancel_after(capy::IoAwaitable auto&& op, timer& t, timer::duration timeout)
{
return cancel_at(
std::forward<decltype(op)>(op), t,
timer::clock_type::now() + timeout);
std::forward<decltype(op)>(op), t, timer::clock_type::now() + timeout);
}

/** Cancel an operation if it does not complete by a deadline.
Expand Down Expand Up @@ -155,12 +149,10 @@ auto cancel_after(

@see cancel_after
*/
auto cancel_at(
capy::IoAwaitable auto&& op,
timer::time_point deadline)
auto
cancel_at(capy::IoAwaitable auto&& op, timer::time_point deadline)
{
return detail::cancel_at_awaitable<
std::decay_t<decltype(op)>, timer, true>(
return detail::cancel_at_awaitable<std::decay_t<decltype(op)>, timer, true>(
std::forward<decltype(op)>(op), deadline);
}

Expand Down Expand Up @@ -198,13 +190,11 @@ auto cancel_at(

@see cancel_at
*/
auto cancel_after(
capy::IoAwaitable auto&& op,
timer::duration timeout)
auto
cancel_after(capy::IoAwaitable auto&& op, timer::duration timeout)
{
return cancel_at(
std::forward<decltype(op)>(op),
timer::clock_type::now() + timeout);
std::forward<decltype(op)>(op), timer::clock_type::now() + timeout);
}

} // namespace boost::corosio
Expand Down
12 changes: 7 additions & 5 deletions include/boost/corosio/detail/acceptor_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,18 @@ class BOOST_COROSIO_DECL acceptor_service
*/
virtual std::error_code open_acceptor_socket(
tcp_acceptor::implementation& impl,
int family, int type, int protocol) = 0;
int family,
int type,
int protocol) = 0;

/** Bind an open acceptor to a local endpoint.

@param impl The acceptor implementation to bind.
@param ep The local endpoint to bind to.
@return Error code on failure, empty on success.
*/
virtual std::error_code bind_acceptor(
tcp_acceptor::implementation& impl, endpoint ep) = 0;
virtual std::error_code
bind_acceptor(tcp_acceptor::implementation& impl, endpoint ep) = 0;

/** Start listening for incoming connections.

Expand All @@ -67,8 +69,8 @@ class BOOST_COROSIO_DECL acceptor_service
@param backlog The maximum length of the pending connection queue.
@return Error code on failure, empty on success.
*/
virtual std::error_code listen_acceptor(
tcp_acceptor::implementation& impl, int backlog) = 0;
virtual std::error_code
listen_acceptor(tcp_acceptor::implementation& impl, int backlog) = 0;

protected:
/// Construct the acceptor service.
Expand Down
Loading
Loading