1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//! [`Aurum`](crate)'s base functionality: spawning actors, binding sockets, forging actor
//! references and sending messages.
//!
//! ### Unifying Types
//! The programmer needs to enumerate to [`Aurum`](crate) all types of messages actors
//! can receive thoughout their whole application. All applications using [`Aurum`](crate) must use
//! exactly one enumeration (henceforth referred to as the
//! [`UnifiedType`](crate::core::UnifiedType)). No more, no less. Due to the way the
//! [`UnifiedType`](crate::core::UnifiedType)
//! is handled, it is still possible to build and use many independent libraries on top of
//! [`Aurum`](crate). The unified type is constructed with the [`unify`](crate::unify) macro. See
//! the [`unify`](crate::unify) macro for an in-depth discussion on how it works and why we need it.
//!
//! ### Actor References
//! Actor References come in 2 flavors: [`ActorRef`](crate::core::ActorRef) and
//! [`LocalRef`](crate::core::LocalRef). [`ActorRef`](crate::core::ActorRef) is
//! location-transparent, it accepts both local and remote messages.
//! [`LocalRef`](crate::core::LocalRef) is for local messages only. An
//! [`ActorRef`](crate::core::ActorRef) requires 2 generic parameters: the
//! [`UnifiedType`](crate::core::UnifiedType) and the interface (not the root message type).
//!
//! ### Creating a Message Type
//! Use [`AurumInterface`](crate::AurumInterface) to create message types for actors.
//!
//! ```ignore
//! #[derive(AurumInterface)]
//! #[aurum(local)]
//! enum MyMsgType {
//!   #[aurum]
//!   MyStringInterface(String),
//!   #[aurum(local)]
//!   MyNonserializableInterface(&'static str),
//!   MyOtherMsg(usize),
//! }
//! ```
//!
//! ### A [`unify`](crate::unify) Example
//! The [`unify`](crate::unify) macro is responsible for constructing the
//! [`UnifiedType`](crate::core::UnifiedType) and implementing traits for it. Arguments must include
//! all message types (whether they are to be remotely accessed or not), and types used for remote
//! interfaces. [`unify`](crate::unify) creates a type, so it should only be called once in a single
//! application.
//!
//! ```ignore
//! unify! { MyUnifiedType =
//!   MyMsgType |
//!   MyOtherMsgType |
//!   MsgTypeForSomeThirdPartyLibrary
//!   ;
//!   String |
//!   InterfaceForSomeThirdPartyLibrary
//! }
//! ```
//!
//! ### Spawning Actors
//! To spawn actors, you need to create a [`Node`](crate::core::Node). You also need an initial
//! instance of whatever type implements the actor trait, the string part of the actor’s name,
//! whether the actor should be double-threaded and whether a reference to it should be sent to the
//! registry.
//!
//! ```ignore
//! struct MyActor {
//!   first: String,
//!   second: usize
//! }
//! //Don’t forget this annotation
//! #[async_trait]
//! impl Actor<MyUnifiedType, MyMsgType> for MyActor { ... }
//!
//! let mut config = NodeConfig::default();
//! config.socket = Socket::new(...);
//! let node = Node::<MyUnifiedType>::new_sync(config);
//! let actor = MyActor {
//!   first: "hi  there".to_string(),
//!   second: 4214
//! };
//! node.spawn(
//!   false, // Double -threaded?1
//!   actor,
//!   "my-very-cool-actor".to_string(),
//!   true, // Register
//! );
//! ```
//!
//! ### Sending Messages
//! An [`ActorId`] is used to uniquely identify an actor in the registry of a [`Node`]. A
//! [`Destination`] contains an [`ActorId`] and information on which interface it is sending
//! messages to. A [`Destination`] can be forged, just like an [`ActorRef`]. The combination of a
//! [`Socket`] and a [`Destination`] consitutes a complete actor address. You can construct and use
//! these two components indepentently.
//!
//! ```ignore
//! let socket = Socket::new(...);
//!
//! // Forging a Destination
//! let dest = Destination::<MyUnifiedType, String>::new::<MyMsgType>(
//!   "my-very-cool-actor".to_string()
//! );
//! let msg = "My name is Baloo".to_string();
//! let ser = UdpSerial::new(&dest, &msg)
//! node.udp(&socket, &ser);
//!
//! // Forging an ActorRef
//! let forged = ActorRef::<MyUnifiedType, String>::new::<MyMsgType>(
//!   "my-very-cool-actor".to_string(),
//!   socket.clone()
//! );
//! forged.remote_send(&node, &msg) ;
//! ```
//!
//! You can send a message unreliably using [`Node.udp_select`](crate::core::Node::udp_select).
//! How messages are dropped or delayed depends on a [`FailureMode`](crate::testkit::FailureMode)
//! and a [`FailureConfigMap`](crate::testkit::FailureConfigMap).
//!
//! ```ignore
//! // Doesn’t have to be a const
//! const MODE: FailureMode = FailureMode :: Message ;
//! let mut fail_map = FailureConfigMap::default();
//! // Make some changes to fail_map...
//! let msg: String = "My name is Baloo".to_string();
//! let ser = UdpSerial::new(&dest, &msg);
//! node.udp_select(&socket , &ser, MODE, &fail_map) ;
//! ```
//!
//! ### Logging
//! Define a [`LogLevel`] for you environment, and call one of these log macros. They all have the same
//! arguments.
//!
//! - [`trace`](crate::trace)
//! - [`debug`](crate::debug)
//! - [`info`](crate::info)
//! - [`warn`](crate::warn)
//! - [`error`](crate::error)
//! - [`fatal`](crate::fatal)
//!
//! The logger is accessible from the node, but there is nothing stopping you from spawning your own
//! logger, it’s just an actor. The log messages can be anything that implements
//! [`Display`](std::fmt::Display). The argument is turned into a trait object in the macro body.
//!
//! ```no_run
//! use aurum_actors::{trace, warn};
//! use aurum_actors::testkit::LogLevel;
//! # use aurum_actors::{unify, AurumInterface};
//! # use aurum_actors::core::{Node, NodeConfig};
//! # 
//! # #[derive(AurumInterface)]
//! # #[aurum(local)]
//! # enum Unit {}
//! # unify!(Foo = Unit;);
//! # let node = Node::<Foo>::new_sync(NodeConfig::default()).unwrap();
//! 
//! // Doesn’t have to be a const
//! const LEVEL: LogLevel = LogLevel::Debug ;
//! // Not logged, the level is Debug, which is above Trace
//! trace!(LEVEL, &node, "kelp") ;
//! // This is logged, Warn is above Debug
//! warn!(LEVEL, &node, "sharks") ;
//! ```

use crate::testkit::LogLevel;

mod actor;
mod actor_ref;
mod actor_tasks_timeout;
mod actor_tasks_unit;
mod node;
mod packets;
mod registry;
mod remoting;
mod udp_receiver;
mod udp_serial;
mod unification;

pub const LOG_LEVEL: LogLevel = LogLevel::Error;

#[rustfmt::skip]
pub(in crate::core) use {
  actor::local_actor_msg_convert, 
  actor::ActorMsg,
  actor_tasks_unit::unit_secondary, 
  actor_tasks_unit::unit_single, 
  packets::DatagramHeader, 
  packets::MessageBuilder, 
  packets::deserialize,
  packets::serialize,
  registry::Registry, 
  registry::SerializedRecvr,
  remoting::DestinationUntyped,
  actor_tasks_timeout::run_single_timeout,
  udp_receiver::udp_receiver,
};

// Needed for macros
#[rustfmt::skip]
#[doc(hidden)]
pub use {
  actor::LocalActorMsg,
  registry::RegistryMsg,
  packets::deserialize_msg,
  packets::DeserializeError, 
  packets::Interpretations,
};

// Actual public interface
#[rustfmt::skip]
pub use {
  actor::Actor, 
  actor::ActorContext, 
  actor::ActorId, 
  actor::ActorSignal,
  actor::TimeoutActor,
  actor_ref::ActorRef, 
  actor_ref::LocalRef,
  remoting::Destination,
  remoting::Host, 
  remoting::Socket,
  node::Node,
  node::NodeConfig,
  udp_serial::UdpSerial,
  unification::Case, 
  unification::RootMessage, 
  unification::UnifiedType,
};