1pub mod ast;
12pub mod compiler;
13pub mod effects;
14pub mod extensions;
15pub mod heap;
16pub mod identifiers;
17pub mod runtime;
18pub mod testing;
19pub mod topology;
20pub mod tracing;
21
22pub use runtime::{
24 ChoiceLabel, ChoreographicAdapter, ChoreographicAdapterExt, Message, ProtocolContext,
25 ProtocolOutput, SystemClock, SystemRng,
26};
27
28pub use identifiers::{Datacenter, Endpoint as TopologyEndpoint, Namespace, Region, RoleName};
30
31pub use ast::{Choreography, MessageType, Protocol, Role};
33pub use compiler::generate_effects_protocol;
34pub use compiler::{
35 create_standard_extension_parser, format_choreography, format_choreography_str,
36 format_choreography_with_config, ExtensionParseError, ExtensionParser, ExtensionParserBuilder,
37 GrammarComposer, GrammarComposerBuilder, GrammarCompositionError, PrettyConfig,
38};
39pub use effects::middleware::{Metrics, Retry, Trace};
40pub use effects::NoOpHandler;
41pub use effects::{
42 interpret, ChoreoHandler, ChoreoHandlerExt, ChoreoResult, ChoreographyError, Effect, Endpoint,
43 InterpretResult, InterpreterState, LabelId, MessageTag, Program, ProgramBuilder,
44 ProgramMessage, RoleId,
45};
46pub use effects::{InMemoryHandler, RecordedEvent, RecordingHandler};
47pub use effects::{SimpleChannel, TelltaleEndpoint, TelltaleHandler};
48pub use extensions::{
49 CodegenContext, ExtensionRegistry, ExtensionValidationError, GrammarExtension, ParseContext,
50 ParseError, ProjectionContext, ProtocolExtension, StatementParser,
51};
52pub use runtime::{spawn, spawn_local};
53pub use topology::{
54 parse_topology, ByteMessage, InMemoryChannelTransport, Location, ParsedTopology, Topology,
55 TopologyBuilder, TopologyConstraint, TopologyError, TopologyHandler, TopologyHandlerBuilder,
56 TopologyLoadError, TopologyMode, TopologyParseError, TopologyValidation, Transport,
57 TransportError, TransportFactory, TransportMessage, TransportResult, TransportType,
58};
59
60pub use heap::{
62 ChannelState, Direction, Heap, HeapCommitment, HeapError, MerkleProof, MerkleTree,
63 Message as HeapMessage, MessagePayload, ProofStep, Resource, ResourceId,
64};
65
66pub use testing::{
68 AsyncClock, BlockedOn, Checkpoint, Clock, InMemoryTransport, MockClock, NullObserver,
69 ProtocolEnvelope, ProtocolObserver, ProtocolStateMachine, ProtocolTest, ProtocolTestBuilder,
70 RecordingObserver, Rng, RoleBinding, SeededRng, SimulatedTransport, StepInput, StepOutput,
71 TestConfig, TestResult, WallClock,
72};
73
74pub use telltale_macros::choreography;
76pub use telltale_types::{ChannelCapacity, MessageLenBytes, QueueCapacity};
77
78#[doc(hidden)]
83pub mod unstable {
84 pub use crate::extensions::{CodegenContext, ParseContext, ProjectionContext, StatementParser};
85}
86
87pub fn parse_and_generate_with_extensions(
91 input: &str,
92 extension_registry: &ExtensionRegistry,
93) -> std::result::Result<proc_macro2::TokenStream, CompilationError> {
94 use compiler::codegen::generate_choreography_code_with_extensions;
95 use compiler::parser::parse_choreography_str_with_extensions;
96 use compiler::projection::project;
97
98 let (choreography, extensions) =
99 parse_choreography_str_with_extensions(input, extension_registry)
100 .map_err(CompilationError::Parse)?;
101
102 choreography
104 .validate()
105 .map_err(|e| CompilationError::Validation(e.to_string()))?;
106
107 let mut local_types = Vec::new();
109 for role in &choreography.roles {
110 let local_type = project(&choreography, role)
111 .map_err(|e| CompilationError::Projection(e.to_string()))?;
112 local_types.push((role.clone(), local_type));
113 }
114
115 let generated_code =
117 generate_choreography_code_with_extensions(&choreography, &local_types, &extensions);
118
119 Ok(generated_code)
120}
121
122pub fn compile_choreography_with_extensions(
124 input: &str,
125) -> std::result::Result<proc_macro2::TokenStream, CompilationError> {
126 let registry = ExtensionRegistry::with_builtin_extensions();
127 parse_and_generate_with_extensions(input, ®istry)
128}
129
130pub fn parse_choreography_with_extensions(
132 input: &str,
133 extension_registry: &ExtensionRegistry,
134) -> std::result::Result<(Choreography, Vec<Box<dyn ProtocolExtension>>), CompilationError> {
135 use compiler::parser::parse_choreography_str_with_extensions;
136
137 parse_choreography_str_with_extensions(input, extension_registry)
138 .map_err(CompilationError::Parse)
139}
140
141#[derive(Debug, thiserror::Error)]
143pub enum CompilationError {
144 #[error("parse error: {0}")]
145 Parse(#[from] compiler::parser::ParseError),
146
147 #[error("validation error: {0}")]
148 Validation(String),
149
150 #[error("projection error: {0}")]
151 Projection(String),
152
153 #[error("code generation error: {0}")]
154 Codegen(String),
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::effects::{LabelId, RoleId};
161 use crate::identifiers::RoleName;
162
163 #[allow(dead_code)]
165 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
166 enum TestRole {
167 Alice,
168 Bob,
169 }
170
171 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
172 enum TestLabel {
173 Test,
174 }
175
176 impl LabelId for TestLabel {
177 fn as_str(&self) -> &'static str {
178 match self {
179 TestLabel::Test => "test",
180 }
181 }
182
183 fn from_str(label: &str) -> Option<Self> {
184 match label {
185 "test" => Some(TestLabel::Test),
186 _ => None,
187 }
188 }
189 }
190
191 impl RoleId for TestRole {
192 type Label = TestLabel;
193
194 fn role_name(&self) -> RoleName {
195 match self {
196 TestRole::Alice => RoleName::from_static("Alice"),
197 TestRole::Bob => RoleName::from_static("Bob"),
198 }
199 }
200 }
201
202 #[test]
203 fn test_module_structure() {
204 let _choreography: Option<Choreography> = None;
206 let _protocol: Option<Protocol> = None;
207 let _role: Option<Role> = None;
208 let _message_type: Option<MessageType> = None;
209
210 let _program: Option<Program<TestRole, String>> = None;
212 let _result: Option<ChoreoResult<()>> = None;
213 let _label: Option<TestLabel> = None;
214 }
215
216 #[test]
217 fn test_free_algebra_integration() {
218 use std::time::Duration;
219
220 let program = Program::<TestRole, String>::new()
222 .send(TestRole::Bob, "hello".to_string())
223 .recv::<String>(TestRole::Bob)
224 .choose(TestRole::Bob, TestLabel::Test)
225 .offer(TestRole::Bob)
226 .with_timeout(
227 TestRole::Bob,
228 Duration::from_millis(100),
229 Program::new().end(),
230 )
231 .parallel(vec![Program::new().end()])
232 .end();
233
234 assert_eq!(program.send_count(), 1);
236 assert_eq!(program.recv_count(), 1);
237 assert!(program.has_timeouts());
238 assert!(program.has_parallel());
239 }
240}