#![allow(
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::must_use_candidate
)]
pub mod ast;
pub mod compiler;
pub mod effects;
pub mod extensions;
pub mod heap;
pub mod identifiers;
pub mod testing;
pub mod topology;
pub mod tracing;
pub mod util;
pub use util::{SystemClock, SystemRng};
pub use identifiers::{Endpoint as TopologyEndpoint, Namespace, Region, RoleName};
pub use ast::{Choreography, MessageType, Protocol, Role};
pub use compiler::generate_effects_protocol;
pub use compiler::{
create_standard_extension_parser, format_choreography, format_choreography_str,
format_choreography_with_config, ExtensionParseError, ExtensionParser, ExtensionParserBuilder,
GrammarComposer, GrammarComposerBuilder, GrammarCompositionError, PrettyConfig,
};
pub use effects::middleware::{Metrics, Retry, Trace};
pub use effects::NoOpHandler;
pub use effects::{
interpret, validate_handler_contract_profile, validated_contract_profile, ChoreoHandler,
ChoreoHandlerExt, ChoreoResult, ChoreographyError, DeliveryModel, DocumentedHandlerContract,
Effect, Endpoint, ExtensionDispatchContract, ExtensionDispatchMode, HandlerContractProfile,
HandlerContractTier, HandlerContractViolation, InterpretResult, InterpreterState, LabelId,
MessageTag, Program, ProgramBuilder, ProgramMessage, ProtocolSemanticContract, RetryPolicy,
RoleId, TimeoutPolicy, TransportPolicyContract,
};
pub use effects::{InMemoryHandler, RecordedEvent, RecordingHandler};
pub use effects::{TelltaleEndpoint, TelltaleHandler, TelltaleSession};
pub use extensions::{
CodegenContext, ExtensionRegistry, ExtensionValidationError, GrammarExtension, ParseContext,
ParseError, ProjectionContext, ProtocolExtension, StatementParser,
};
pub use topology::{
parse_topology, validate_transport_contract_profile, validated_transport_contract_profile,
ByteMessage, DocumentedTransportContract, InMemoryChannelTransport, Location, ParsedTopology,
RoleFamilyConstraint, RoleFamilyConstraintError, Topology, TopologyBuilder, TopologyConstraint,
TopologyError, TopologyHandler, TopologyHandlerBuilder, TopologyLoadError, TopologyMode,
TopologyParseError, TopologyValidation, Transport, TransportContractProfile,
TransportContractTier, TransportContractViolation, TransportError, TransportFactory,
TransportMessage, TransportOperationalContract, TransportResult, TransportSemanticContract,
TransportStartupMode, TransportType,
};
pub use util::{spawn, spawn_local};
pub use heap::{
merkle_node_hash, nullifier_leaf_hash, resource_leaf_hash, CanonicalHeapEncoder,
CanonicalHeapEncoding, ChannelState, DefaultHeapHasher, Direction, Hasher, Heap,
HeapCommitment, HeapError, MerkleProof, MerkleTree, Message as HeapMessage, MessagePayload,
ProofStep, Resource, ResourceId, HEAP_ENCODING_MAGIC, HEAP_ENCODING_VERSION,
};
pub use testing::{
AsyncClock, BlockedOn, Checkpoint, Clock, InMemoryTransport, MockClock, NullObserver,
ProtocolEnvelope, ProtocolObserver, ProtocolStateMachine, RecordingObserver, Rng, SeededRng,
SimulatedTransport, StepInput, StepOutput, WallClock,
};
pub use telltale_macros::tell;
pub use telltale_types::{ChannelCapacity, MessageLenBytes, QueueCapacity};
#[doc(hidden)]
pub mod unstable {
pub use crate::extensions::{CodegenContext, ParseContext, ProjectionContext, StatementParser};
}
pub fn parse_and_generate_with_extensions(
input: &str,
extension_registry: &ExtensionRegistry,
) -> std::result::Result<proc_macro2::TokenStream, CompilationError> {
use compiler::codegen::generate_choreography_code_with_extensions;
use compiler::parser::parse_choreography_str_with_extensions;
use compiler::projection::project;
let (choreography, extensions) =
parse_choreography_str_with_extensions(input, extension_registry)
.map_err(CompilationError::Parse)?;
choreography
.validate()
.map_err(|e| CompilationError::Validation(e.to_string()))?;
let mut local_types = Vec::new();
for role in &choreography.roles {
let local_type = project(&choreography, role)
.map_err(|e| CompilationError::Projection(e.to_string()))?;
local_types.push((role.clone(), local_type));
}
let generated_code =
generate_choreography_code_with_extensions(&choreography, &local_types, &extensions);
Ok(generated_code)
}
pub fn compile_choreography_with_extensions(
input: &str,
) -> std::result::Result<proc_macro2::TokenStream, CompilationError> {
let registry = ExtensionRegistry::with_builtin_extensions();
parse_and_generate_with_extensions(input, ®istry)
}
pub fn parse_choreography_with_extensions(
input: &str,
extension_registry: &ExtensionRegistry,
) -> std::result::Result<(Choreography, Vec<Box<dyn ProtocolExtension>>), CompilationError> {
use compiler::parser::parse_choreography_str_with_extensions;
parse_choreography_str_with_extensions(input, extension_registry)
.map_err(CompilationError::Parse)
}
#[derive(Debug, thiserror::Error)]
pub enum CompilationError {
#[error("parse error: {0}")]
Parse(#[from] compiler::parser::ParseError),
#[error("validation error: {0}")]
Validation(String),
#[error("projection error: {0}")]
Projection(String),
#[error("code generation error: {0}")]
Codegen(String),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::effects::{LabelId, RoleId};
use crate::identifiers::RoleName;
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
enum TestRole {
Alice,
Bob,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
enum TestLabel {
Test,
}
impl LabelId for TestLabel {
fn as_str(&self) -> &'static str {
match self {
TestLabel::Test => "test",
}
}
fn from_str(label: &str) -> Option<Self> {
match label {
"test" => Some(TestLabel::Test),
_ => None,
}
}
}
impl RoleId for TestRole {
type Label = TestLabel;
fn role_name(&self) -> RoleName {
match self {
TestRole::Alice => RoleName::from_static("Alice"),
TestRole::Bob => RoleName::from_static("Bob"),
}
}
}
#[test]
fn test_module_structure() {
let _choreography: Option<Choreography> = None;
let _protocol: Option<Protocol> = None;
let _role: Option<Role> = None;
let _message_type: Option<MessageType> = None;
let _program: Option<Program<TestRole, String>> = None;
let _result: Option<ChoreoResult<()>> = None;
let _label: Option<TestLabel> = None;
}
#[test]
fn test_free_algebra_integration() {
use std::time::Duration;
let program = Program::<TestRole, String>::new()
.send(TestRole::Bob, "hello".to_string())
.recv::<String>(TestRole::Bob)
.choose(TestRole::Bob, TestLabel::Test)
.offer(TestRole::Bob)
.with_timeout(
TestRole::Bob,
Duration::from_millis(100),
Program::new().end(),
)
.parallel(vec![Program::new().end()])
.end();
assert_eq!(program.send_count(), 1);
assert_eq!(program.recv_count(), 1);
assert!(program.has_timeouts());
assert!(program.has_parallel());
}
}