(.using
  [library
   [lux {"-" if loop}
    ["$" documentation {"+" documentation:}]
    [data
     [text {"+" \n}
      ["%" format {"+" format}]]]
    [macro
     ["[0]" template]]]]
  [\\library
   ["[0]" /]])

(documentation: (/.Actor state)
  "An entity that can react to messages (mail) sent to it concurrently.")

(documentation: (/.Mail state)
  "A one-way message sent to an actor, without expecting a reply.")

(documentation: (/.Obituary state)
  "Details on the death of an actor.")

(documentation: (/.Behavior input state)
  "An actor's behavior when mail is received and when a fatal error occurs.")

(documentation: /.spawn!
  "Given a behavior and initial state, spawns an actor and returns it.")

(documentation: /.obituary
  "Await for an actor to stop working.")

(documentation: /.mail!
  "Send mail to an actor.")

(documentation: (/.Message state output)
  "A two-way message sent to an actor, expecting a reply.")

(documentation: /.tell!
  "Communicate with an actor through message-passing.")

(documentation: /.default
  "Default actor behavior.")

(documentation: /.poison!
  (format "Kills the actor by sending mail that will kill it upon processing,"
          \n "but allows the actor to handle previous mail."))

(with_expansions [<examples> (as_is (actor: .public (stack a)
                                      (List a)

                                      ((on_mail mail state self)
                                       (do (try.with async.monad)
                                         [.let [_ (debug.log! "BEFORE")]
                                          output (mail state self)
                                          .let [_ (debug.log! "AFTER")]]
                                         (in output)))

                                      (message: .public (push [value a] state self)
                                        (List a)
                                        (let [state' {.#Item value state}]
                                          (async.resolved {try.#Success [state' state']}))))

                                    (actor: .public counter
                                      Nat

                                      (message: .public (count! [increment Nat] state self)
                                        Any
                                        (let [state' (n.+ increment state)]
                                          (async.resolved {try.#Success [state' state']})))

                                      (message: .public (read! state self)
                                        Nat
                                        (async.resolved {try.#Success [state state]}))))]
  (documentation: /.actor:
    (format "Defines a named actor, with its behavior and internal state."
            \n "Messages for the actor must be defined after the on_mail handler.")
    [<examples>])

  (documentation: /.actor
    (format "Defines an anonymous actor, with its behavior and internal state."
            \n "Messages for the actor must be defined after the on_mail handler.")
    [(actor [Nat
             123]
            ((on_mail message state self)
             (message (++ state) self)))])

  (documentation: /.message:
    (format "A message can access the actor's state through the state parameter."
            \n "A message can also access the actor itself through the self parameter."
            \n "A message's output must be an async containing a 2-tuple with the updated state and a return value."
            \n "A message may succeed or fail (in case of failure, the actor dies).")
    [<examples>]))

(documentation: /.Stop
  "A signal to stop an actor from observing a channel.")

(documentation: /.observe!
  (format "Use an actor to observe a channel by transforming each datum"
          \n "flowing through the channel into mail the actor can process."
          \n "Can stop observing the channel by executing the Stop value."))

(.def: .public documentation
  (.List $.Module)
  ($.module /._
            "The actor model of concurrency."
            [..Actor
             ..Mail
             ..Obituary
             ..Behavior
             ..spawn!
             ..obituary
             ..mail!
             ..Message
             ..tell!
             ..default
             ..poison!
             ..actor:
             ..actor
             ..message:
             ..Stop
             ..observe!
             ($.default /.poisoned)
             ($.default /.dead)
             ($.default /.alive?)
             ($.default /.obituary')]
            []))
