Cross-Type State Bridges¶
Bridges allow terminal states of one typestate to transition into states of a completely different typestate. This enables modeling resource transformation, wrapping, and protocol handoff.
Declaration¶
Declare bridges in the source typestate using a bridges: block with dotted notation:
import session
typestate AuthFlow:
states Pending, Authenticated, Failed
transitions:
Pending -> Authenticated
Pending -> Failed
bridges:
Authenticated -> Session.Active
Failed -> ErrorLog.Entry
The destination typestate must be imported and exist.
Module-Qualified Syntax¶
For clarity when bridging to typestates from other modules, use the full module-qualified syntax:
import ./session_module
typestate AuthFlow:
states Pending, Authenticated
transitions:
Pending -> Authenticated
bridges:
# Explicit module prefix for clarity
Authenticated -> session_module.Session.Active
This syntax is especially useful when:
- Multiple modules define typestates with similar names
- You want to make cross-module dependencies explicit
- Working with library typestates (see Library Modularity)
Implementation¶
Using Procs¶
Use procs when you need extra arguments:
proc startSession(auth: Authenticated, config: SessionConfig): Active {.transition.} =
result = Active(Session(
userId: auth.AuthFlow.userId,
timeout: config.timeout
))
Using Converters¶
Use converters for simple 1:1 transforms:
converter toSession(auth: Authenticated): Active {.transition.} =
Active(Session(userId: auth.AuthFlow.userId))
# Usage - implicit conversion works
let session: Active = myAuth
Branching¶
Bridges support branching like regular transitions:
Wildcard Bridges¶
Use * to allow any state to bridge to a destination:
Validation¶
The compiler validates:
- Bridge is declared in source typestate's
bridges:block - Proc/converter signature matches declaration
- Destination typestate exists
- Destination state exists in that typestate
- Destination module is imported
Error Messages¶
Bridge Not Declared¶
Error: Undeclared bridge: Authenticated -> Session.Active
Typestate 'AuthFlow' does not declare this bridge.
Valid bridges from 'Authenticated': @[]
Hint: Add 'bridges: Authenticated -> Session.Active' to AuthFlow.
Unknown Typestate¶
If you reference a typestate that doesn't exist, you'll get an error indicating that the destination type isn't part of any registered typestate.
Unknown State¶
If you reference a state that doesn't exist in the destination typestate, you'll get an error indicating which states are valid.
Complete Example¶
# session.nim
import typestates
type
Session = object
userId: string
Active = distinct Session
Expired = distinct Session
typestate Session:
states Active, Expired
transitions:
Active -> Expired
# auth.nim
import typestates
import ./session
type
AuthFlow = object
userId: string
Pending = distinct AuthFlow
Authenticated = distinct AuthFlow
typestate AuthFlow:
states Pending, Authenticated
transitions:
Pending -> Authenticated
bridges:
Authenticated -> Session.Active
converter toSession(a: Authenticated): Active {.transition.} =
Active(Session(userId: a.AuthFlow.userId))
Cross-Module Considerations¶
consumeOnTransition and Bridges¶
Important: When bridging between typestates from different modules, both typestates should use consumeOnTransition = false.
With consumeOnTransition = true (the default), state values cannot be copied. When a bridge proc takes a state from typestate A and creates a state in typestate B, the value must be passed across module boundaries. This can trigger copy errors if either typestate has copy disabled.
# module_a.nim
typestate AuthFlow:
consumeOnTransition = false # Required for cross-module bridging
states Pending, Authenticated
bridges:
Authenticated -> Session.Active
# module_b.nim
typestate Session:
consumeOnTransition = false # Required for cross-module bridging
states Active, Expired
If you see errors like '=copy' is not available for type <State> when using bridges, add consumeOnTransition = false to both the source and destination typestates.
Visualization¶
Unified Graph (default)¶
Shows all typestates with cross-cluster dashed edges for bridges.
Separate Graphs¶
Shows individual graphs per typestate with bridges as terminal nodes.