# Serving

> UCall for Rust

`Server::new` takes the interfaces to answer on, and `Server::with_options` also takes `ServerOptions`: the `Backend`, an optional `CPUClass` ceiling, a `Log` sink and a StatsD endpoint in `Metrics`.
It fails rather than substituting when the backend is unavailable or the CPU does not run the class.
An `Interface` is an address, optionally pinned to a Linux device, with its own security and admission limits, so one server answers plaintext on loopback and Noise on the wire at once.
It admits 1024 connections by default, reads one request per connection at a time unless `pipelined_requests` allows more, and replies still leave in request order.
`max_request_bytes` caps a request's head and buffered body, answering 413 past it, and `reply_directories` names the directories path replies resolve beneath.
`Interface::listening` accepts on a listener another owner opened, a `TcpListener`, a `UnixListener` or one systemd passed in, instead of binding an address, and never closes it.
At its connection budget an interface evicts the idle keep-alive connection that progressed least recently for a new peer.
Port zero binds a free port, which `Server::address` reports.

```rust
use std::sync::Arc;
use ucall::*;

let public = Interface::new("0.0.0.0:8545").event_loops(4).connections(16_384).pipelined_requests(16);
let health = Interface::new("127.0.0.1:8546").connections(4);
let log = Log { callback: Arc::new(|level: LogLevel, line: &[u8]| eprintln!("{level:?} {}", String::from_utf8_lossy(line))), format: LogFormat::Human, level: LogLevel::Warning };
let metrics = Metrics { address: "127.0.0.1:8125".into(), prefix: "rpc".into(), ..Default::default() };
let options = ServerOptions { cpu_class: Some(CPUClass::Serial), log: Some(log), metrics: Some(metrics), ..Default::default() };
let mut server = Server::with_options(&[public, health], options)?;
println!("{} event loops on {} with {} kernels", server.event_loops(), server.backend(), server.cpu_class());

server.get("/users/{user}/files/{*path}", |request: Request| {
    let user = request.path_parameter("user").unwrap_or_default();
    let path = request.path_parameter("path").unwrap_or_default();
    let listing = [user, b":".as_slice(), path].concat();
    let _ = request.reply(HTTPStatus::OK, &[], &listing);
})?;
server.route("/anything", Verb::Any, |request: Request| {
    let message = format!("{:?} is not served", request.verb());
    let _ = request.reply_error(HTTPStatus::NOT_IMPLEMENTED, &message);
})?;
```

Endpoints register through `&mut Server` before any loop is polled, with `route` taking any `Verb` and `get`, `post`, `put`, `delete` and `patch` naming one.
Templates capture `{name}` segments and a greedy `{*name}` tail, literal segments match before captures, and registering one template and verb twice fails with `Status::AlreadyExists`.
Routing is exact: an empty segment is a segment, so `/users` and `/users/` are different paths.
A path no endpoint matches answers 404, one whose endpoints take other verbs answers 405 with an `allow` header, a GET endpoint also serves HEAD, and `OPTIONS` answers 204 with the same `allow` list.
A request that cannot be parsed answers 400, 413 or 501 before reaching any handler.

Log lines reach the callback on whichever thread produced them, and StatsD datagrams carry each loop's counters and sampled request latencies, every second unless `Metrics::interval` says otherwise.
`Server::event_loop_statistics` copies one loop's counters, from any thread while the loop runs: polls, system calls, submissions and completions, accepted connections, requests, and the bytes received, sent and copied.
Divided by `requests`, they price one call.

`use ucall::BatchEndpoint;`

`use ucall::BatchEndpointStatistics;`

`use ucall::EventLoopStatistics;`

`use ucall::Interface;`

`use ucall::Metrics;`

`use ucall::Server;`

`use ucall::ServerOptions;`

`use ucall::Backend;`

`use ucall::Log;`

`use ucall::LogFormat;`

`use ucall::LogLevel;`

`use ucall::Verb;`

`use ucall::*;`

## LogCallback

Receives one formatted log line, without a trailing newline, on whichever thread produced it, polling threads included; it should return quickly, and a panic drops the line.

```rust
pub type LogCallback = dyn Fn(LogLevel, &[u8]) + Send + Sync;
```

## BatchEndpoint

One batch endpoint, polled by one thread at a time and observable from any.

```rust
pub struct BatchEndpoint
```

Requests from every event loop share its queue, so one thread drains what all of them
received. Dropping it leaves its queued requests unanswered until the server is freed, and the
queue, once full, refuses new ones with 503.

```
use std::time::Duration;
use ucall::*;

let mut server = Server::new(&#x26;[Interface::new("127.0.0.1:0")])?;
let batching = Batching { min_size: 2, max_size: 2, max_latency: Duration::from_secs(1) };
let scores = server.batch("/score", Verb::Post, batching, |batch: Batch| {
    for request in batch {
        let score = request.body().len().to_string();
        let _ = request.reply(HTTPStatus::OK, &#x26;[], score.as_bytes());
    }
})?;
let address = server.address(0).unwrap().to_owned();

let mut client = Client::new(ClientOptions { connections: 2, ..Default::default() })?;
client.submit(ClientCall::post(format!("http://{address}/score"), b"four".as_slice()), 0)?;
client.submit(ClientCall::post(format!("http://{address}/score"), b"seven..".as_slice()), 1)?;
std::thread::scope(|scope| {
    scope.spawn(|| server.take_calls(0));
    scope.spawn(|| scores.take_batches());
    let mut completed: [Completed; 2] = Default::default();
    let mut answered = 0;
    while answered &#x3C; 2 {
        match client.take_completed(&#x26;mut completed, Duration::from_secs(1)) {
            Ok(done) => answered += done.len(),
            Err(_) => break,
        }
    }
    server.stop();
});
let statistics = scores.statistics()?;
assert_eq!((statistics.batches, statistics.requests, statistics.filled_batches), (1, 2, 1));
```

Implements: `Send`, `Sync`, `Drop`

## take_batch

Runs the handler on this thread if a batch is due, waiting up to `timeout` for one; zero performs one nonblocking round.

```rust
pub fn take_batch(&self, timeout: Duration) -> Result<()>
```

Fails with [`Status::Contended`](https://www.unum.cloud/docs/ucall/rust/errors.md#Contended) while another thread drains the same endpoint.

## take_batches

Runs the handler on this thread for every due batch until [`Server::stop`](#stop); requests still queued then are released without a reply.

```rust
pub fn take_batches(&self) -> Result<()>
```

Fails with [`Status::Contended`](https://www.unum.cloud/docs/ucall/rust/errors.md#Contended) while another thread drains the same endpoint.

## statistics

A snapshot of the endpoint's counters, readable from any thread while it is polled.

```rust
pub fn statistics(&self) -> Result<BatchEndpointStatistics>
```

## BatchEndpointStatistics

Counters of one batch endpoint since registration: how large its batches were, and why each was dispatched.

```rust
pub struct BatchEndpointStatistics
```

Each counter is read on its own, so a snapshot of an endpoint being polled is not one
instant. Requests released by [`Server::stop`](#stop) count nowhere.

- `batches` `u64`: Batches handed to the handler.
- `requests` `u64`: Requests across those batches.
- `filled_batches` `u64`: Batches dispatched on reaching [`Batching::max_size`](https://www.unum.cloud/docs/ucall/rust/batches.md#Batching).
- `ready_batches` `u64`: Batches dispatched on reaching [`Batching::min_size`](https://www.unum.cloud/docs/ucall/rust/batches.md#Batching), below the maximum.
- `expired_batches` `u64`: Batches dispatched below [`Batching::min_size`](https://www.unum.cloud/docs/ucall/rust/batches.md#Batching) once [`Batching::max_latency`](https://www.unum.cloud/docs/ucall/rust/batches.md#Batching) passed.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, [`Debug`](#Debug), `Default`

## EventLoopStatistics

Counters of one event loop since the server started; divided by `requests`, they price one call.

```rust
pub struct EventLoopStatistics
```

Each counter is read on its own, so a snapshot of a running loop is not one instant. Byte
counters cover the bytes UCall itself moves, never the kernel's own copies.

- `polls` `u64`: Engine polls the loop issued, each taking zero or more completions.
- `empty_polls` `u64`: Engine polls that took no completion.
- `kernel_enters` `u64`: System calls: io_uring enters, or other backends' waits, registrations and socket calls.
- `submissions` `u64`: Operations queued: io_uring submission entries, or requests another backend accepted.
- `completions` `u64`: Results taken: io_uring completion entries, or operations another backend finished.
- `cancellations` `u64`: Pending operations, or io_uring multishot receives, the engine asked to cancel.
- `accepts` `u64`: Connections accepted and handed to this loop.
- `requests` `u64`: HTTP requests parsed and dispatched to an endpoint or an error reply.
- `receive_rearms` `u64`: Multishot receives armed again on a socket that already streamed, only on io_uring 7.0.
- `bytes_received` `u64`: Bytes the kernel reported received on this loop's connections, ciphertext under Noise.
- `bytes_sent` `u64`: Bytes the kernel reported sent from this loop's connections, ciphertext under Noise.
- `bytes_copied` `u64`: Bytes UCall copied: receive appends, reply bodies, Noise records and parked receives.
- `zero_copy_sends` `u64`: Sends that left without copying: reply segments and file windows.
- `zero_copy_fallbacks` `u64`: Zero-copy sends the kernel copied anyway or refused to pin, as loopback always does.
- `copying_sends` `u64`: Sends that copied instead of pinning: the socket was demoted, refused zero-copy, or had no
room to track one.
- `file_reads_asynchronous` `u64`: File reads handed to the kernel to finish later: io_uring, Linux or FreeBSD AIO, or
overlapped reads.
- `file_reads_blocking` `u64`: File reads the loop issued itself and blocked on, as the posix backend and macOS do.
- `bytes_read` `u64`: Bytes the kernel reported read from files into the loop's file windows.
- `file_window_overlaps` `u64`: File reads submitted while an earlier window of the same stream waited to send or sent.
- `linger_resets` `u64`: Lingering closes reset at their deadline because the kernel still held what they sent.
- `ready_passes` `u64`: Passes the loop made over a ready connection, each advancing it as far as it goes.
- `replied_dequeues` `u64`: Replied exchanges the loop took from its queue to adopt their reply segments.
- `refused_requests` `u64`: Requests the loop answered itself with 400, 404, 405, 413, 501, 503 or 505.
- `handshake_failures` `u64`: Connections whose Noise handshake failed.
- `authorizer_refusals` `u64`: Connections whose authenticated peer key the interface's authorizer refused.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, [`Debug`](#Debug), `Default`

## Interface

One address a server answers on, with the security and admission limits of the connections arriving there.

```rust
pub struct Interface
```

One server may answer plaintext on loopback and Noise on the wire at once, through two
interfaces:

```
use ucall::*;

let (private_key, _) = generate_noise_keypair()?;
let plain = Interface::new("127.0.0.1:0");
let sealed = Interface::new("127.0.0.1:0")
    .security(Security::NoiseXX, private_key)
    .peer_authorizer(|noise_private_key: &#x26;NoiseKey| noise_private_key != &#x26;[0; 32]);
let server = Server::new(&#x26;[plain, sealed])?;
assert!(server.address(1).is_some());
```

Implements: `Clone`

## new

An interface listening on [`address`](#address) in "host:port" form, admitting 1024 connections at once; port zero picks a free one, which [`Server::address`](#address) reports.

```rust
pub fn new(address: impl Into<String>) -> Self
```

## listening

An interface accepting on a listening stream socket another owner opened, such as a `TcpListener`, a `UnixListener` or one systemd passed in; the server accepts on duplicates and never closes `listener`, which must outlive [`Server::new`](https://www.unum.cloud/docs/ucall/rust/calling.md#new).

```rust
pub fn listening(listener: &impl AsRawFd) -> Self
```

## device_name

Pins the interface to a physical device, like "eth0"; only Linux supports it.

```rust
pub fn device_name(self, name: impl Into<String>) -> Self
```

## security

Requires a Noise handshake under this server identity; [`NoiseXX`](https://www.unum.cloud/docs/ucall/rust/noise-keys.md#NoiseXX) also needs an authorizer, and [`NoiseKK`](https://www.unum.cloud/docs/ucall/rust/noise-keys.md#NoiseKK) the initiator's key.

```rust
pub fn security(self, security: Security, private_key: NoiseKey) -> Self
```

## noise_peer_key

The one initiator's static public key a [`NoiseKK`](https://www.unum.cloud/docs/ucall/rust/noise-keys.md#NoiseKK) interface admits, known in advance.

```rust
pub fn noise_peer_key(self, public_key: NoiseKey) -> Self
```

## peer_authorizer

Vets each client's authenticated static key before any of its requests is read.

```rust
pub fn peer_authorizer(self, authorizer: impl Fn(&NoiseKey) -> bool + Send + Sync + 'static) -> Self
```

## event_loops

Event loops accepting on this interface; zero means one, or the receive-queue count of a named Linux device.

```rust
pub fn event_loops(self, count: usize) -> Self
```

## connections

Connections open at once across this interface's loops; further ones wait in the listen queue until one closes.

```rust
pub fn connections(self, count: usize) -> Self
```

## pipelined_requests

Requests one connection may have in flight before the server stops reading from it; zero means one, and replies still leave in request order.

```rust
pub fn pipelined_requests(self, count: usize) -> Self
```

## max_request_bytes

The largest request head and buffered body; past it the reply is 413 and the connection closes.

```rust
pub fn max_request_bytes(self, bytes: usize) -> Self
```

Zero takes the largest receive buffer the kernel grants a socket, and streamed
bodies are bounded by the handler's pulls instead.

## reply_directories

Directories the [`ReplyPart::Path`](https://www.unum.cloud/docs/ucall/rust/requests.md#Path) parts of replies to this interface's requests resolve beneath, by position; each is opened when the server starts, failing it if one cannot be.

```rust
pub fn reply_directories(self, directories: impl IntoIterator<Item = impl Into<String>>) -> Self
```

## Metrics

The StatsD endpoint a server sends each event loop's counters and sampled request latencies to, as UDP datagrams.

```rust
pub struct Metrics
```

- `address` `String`: The endpoint in "host:port" form.
- `sample_rate` `f32`: The fraction of finished requests whose latency is reported, in (0, 1]; zero means 1.
- `prefix` `String`: The metric name prefix; empty means "ucall".
- `tags` `Vec<String>`: Tags on every metric, each "key:value".
- `interval` `Duration`: The time between one event loop's datagrams; zero means one second.

Implements: `Clone`, [`Debug`](#Debug), `Default`

## Server

An HTTP server over one or more interfaces, polled by application threads.

```rust
pub struct Server
```

Register every endpoint first, through `&mut self`, then share `&Server` with the threads
that poll its event loops. Dropping it stops the server; the library frees it once the last
[`BatchEndpoint`](#BatchEndpoint) and retained [`Request`](https://www.unum.cloud/docs/ucall/rust/requests.md#Request) are dropped too.

```
use ucall::*;

let mut server = Server::new(&#x26;[Interface::new("127.0.0.1:0")])?;
server.get("/hello", |request: Request| {
    let _ = request.reply(HTTPStatus::OK, &#x26;["content-type: text/plain".into()], b"Hello!");
})?;
let address = server.address(0).unwrap().to_owned();

let mut client = Client::new(ClientOptions { connections: 1, ..Default::default() })?;
std::thread::scope(|scope| {
    for event_loop in 0..server.event_loops() {
        let server = &#x26;server;
        scope.spawn(move || server.take_calls(event_loop));
    }
    let response = client.get(format!("http://{address}/hello"));
    server.stop();
    assert_eq!(response?.body(), b"Hello!");
    Ok::&#x3C;(), Error>(())
})?;
assert_eq!(server.event_loop_statistics(0)?.requests, 1);
```

Implements: `Send`, `Sync`, `Drop`

## new

Starts a server answering on `interfaces`, with the automatic backend and CPU class.

```rust
pub fn new(interfaces: &[Interface]) -> Result<Server>
```

## with_options

Starts a server answering on `interfaces` with the backend, CPU class, log sink and StatsD endpoint `options` name.

```rust
pub fn with_options(interfaces: &[Interface], options: ServerOptions) -> Result<Server>
```

## event_loops

Event loops this server runs, each to be polled by one thread at a time.

```rust
pub fn event_loops(&self) -> usize
```

## backend

The I/O backend the server resolved to.

```rust
pub fn backend(&self) -> Backend
```

## cpu_class

The CPU class the server resolved to.

```rust
pub fn cpu_class(&self) -> CPUClass
```

## address

The numeric address interface `index` listens on, with the port it bound.

```rust
pub fn address(&self, index: usize) -> Option<&str>
```

## route

Routes requests matching [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) and [`verb`](https://www.unum.cloud/docs/ucall/rust/requests.md#verb) to `handler`, which runs on the polling thread.

```rust
pub fn route(
    &mut self,
    path: &str,
    verb: Verb,
    handler: impl Fn(Request) + Send + Sync + 'static,
) -> Result<()>
```

Templates capture `{name}` segments and a greedy `{*name}` tail, read back through
[`Request::path_parameter`](https://www.unum.cloud/docs/ucall/rust/requests.md#path_parameter); literal segments match before captures, and captures before a
tail. A handler that panics, or drops its request unreplied, answers 500. Registering the
same template and verb twice fails with [`Status::AlreadyExists`](https://www.unum.cloud/docs/ucall/rust/errors.md#AlreadyExists).

## route_with

Routes like [`Server::route`](#route), running `handler` once the body is buffered, or with [`BodyDelivery::Streamed`](https://www.unum.cloud/docs/ucall/rust/batches.md#Streamed) as soon as the headers arrived, the body still to be pulled through [`DetachedRequest::body_chunk`](https://www.unum.cloud/docs/ucall/rust/requests.md#body_chunk).

```rust
pub fn route_with(
    &mut self,
    path: &str,
    verb: Verb,
    delivery: BodyDelivery,
    handler: impl Fn(Request) + Send + Sync + 'static,
) -> Result<()>
```

## get

Routes GET requests on [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) to `handler`.

```rust
pub fn get(&mut self, path: &str, handler: impl Fn(Request) + Send + Sync + 'static) -> Result<()>
```

## post

Routes POST requests on [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) to `handler`.

```rust
pub fn post(&mut self, path: &str, handler: impl Fn(Request) + Send + Sync + 'static) -> Result<()>
```

## put

Routes PUT requests on [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) to `handler`.

```rust
pub fn put(&mut self, path: &str, handler: impl Fn(Request) + Send + Sync + 'static) -> Result<()>
```

## delete

Routes DELETE requests on [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) to `handler`.

```rust
pub fn delete(
    &mut self,
    path: &str,
    handler: impl Fn(Request) + Send + Sync + 'static,
) -> Result<()>
```

## patch

Routes PATCH requests on [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) to `handler`.

```rust
pub fn patch(&mut self, path: &str, handler: impl Fn(Request) + Send + Sync + 'static) -> Result<()>
```

## batch

Collects requests matching [`path`](https://www.unum.cloud/docs/ucall/rust/requests.md#path) and [`verb`](https://www.unum.cloud/docs/ucall/rust/requests.md#verb) from every event loop into one queue, which the returned endpoint drains into `handler` on whichever thread drains it.

```rust
pub fn batch(
    &mut self,
    path: &str,
    verb: Verb,
    batching: Batching,
    handler: impl Fn(Batch<'_>) + Send + Sync + 'static,
) -> Result<BatchEndpoint>
```

Requests the handler neither replies to nor keeps answer 500 once it returns, as do all of
them when it panics.

## take_call

Advances one event loop, running the handlers of the requests it completes on this thread, and waits up to `timeout` for progress; zero performs one nonblocking round.

```rust
pub fn take_call(&self, event_loop: usize, timeout: Duration) -> Result<Polling>
```

Answers
[`Polling::Retired`](https://www.unum.cloud/docs/ucall/rust/threads-and-polling.md#Retired) once the loop has nothing left to take after [`Server::stop`](#stop).

Fails with [`Status::Contended`](https://www.unum.cloud/docs/ucall/rust/errors.md#Contended) while another thread polls the same loop.

## take_calls

Drives one event loop on this thread until [`Server::stop`](#stop) or an I/O failure.

```rust
pub fn take_calls(&self, event_loop: usize) -> Result<()>
```

Fails with [`Status::Contended`](https://www.unum.cloud/docs/ucall/rust/errors.md#Contended) while another thread polls the same loop.

## stop

Requests shutdown and wakes every polling thread; callable from any thread, including from inside a handler.

```rust
pub fn stop(&self)
```

The first call drains: no new connections, idle ones close, and the requests already held
are answered before their connections close. A second call cuts the replies still in flight.

## event_loop_statistics

A snapshot of one event loop's counters, readable from any thread while it is polled.

```rust
pub fn event_loop_statistics(&self, event_loop: usize) -> Result<EventLoopStatistics>
```

Fails with [`Status::InvalidArgument`](https://www.unum.cloud/docs/ucall/rust/errors.md#InvalidArgument) for an index past the last loop.

## ServerOptions

What a server runs on and reports through, beside its interfaces.

```rust
pub struct ServerOptions
```

- `backend` `Backend`: The requested I/O backend, failing rather than substituting when it is unavailable.
- `cpu_class` `Option<CPUClass>`: A ceiling on the CPU class, failing where the CPU does not run it; [`None`](https://www.unum.cloud/docs/ucall/rust/noise-keys.md#None) takes what the
constructing thread's CPU offers.
- `log` `Option<Log>`: Where log lines go; [`None`](https://www.unum.cloud/docs/ucall/rust/noise-keys.md#None) keeps the server silent.
- `metrics` `Option<Metrics>`: Where StatsD datagrams go; [`None`](https://www.unum.cloud/docs/ucall/rust/noise-keys.md#None) sends none.

Implements: `Clone`, `Default`

## Backend

The I/O implementation a server or client runs on.

```rust
pub enum Backend
```

Prints and parses its stable name, like "linux-uring618".

- `Automatic`: The best native backend this machine and build offer.
- `POSIX`: Portable readiness polling on any POSIX system.
- `LinuxEpollAIO`: Linux readiness polling over `epoll`, reading files through Linux AIO.
- `LinuxURing612`: Linux io_uring as kernel 6.12 offers it.
- `LinuxURing618`: Linux io_uring as kernel 6.18 offers it.
- `BSDKqueue`: macOS and FreeBSD readiness polling over `kqueue`.
- `WindowsIOCP`: Windows I/O completion ports.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, [`Debug`](#Debug), `Hash`, `Default`, `Display`, `FromStr`

## Log

The one log sink of a server or a client; without one, the library writes nothing anywhere.

```rust
pub struct Log
```

- `callback` `Arc<LogCallback>`: Receives every line at or above `level`.
- `format` `LogFormat`: The line format.
- `level` `LogLevel`: Lines below this severity are never formatted.

Implements: `Clone`

## LogFormat

The shape of each log line.

```rust
pub enum LogFormat
```

- `Human`: Human-readable lines with normalized units.
- `JSON`: One JSON document per line.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, [`Debug`](#Debug), `Hash`, `Default`

## LogLevel

The severity of a log line, from the most verbose up.

```rust
pub enum LogLevel
```

- `Debug`: Detail for debugging UCall itself.
- `Info`: Routine events.
- `Warning`: Something recoverable went wrong.
- `Error`: An operation failed.
- `Fatal`: The handle cannot go on.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, `PartialOrd`, `Ord`, [`Debug`](#Debug), `Hash`, `Default`

## Verb

An HTTP method, for routing on the server and for calls on the client.

```rust
pub enum Verb
```

- `Unknown`: Unrecognized; a routed request never carries it.
- `Get`: GET, reading a resource.
- `Post`: POST, creating a resource or calling a procedure.
- `Put`: PUT, replacing a resource.
- `Delete`: DELETE, removing a resource.
- `Patch`: PATCH, updating part of a resource.
- `Head`: HEAD, reading only the headers.
- `Options`: OPTIONS, asking which methods a resource supports.
- `Any`: Matches every method; valid only when registering an endpoint.

Implements: `Clone`, `Copy`, `StructuralPartialEq`, `PartialEq`, `Eq`, [`Debug`](#Debug), `Hash`

