Skip to main content

rivescript_core/macros/
mod.rs

1//! Traits and types for RiveScript Object Macros.
2
3use std::collections::HashMap;
4
5use async_trait::async_trait;
6
7/// Proxy is given as the first argument to RiveScript object macro functions.
8///
9/// It stands in as a 'proxy' for the master RiveScript struct. In most RiveScript
10/// implementations (in other programming languages), object macros receive a
11/// pointer to RiveScript as their first parameter so that they can get/set user
12/// variables or manipulate the inner state of the bot to varying degrees.
13///
14/// In Rust, it is not possible to give a mutable borrow of RiveScript to the
15/// object macros. Instead, the Proxy stands in for RiveScript and exposes a
16/// subset of useful function calls.
17///
18/// Functions like get_uservar should proxy through and get the live value from
19/// the RiveScript struct. Functions like set_uservar should cache or 'stage'
20/// the updates (e.g. using an internal HashMap), and return those values if
21/// a subsequent get function asks for them.
22///
23/// Object macros return their final response via the Proxy.finish() method,
24/// which (in the SubroutineResult) carries the staged writes to user variables
25/// back out so the master RiveScript struct can commit them all after the
26/// subroutine has returned.
27///
28/// For object macro subroutines written in Rust, the concrete implementation
29/// of this trait can be found in rivescript::macros::proxy::Proxy.
30#[async_trait]
31pub trait Proxy: Send + Sync {
32    fn current_username(&self) -> String;
33    async fn set_uservar(&mut self, username: &str, name: &str, value: &str) -> Result<bool, String>;
34    async fn get_uservar(&self, username: &str, name: &str) -> String;
35    async fn get_uservars(&self, username: &str) -> HashMap<String, String>;
36    fn set_variable(&mut self, name: &str, value: &str);
37    fn get_variable(&self, name: &str) -> String;
38    fn finish(&mut self, output: String) -> Result<SubroutineResult, String>;
39}
40
41/// SubroutineResult is the return value from object macro subroutines,
42/// especially those written natively in Rust.
43///
44/// Its job is to carry the text output of the object macro, along with any
45/// 'staged' user or bot variables that the macro wanted to update.
46#[derive(Debug)]
47pub struct SubroutineResult {
48    pub output: String,
49    pub staged_user_vars: HashMap<String, String>,
50    pub staged_bot_vars: HashMap<String, String>,
51}
52
53/// # Foreign Programming Language Object Macros
54///
55/// The LanguageLoader trait enables you to define a custom programming-language
56/// handler for RiveScript Object Macros written in languages other than Rust.
57///
58/// For example, a RiveScript document might define an object macro written
59/// in JavaScript like so:
60///
61/// ```rivescript
62/// > object reverse javascript
63///     let str = args.join(" ");
64///     return str.split('').reverse().join('');
65/// < object
66///
67/// + reverse *
68/// - "<star>" spelled backwards is "<call>reverse <star></call>."
69/// ```
70///
71/// The load() function will receive the name of the object macro along with its
72/// source code (as lines of text). Your LanguageLoader might then parse and
73/// evaluate the code using your backing runtime or VM.
74///
75/// The call() function is invoked when a named object macro has been called via
76/// the `<call>` tag in a RiveScript reply. The `name` is the name of the object
77/// macro and the `args` are the parameters (using shell-style quoting rules, so
78/// a "quoted string" would come as one item of the `Vec<String>`).
79#[async_trait]
80pub trait LanguageLoader: Send + Sync {
81    fn load(&mut self, name: &str, code: Vec<String>) -> Result<bool, String>;
82    async fn call(&self, proxy: &dyn Proxy, name: &str, args: Vec<String>) -> Result<SubroutineResult, String>;
83}