Custom Type Indexers

A custom type can also expose an indexer by registering an indexer function.

A custom type with an indexer function defined can use the bracket notation to get a property value:

object [ index ]

Like property getters/setters, indexers take a &mut reference to the first parameter.

They also take an additional parameter of any type that serves as the index within brackets.

Indexers are disabled when the no_index feature is used.

Engine APIFunction signature(s)
(T: Clone = custom type,
X: Clone = index type,
V: Clone = data type)
Can mutate T?
register_indexer_getFn(&mut T, X) -> Vyes, but not advised
register_indexer_setFn(&mut T, X, V)yes
register_indexer_get_setgetter: Fn(&mut T, X) -> V
setter: Fn(&mut T, X, V)
yes, but not advised in getter
register_indexer_get_resultFn(&mut T, X) -> Result<Dynamic, Box<EvalAltResult>>yes, but not advised
register_indexer_set_resultFn(&mut T, X, V) -> Result<(), Box<EvalAltResult>>yes

By convention, index getters are not supposed to mutate the custom type, although there is nothing that prevents this mutation.

IMPORTANT: Rhai does NOT support normal references (i.e. &T) as parameters.

Cannot Override Arrays, Object Maps and Strings

For efficiency reasons, indexers cannot be used to overload (i.e. override) built-in indexing operations for arrays, object maps and strings.

Attempting to register indexers for an array, object map or string panics.

Examples


#![allow(unused)]
fn main() {
#[derive(Clone)]
struct TestStruct {
    fields: Vec<i64>
}

impl TestStruct {
    // Remember &mut must be used even for getters
    fn get_field(&mut self, index: String) -> i64 {
        self.fields[index.len()]
    }
    fn set_field(&mut self, index: String, value: i64) {
        self.fields[index.len()] = value
    }

    fn new() -> Self {
        Self { fields: vec![1, 2, 3, 4, 5] }
    }
}

let mut engine = Engine::new();

engine
    .register_type::<TestStruct>()
    .register_fn("new_ts", TestStruct::new)
    // Short-hand: .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
    .register_indexer_get(TestStruct::get_field)
    .register_indexer_set(TestStruct::set_field);

let result = engine.eval::<i64>(
                r#"
                    let a = new_ts();
                    a["xyz"] = 42;                  // these indexers use strings
                    a["xyz"]                        // as the index type
                "#
)?;

println!("Answer: {}", result);                     // prints 42
}