// The gRPC sub-connection connectivity state machine (← gRPC `connectivity.State`): each address the
// Channel dials is a `SubConn` that moves through IDLE → CONNECTING → READY, drops to
// TRANSIENT_FAILURE on error (then retries via CONNECTING after backoff), and ends at SHUTDOWN. The
// load balancer picks among the sub-connections that are READY; the connection pool holds them. This
// is the pure state core — the Channel calls the transition methods as real socket events happen.

///|
/// A sub-connection's connectivity state (← gRPC `connectivity.State`).
pub(all) enum ConnectivityState {
  Idle
  Connecting
  Ready
  TransientFailure
  Shutdown
} derive(Eq, Debug)

///|
/// One address the Channel dials, tracking its connectivity state.
pub struct SubConn {
  address : String
  mut state : ConnectivityState
}

///|
/// A fresh sub-connection to `address`, starting IDLE.
pub fn SubConn::new(address : String) -> SubConn {
  { address, state: Idle }
}

///|
/// Begin connecting (IDLE or TRANSIENT_FAILURE → CONNECTING). A no-op once SHUTDOWN or already
/// connecting/ready.
pub fn SubConn::connect(self : SubConn) -> Unit {
  match self.state {
    Idle | TransientFailure => self.state = Connecting
    _ => ()
  }
}

///|
/// The connection attempt succeeded (CONNECTING → READY).
pub fn SubConn::on_connected(self : SubConn) -> Unit {
  if self.state is Connecting {
    self.state = Ready
  }
}

///|
/// A connection attempt or an established connection failed (→ TRANSIENT_FAILURE), unless shut down.
pub fn SubConn::on_failure(self : SubConn) -> Unit {
  if self.state != Shutdown {
    self.state = TransientFailure
  }
}

///|
/// A READY connection went idle (READY → IDLE).
pub fn SubConn::on_idle(self : SubConn) -> Unit {
  if self.state is Ready {
    self.state = Idle
  }
}

///|
/// Shut the sub-connection down permanently (→ SHUTDOWN, a terminal state).
pub fn SubConn::shutdown(self : SubConn) -> Unit {
  self.state = Shutdown
}

///|
/// Whether this sub-connection can carry RPCs right now.
pub fn SubConn::is_ready(self : SubConn) -> Bool {
  self.state is Ready
}