Struct lunatic::Process

source ·
pub struct Process<M, S = Bincode> { /* private fields */ }
Expand description

Processes are isolated units of compute.

In lunatic, all code runs inside processes. Processes run concurrently and communicate via message passing.

Lunatic’s processes should not be confused with operating system processes. Processes in lunatic are extremely lightweight in terms of memory and CPU (even compared to threads as used in many other programming languages). Because of this, it is not uncommon to have tens or even hundreds of thousands of processes running simultaneously.

The Process type allows us to spawn new processes from rust functions. There are two kinds of processes:

  1. Mailbox based processes
  2. Protocol based processes

They are differentiated by the second argument of the entry function.

Mailbox based processes

A mailbox process takes a Mailbox that can only receive messages of one type.

Example

let child = Process::spawn(1, |capture, mailbox: Mailbox<i32>| {
   assert_eq!(capture, 1);
   assert_eq!(mailbox.receive(), 2);
});

child.send(2);

Processes don’t share any memory and messages sent between them need to be serialized. By default, the Bincode serializer is used, but other serializers that implement the CanSerialize trait can be used instead. The serializer just needs to be added to the Mailbox type (e.g. Mailbox<i32, MessagePack>).

Processes can also be linked together using the spawn_link function. This means that if one of them fails (panics) the other will be killed too. It is always recommended to spawn linked processes when they depend on each other. That way we can avoid one process forever waiting on a message from another process that doesn’t exist anymore.

Protocol based processes

A protocol process takes a Protocol that can define a sequence of messages that will be exchanged between two processes. This is also known as a session type. The child will get a reference to the protocol and the parent will get a reference to the opposite protocol.

Example

type AddProtocol = Recv<i32, Recv<i32, Send<i32, End>>>;
let child = Process::spawn(1, |capture: i32, protocol: Protocol<AddProtocol>| {
    assert_eq!(capture, 1);
    let (protocol, a) = protocol.receive();
    let (protocol, b) = protocol.receive();
    let _ = protocol.send(capture + a + b);
});

let child = child.send(2);
let child = child.send(2);
let (_, result) = child.receive();
assert_eq!(result, 5);

The rust type system guarantees that the all messages are sent in the correct order and are of correct type. Code that doesn’t follow the protocol would not compile.

Same as the mailbox, the protocol based process can choose another serializer (e.g. Protocol<AddProtocol, MessagePack>).

If a protocol based process is dropped before the End state is reached, the drop will panic.

Implementations§

source§

impl<M, S> Process<M, S>

source

pub unsafe fn new(node_id: u64, process_id: u64) -> Self

Creates a new process reference from a node_id and process_id.

Safety

When creating a process from raw IDs you will need to manually specify the right types.

source

pub unsafe fn this() -> Self

Return reference to self.

Safety

The right type needs to be manually specified for the deserializer to know what messages to expect.

source

pub fn is_alive(&self) -> bool

Returns true for processes on the local node that are running.

Panics if called on a remote process.

source

pub fn spawn<C, T>(capture: C, entry: fn(_: C, _: T)) -> T::Processwhere S: CanSerialize<C> + CanSerialize<ProtocolCapture<C>>, T: IntoProcess<M, S> + NoLink,

Spawn a process.

source

pub fn spawn_node<C, T>( node_id: u64, capture: C, entry: fn(_: C, _: T) ) -> T::Processwhere S: CanSerialize<C> + CanSerialize<ProtocolCapture<C>>, T: IntoProcess<M, S> + NoLink,

Spawn a process on a remote node.

source

pub fn spawn_node_config<C, T>( node_id: u64, config: &ProcessConfig, capture: C, entry: fn(_: C, _: T) ) -> T::Processwhere S: CanSerialize<C> + CanSerialize<ProtocolCapture<C>>, T: IntoProcess<M, S> + NoLink,

Spawn a process on a remote node.

Spawn a linked process.

Spawn a linked process with a tag.

Allows the caller to provide a tag for the link.

source

pub fn spawn_config<C, T>( config: &ProcessConfig, capture: C, entry: fn(_: C, _: T) ) -> T::Processwhere S: CanSerialize<C> + CanSerialize<ProtocolCapture<C>>, T: IntoProcess<M, S> + NoLink,

Spawn a process with a custom configuration.

Spawn a linked process with a custom configuration.

Spawn a linked process with a custom configuration & provide tag for linking.

source

pub fn id(&self) -> u64

Returns the process ID for the local node.

source

pub fn node_id(&self) -> u64

Returns the node ID.

Link process to the one currently running.

Unlink processes from the caller.

source

pub fn kill(&self)

Kill this process

source

pub fn register<N: ProcessName>(&self, name: &N)

Register process under a name.

source

pub fn lookup<N: ProcessName + ?Sized>(name: &N) -> Option<Self>

Look up a process.

source§

impl<M, S> Process<M, S>where S: CanSerialize<M>,

source

pub fn send(&self, message: M)

Send a message to the process.

Panics

This function will panic if the received message can’t be serialized into M with serializer S.

source

pub fn send_after(&self, message: M, duration: Duration) -> TimerRef

Send a message to the process after the specified duration has passed.

Panics

This function will panic if the received message can’t be serialized into M with serializer S.

source

pub fn tag_send(&self, tag: Tag, message: M)

Send message to process with a specific tag.

Panics

This function will panic if the received message can’t be serialized into M with serializer S.

source

pub fn tag_send_after( &self, tag: Tag, message: M, duration: Duration ) -> TimerRef

Send a message to the process with a specific tag, after the specified duration has passed.

Panics

This function will panic if the received message can’t be serialized into M with serializer S.

Trait Implementations§

source§

impl<M, S> Clone for Process<M, S>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<M, S> Debug for Process<M, S>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'de, M, S> Deserialize<'de> for Process<M, S>

source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl<P, M, S, S2> From<Process<M, S>> for Protocol<P, S2>

source§

fn from(process: Process<M, S>) -> Self

Converts to this type from the input type.
source§

impl<M, S> Hash for Process<M, S>

source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl<M, S> PartialEq<Process<M, S>> for Process<M, S>

Processes are equal if their process id and node id are equal.

source§

fn eq(&self, other: &Self) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<M, S> Serialize for Process<M, S>

source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
source§

impl<M, S> Copy for Process<M, S>

source§

impl<M, S> Eq for Process<M, S>

Process equality comparison is an equivalence relation

Auto Trait Implementations§

§

impl<M, S> RefUnwindSafe for Process<M, S>where M: RefUnwindSafe, S: RefUnwindSafe,

§

impl<M, S> Send for Process<M, S>where M: Send, S: Send,

§

impl<M, S> Sync for Process<M, S>where M: Sync, S: Sync,

§

impl<M, S> Unpin for Process<M, S>where M: Unpin, S: Unpin,

§

impl<M, S> UnwindSafe for Process<M, S>where M: UnwindSafe, S: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> DeserializeOwned for Twhere T: for<'de> Deserialize<'de>,