\section{Messages}

Messages in \lib are type-erased, copy-on-write tuples.
The actual message type itself is usually hidden, as actors use pattern matching to decompose messages automatically.
However, the classes \lstinline^message^ and \lstinline^message_builder^ allow more advanced usage scenarios than only sending data from one actor to another.

\subsection{Class \texttt{message}}

{\small
\begin{tabular*}{\textwidth}{m{0.45\textwidth}m{0.5\textwidth}}
  \multicolumn{2}{m{\linewidth}}{\large{\textbf{Member functions}}\vspace{3pt}} \\
  \\
  \multicolumn{2}{l}{\textbf{Observers}\vspace{3pt}} \\
  \hline
  \lstinline^bool empty()^ & Returns whether this message is empty \\
  \hline
  \lstinline^size_t size()^ & Returns the size of this message \\
  \hline
  \lstinline^const void* at(size_t p)^ & Returns a const pointer to the element at position \lstinline^p^ \\
  \hline
  \lstinline^template <class T>^ \lstinline^const T& get_as(size_t p)^ & Returns a const ref. to the element at position \lstinline^p^ \\
  \hline
  \lstinline^template <class T>^ \lstinline^bool match_element(size_t p)^ & Returns whether the element at position \lstinline^p^ has type \lstinline^T^ \\
  \hline
  \lstinline^template <class... Ts>^ \lstinline^bool match_elements()^ & Returns whether this message has the types \lstinline^Ts...^ \\
  \hline
  \lstinline^message drop(size_t n)^ & Creates a new message with all but the first \lstinline^n^ values \\
  \hline
  \lstinline^message drop_right(size_t n)^ & Creates a new message with all but the last \lstinline^n^ values \\
  \hline
  \lstinline^message take(size_t n)^ & Creates a new message from the first \lstinline^n^ values \\
  \hline
  \lstinline^message take_right(size_t n)^ & Creates a new message from the last \lstinline^n^ values \\
  \hline
  \lstinline^message slice(size_t p, size_t n)^ & Creates a new message from \lstinline^[p, p + n)^ \\
  \hline
  \lstinline^message slice(size_t p, size_t n)^ & Creates a new message from \lstinline^[p, p + n)^ \\
  \hline
  \lstinline^message extract(message_handler)^ & See \S\,\ref{Sec::Messages::Extract} \\
  \hline
  \lstinline^message extract_opts(...)^ & See \S\,\ref{Sec::Messages::ExtractOpts} \\
  \hline
  \\
  \multicolumn{2}{l}{\textbf{Modifiers}\vspace{3pt}} \\
  \hline
  \lstinline^optional<message>^ \lstinline^apply(message_handler f)^ & Returns \lstinline^f(*this)^ \\
  \hline
  \lstinline^void* mutable_at(size_t p)^ & Returns a pointer to the element at position p \\
  \hline
  \lstinline^template <class T>^ \lstinline^T& get_as_mutable(size_t p)^ & Returns a reference to the element at position p \\
  \hline
\end{tabular*}
}

\clearpage
\subsection{Class \texttt{message\_builder}}

{\small
\begin{tabular*}{\textwidth}{m{0.45\textwidth}m{0.5\textwidth}}
  \multicolumn{2}{m{\linewidth}}{\large{\textbf{Member functions}}\vspace{3pt}} \\
  \\
  \multicolumn{2}{l}{\textbf{Constructors}\vspace{3pt}} \\
  \hline
  \lstinline^()^ & Creates an empty message builder \\
  \hline
  \lstinline^template <class Iter>^ \lstinline^(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^ \\
  \hline
  \\
  \multicolumn{2}{l}{\textbf{Observers}\vspace{3pt}} \\
  \hline
  \lstinline^bool empty()^ & Returns whether this message is empty \\
  \hline
  \lstinline^size_t size()^ & Returns the size of this message \\
  \hline
  \lstinline^message to_message(	)^ & Converts the buffer to an actual message object \\
  \hline
  \lstinline^template <class T>^ \lstinline^append(T val)^ & Adds \lstinline^val^ to the buffer \\
  \hline
  \lstinline^template <class Iter>^ \lstinline^append(Iter first, Iter last)^ & Adds all elements from range \lstinline^[first, last)^ \\
  \hline
  \lstinline^message extract(message_handler)^ & See \S\,\ref{Sec::Messages::Extract} \\
  \hline
  \lstinline^message extract_opts(...)^ & See \S\,\ref{Sec::Messages::ExtractOpts} \\
  \hline
  \\
  \multicolumn{2}{l}{\textbf{Modifiers}\vspace{3pt}} \\
  \hline
  \lstinline^optional<message>^ \lstinline^apply(message_handler f)^ & Returns \lstinline^f(*this)^ \\
  \hline
  \lstinline^message move_to_message()^ & Transfers ownership of its data to the new message \textbf{Warning}: this function leaves the builder in an \emph{invalid state}, i.e., calling any member function on it afterwards is undefined behavior \\
  \hline
\end{tabular*}
}

\clearpage
\subsection{Extracting}
\label{Sec::Messages::Extract}

The member function \lstinline^message::extract^ removes matched elements from a message. x
Messages are filtered by repeatedly applying a message handler to the greatest remaining slice, whereas slices are generated in the sequence \lstinline^[0, size)^, \lstinline^[0, size-1)^, \lstinline^...^, \lstinline^[1, size-1)^, \lstinline^...^, \lstinline^[size-1, size)^.
Whenever a slice is matched, it is removed from the message and the next slice starts at the same index on the reduced message.

For example:

\begin{lstlisting}
auto msg = make_message(1, 2.f, 3.f, 4);
// remove float and integer pairs
auto msg2 = msg.extract({
  [](float, float) { },
  [](int, int) { }
});
assert(msg2 == make_message(1, 4));
\end{lstlisting}

Step-by-step explanation:

\begin{itemize}
  \item Slice 1: \lstinline^(1, 2.f, 3.f, 4)^, no match
  \item Slice 2: \lstinline^(1, 2.f, 3.f)^, no match
  \item Slice 3: \lstinline^(1, 2.f)^, no match
  \item Slice 4: \lstinline^(1)^, no match
  \item Slice 5: \lstinline^(2.f, 3.f, 4)^, no match
  \item Slice 6: \lstinline^(2.f, 3.f)^, \emph{match}; new message is \lstinline^(1, 4)^
  \item Slice 7: \lstinline^(4)^, no match
\end{itemize}

Slice 7 is \lstinline^(4)^, i.e., does not contain the first element, because the match on slice 6 occurred at index position 1. The function \lstinline^extract^ iterates a message only once, from left to right.
The returned message contains the remaining, i.e., unmatched, elements.

\clearpage
\subsection{Extracting Command Line Options}
\label{Sec::Messages::ExtractOpts}

The class \lstinline^message^ also contains a convenience interface to \lstinline^extract^ for parsing command line options: the member function \lstinline^extract_opts^.

\begin{lstlisting}
int main(int argc, char** argv) {
  uint16_t port;
  string host = "localhost";
  auto res = message_builder(argv + 1, argv + argc).extract_opts({
    {"port,p", "set port", port},
    {"host,H", "set host (default: localhost)", host},
    {"verbose,v", "enable verbose mode"}
  });
  if (! res.error.empty()) {
    // read invalid CLI arguments
    cerr << res.error << endl;
    return 1;
  }
  if (res.opts.count("help") > 0) {
    // CLI arguments contained "-h", "--help", or "-?" (builtin);
    cout << res.helptext << endl;
    return 0;
  }
  if (! res.remainder.empty()) {
    // res.remainder stors all extra arguments that weren't consumed
  }
  if (res.opts.count("verbose") > 0) {
    // enable verbose mode
  }
  // ...
}

/*
Output of ./program_name -h:

Allowed options:
  -p [--port] arg  : set port
  -H [--host] arg  : set host (default: localhost)
  -v [--verbose]   : enable verbose mode
*/
\end{lstlisting}
