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