Hello World
In this chapter we will look at two simple programs that implement hello world in Ferrite.
Hello Protocol
A session type, a.k.a. a protocol, describes a communication protocol between two parties: a provider and a client. The provider offers a service as described by the session type, and the client consumes the provided service in a linear fashion.
In this example, we will define a simple Hello
protocol that has
the session type SendValue<String, End>
:
type Hello = SendValue<String, End>;
Our Hello
protocol pretty much self describe the communication protocol:
The provider would send a Rust String
value and then terminates. Conversely,
a client for Hello
would receive a Rust String
value, and then waits
for the provider to terminate.
The type SendValue<T, A>
defines a session type that sends a Rust value
T
, and then continues with the continuation session type A
. The type
End
defines a session type that simply terminates. When we combine both
SendValue
and End
to get SendValue<String, End>
, we are effectively
defining a session type that sends a Rust value of type String
, and then
continues as session type End
, which happens to simply terminates.
Hello World Provider
We first look at how a provider for the Hello
protocol can be implemented:
let hello_provider: Session<Hello> =
send_value("Hello World!".to_string(), terminate());
In the above example, we define a variable named hello_provider
with the Rust type Session<Hello>
. The Rust type Session<A>
denotes
a Ferrite program that is providing a session type A
. In this case,
hello_provider
is a Ferrite program that provides the Hello
protocol.
In the body of hello_provider
, we use the Ferrite functions send_value
and
terminate
to build up our Ferrite program. According to the Hello
protocol,
the first step hello_provider
needs to do is to send a String
value.
To do that, we create a Rust string "Hello World!".to_string()
, and then send
it by calling send_value("Hello World!".to_string(), ... )
.
Other than the "Hello World!"
string in the first argument, send_value
also
expects a second argument, which is the continuation after our string value
is sent. In our case, The continuation session type of SendValue<String, End>
is End
. As such, there is nothing left to do other than terminating the Ferrite
program, which we can do it by calling terminate()
.
Run Session
Up to this point, we have only defined a Ferrite program named hello_provider
,
but we have not yet execute the program. To run it, we would typically need to
pair it with a client that consumes the offered protocol Hello
. However
Ferrite provides a special case for Ferrite programs that offer the session types
SendValue<T, End>
. So we can run our hello_provider
by calling
run_session_with_result
:
let result: String = run_session_with_result(hello_provider).await;
println!("{}", result);
Ferrite provides run_session_with_result
as a default way of handling
Ferrite programs offering the session type SendValue<T, End>
,
because they are trivial to handle.
This can be done by receiving the Rust value sent from the provider,
waits for the provider to terminate, and then returns to the caller.
The function is an async function, so we have to use the .await
syntax to wait for Ferrite to run the program and return the results.
After getting the result back, we can print the received string using
println!
, and we can expect "Hello World!"
to be printed at this point.
Full Hello World Program
Putting everything together, our first hello world program is written as follows:
use ferrite_session::prelude::*;
type Hello = SendValue<String, End>;
#[tokio::main]
async fn main()
{
let hello_provider: Session<Hello> =
send_value("Hello World!".to_string(), terminate());
let result: String = run_session_with_result(hello_provider).await;
println!("{}", result);
}
Our Rust program defines an async main
function using the #[tokio::main]
attribute provided by tokio
. Inside the main body, we define our provider
Ferrite program as hello_provider
, and then immediately run it using
run_session_with_result
. Finally we get back the result string and print it
to the terminal.