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::{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,
58 RoleFamilyConstraint, RoleFamilyConstraintError, Topology, TopologyBuilder, TopologyConstraint,
59 TopologyError, TopologyHandler, TopologyHandlerBuilder, TopologyLoadError, TopologyMode,
60 TopologyParseError, TopologyValidation, Transport, TransportError, TransportFactory,
61 TransportMessage, TransportResult, TransportType,
62};
63
64pub use heap::{
66 ChannelState, Direction, Heap, HeapCommitment, HeapError, MerkleProof, MerkleTree,
67 Message as HeapMessage, MessagePayload, ProofStep, Resource, ResourceId,
68};
69
70pub use testing::{
72 AsyncClock, BlockedOn, Checkpoint, Clock, InMemoryTransport, MockClock, NullObserver,
73 ProtocolEnvelope, ProtocolObserver, ProtocolStateMachine, RecordingObserver, Rng, SeededRng,
74 SimulatedTransport, StepInput, StepOutput, WallClock,
75};
76
77pub use telltale_macros::tell;
79pub use telltale_types::{ChannelCapacity, MessageLenBytes, QueueCapacity};
80
81#[doc(hidden)]
86pub mod unstable {
87 pub use crate::extensions::{CodegenContext, ParseContext, ProjectionContext, StatementParser};
88}
89
90pub fn parse_and_generate_with_extensions(
94 input: &str,
95 extension_registry: &ExtensionRegistry,
96) -> std::result::Result<proc_macro2::TokenStream, CompilationError> {
97 use compiler::codegen::generate_choreography_code_with_extensions;
98 use compiler::parser::parse_choreography_str_with_extensions;
99 use compiler::projection::project;
100
101 let (choreography, extensions) =
102 parse_choreography_str_with_extensions(input, extension_registry)
103 .map_err(CompilationError::Parse)?;
104
105 choreography
107 .validate()
108 .map_err(|e| CompilationError::Validation(e.to_string()))?;
109
110 let mut local_types = Vec::new();
112 for role in &choreography.roles {
113 let local_type = project(&choreography, role)
114 .map_err(|e| CompilationError::Projection(e.to_string()))?;
115 local_types.push((role.clone(), local_type));
116 }
117
118 let generated_code =
120 generate_choreography_code_with_extensions(&choreography, &local_types, &extensions);
121
122 Ok(generated_code)
123}
124
125pub fn compile_choreography_with_extensions(
127 input: &str,
128) -> std::result::Result<proc_macro2::TokenStream, CompilationError> {
129 let registry = ExtensionRegistry::with_builtin_extensions();
130 parse_and_generate_with_extensions(input, ®istry)
131}
132
133pub fn parse_choreography_with_extensions(
135 input: &str,
136 extension_registry: &ExtensionRegistry,
137) -> std::result::Result<(Choreography, Vec<Box<dyn ProtocolExtension>>), CompilationError> {
138 use compiler::parser::parse_choreography_str_with_extensions;
139
140 parse_choreography_str_with_extensions(input, extension_registry)
141 .map_err(CompilationError::Parse)
142}
143
144#[derive(Debug, thiserror::Error)]
146pub enum CompilationError {
147 #[error("parse error: {0}")]
148 Parse(#[from] compiler::parser::ParseError),
149
150 #[error("validation error: {0}")]
151 Validation(String),
152
153 #[error("projection error: {0}")]
154 Projection(String),
155
156 #[error("code generation error: {0}")]
157 Codegen(String),
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use crate::effects::{LabelId, RoleId};
164 use crate::identifiers::RoleName;
165
166 #[allow(dead_code)]
168 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
169 enum TestRole {
170 Alice,
171 Bob,
172 }
173
174 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
175 enum TestLabel {
176 Test,
177 }
178
179 impl LabelId for TestLabel {
180 fn as_str(&self) -> &'static str {
181 match self {
182 TestLabel::Test => "test",
183 }
184 }
185
186 fn from_str(label: &str) -> Option<Self> {
187 match label {
188 "test" => Some(TestLabel::Test),
189 _ => None,
190 }
191 }
192 }
193
194 impl RoleId for TestRole {
195 type Label = TestLabel;
196
197 fn role_name(&self) -> RoleName {
198 match self {
199 TestRole::Alice => RoleName::from_static("Alice"),
200 TestRole::Bob => RoleName::from_static("Bob"),
201 }
202 }
203 }
204
205 #[test]
206 fn test_module_structure() {
207 let _choreography: Option<Choreography> = None;
209 let _protocol: Option<Protocol> = None;
210 let _role: Option<Role> = None;
211 let _message_type: Option<MessageType> = None;
212
213 let _program: Option<Program<TestRole, String>> = None;
215 let _result: Option<ChoreoResult<()>> = None;
216 let _label: Option<TestLabel> = None;
217 }
218
219 #[test]
220 fn test_free_algebra_integration() {
221 use std::time::Duration;
222
223 let program = Program::<TestRole, String>::new()
225 .send(TestRole::Bob, "hello".to_string())
226 .recv::<String>(TestRole::Bob)
227 .choose(TestRole::Bob, TestLabel::Test)
228 .offer(TestRole::Bob)
229 .with_timeout(
230 TestRole::Bob,
231 Duration::from_millis(100),
232 Program::new().end(),
233 )
234 .parallel(vec![Program::new().end()])
235 .end();
236
237 assert_eq!(program.send_count(), 1);
239 assert_eq!(program.recv_count(), 1);
240 assert!(program.has_timeouts());
241 assert!(program.has_parallel());
242 }
243}