## Typestate Pattern with Generics

Generics can be used with the typestate pattern to reduce duplication and allow
shared logic across state variants, while still encoding state transitions in
the type system.

```rust
#[non_exhaustive]
struct Insecure;
struct Secure {
    client_cert: Option<Vec<u8>>,
}

trait Transport {
    /* ... */
}
impl Transport for Insecure {
    /* ... */
}
impl Transport for Secure {
    /* ... */
}

#[non_exhaustive]
struct WantsTransport;
struct Ready<T> {
    transport: T,
}

struct ConnectionBuilder<T> {
    host: String,
    timeout: Option<u64>,
    stage: T,
}

struct Connection {/* ... */}

impl Connection {
    fn new(host: &str) -> ConnectionBuilder<WantsTransport> {
        ConnectionBuilder {
            host: host.to_owned(),
            timeout: None,
            stage: WantsTransport,
        }
    }
}

impl<T> ConnectionBuilder<T> {
    fn timeout(mut self, secs: u64) -> Self {
        self.timeout = Some(secs);
        self
    }
}

impl ConnectionBuilder<WantsTransport> {
    fn insecure(self) -> ConnectionBuilder<Ready<Insecure>> {
        ConnectionBuilder {
            host: self.host,
            timeout: self.timeout,
            stage: Ready { transport: Insecure },
        }
    }

    fn secure(self) -> ConnectionBuilder<Ready<Secure>> {
        ConnectionBuilder {
            host: self.host,
            timeout: self.timeout,
            stage: Ready { transport: Secure { client_cert: None } },
        }
    }
}

impl ConnectionBuilder<Ready<Secure>> {
    fn client_certificate(mut self, raw: Vec<u8>) -> Self {
        self.stage.transport.client_cert = Some(raw);
        self
    }
}

impl<T: Transport> ConnectionBuilder<Ready<T>> {
    fn connect(self) -> std::io::Result<Connection> {
        // ... use valid state to establish the configured connection
        Ok(Connection {})
    }
}

fn main() -> std::io::Result<()> {
    let _conn = Connection::new("db.local")
        .secure()
        .client_certificate(vec![1, 2, 3])
        .timeout(10)
        .connect()?;
    Ok(())
}
```

<details>

- This example extends the typestate pattern using **generic parameters** to
  avoid duplication of common logic.

- We use a generic type `T` to represent the current stage of the builder, and
  share fields like `host` and `timeout` across all stages.

- The transport phase uses `insecure()` and `secure()` to transition from
  `WantsTransport` into `Ready<T>`, where `T` is a type that implements the
  `Transport` trait.

- Only once the connection is in a `Ready<T>` state, we can call `.connect()`,
  guaranteed at compile time.

- Using generics allows us to avoid writing separate `BuilderForSecure`,
  `BuilderForInsecure`, etc. structs.

  Shared behavior, like `.timeout(...)`, can be implemented once and reused
  across all states.

- This same design appears
  [in real-world libraries like **Rustls**](https://docs.rs/rustls/latest/rustls/struct.ConfigBuilder.html),
  where the `ConfigBuilder` uses typestate and generics to guide users through a
  safe, ordered configuration flow.

  It enforces at compile time that users must choose protocol versions, a
  certificate verifier, and client certificate options, in the correct sequence,
  before building a config.

- **Downsides** of this approach include:
  - The documentation of the various builder types can become difficult to
    follow, since their names are generated by generics and internal structs
    like `Ready<T>`.
  - Error messages from the compiler may become more opaque, especially if a
    trait bound is not satisfied or a state transition is incomplete.

    The error messages might also be hard to follow due to the complexity as a
    result of the nested generics types.

- Still, in return for this complexity, you get compile-time enforcement of
  valid configuration, clear builder sequencing, and no possibility of
  forgetting a required step or misusing the API at runtime.

</details>
