rhai icon indicating copy to clipboard operation
rhai copied to clipboard

Projects using Rhai

Open stevedonovan opened this issue 7 years ago • 31 comments

Just a tracking issue for projects.

Apparently I've got the first published crate that uses Rhai as a dependency:

https://github.com/stevedonovan/findr

stevedonovan avatar Apr 07 '18 08:04 stevedonovan

Awesome! I like the idea of a find that doesn't have an arcane obscure syntax. Yep, you are the first person to actually have a crate using it published. Good job :D

luciusmagn avatar Apr 07 '18 08:04 luciusmagn

@luciusmagn We're considering using Rhai for a game project (https://www.github.com/veloren/game/). The team has a few questions about the language first though. Where is best to ask them?

zesterer avatar Jul 06 '18 08:07 zesterer

I'd say here, or you can write me an email at [email protected]. I am currently out of home, so it may take a while for me to respond

Dne pá 6. 7. 2018 10:48 uživatel Joshua Barretto [email protected] napsal:

@luciusmagn https://github.com/luciusmagn We're considering using Rhai for a game project (https://www.github.com/veloren/game/). The team has a few questions about the language first though. Where is best to ask them?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jonathandturner/rhai/issues/69#issuecomment-402970746, or mute the thread https://github.com/notifications/unsubscribe-auth/AIAzh6bJeD2eB_VIbrajwJi6iVse0VwYks5uDyRugaJpZM4TK_Rr .

luciusmagn avatar Jul 06 '18 09:07 luciusmagn

casbin-rs is also using rhai!

0x8f701 avatar Apr 09 '20 13:04 0x8f701

I consider using Rhai for a game too. But I'm in the planning process and far away from any code

Another option for scripting would be Mun, but this is also in an early state

MarkuBu avatar Apr 17 '20 11:04 MarkuBu

@MarkuBu my $0.02 worth - use Rhai if you want tight integration with lots of functionalities written in Rust. If you want to basically write your game logic in a scripting language, probably Lua is much more suited for this purpose.

schungx avatar Apr 17 '20 12:04 schungx

@schungx why? Because of the performance? I know that Lua is fast, even without the JIT

MarkuBu avatar Apr 17 '20 12:04 MarkuBu

Yes. Rhai is an AST-walking interpreter. It is never going to break any speed records. So use it where the majority of your application's time is not spend in the script.

schungx avatar Apr 17 '20 12:04 schungx

Ok, thanks.

MarkuBu avatar Apr 17 '20 13:04 MarkuBu

I'm looking for a scripting language to add dynamic helper support for my template engine handlebars-rust. By far Rhai seems to be a good fit because of its inter-operatability with rust data. I will be writing poc code recently and seeking for help with you.

sunng87 avatar Apr 22 '20 02:04 sunng87

No prob!

schungx avatar Apr 22 '20 09:04 schungx

FYI support for rhai script helper has been released in handlebars 3.1.0 with a feature flag script_helper https://github.com/sunng87/handlebars-rust/blob/master/examples/script.rs

sunng87 avatar Jun 03 '20 13:06 sunng87

I'm trying to integrate Rhai into my game but for the life of me I can't figure out how to pass a Vec of a custom Rust type (already registered with the engine) and access the indices from it.

I can successfully pass it but when the script tries to access any index it crashes.

Pebaz avatar Jan 14 '21 22:01 Pebaz

When you pass a Vec into Rhai, it treats it as a custom type. You're responsible for registering an API for use with that API. In your case, you'd want to register an indexer.

engine
    .register_type_with_name::<Vec<MyType>>("Vec<MyType>")
    .register_indexer_get_set(
        |v: &mut Vec<MyType>, i: INT| v[i],
        |v: &mut Vec<MyType>, i: INT, value: MyType| v[i] = value)
    .register_fn("len", |v: &mut Vec<MyType>| v.len() as INT)
    .register_get("len", |v: &mut Vec<MyType>| v.len() as INT)
    .register_fn("contains", |v: &mut Vec<MyType>, value: MyType| v.contains(&value))
    .register_fn("is_empty", |v: &mut Vec<MyType>| v.is_empty())
    .register_get("is_empty", |v: &mut Vec<MyType>| v.is_empty());

After a while it gets clumsy. You'd want to use a plugin module to define the API instead.

schungx avatar Jan 15 '21 01:01 schungx

Alternatively, you can convert the Vec<T> into a Rhai Array and it'll work with Rhai just fine.

// assuming 'my_vec' is 'Vec<T>'
let array: Dynamic = my_vec.into();

The catch is that a Rhai Array is dynamically typed, meaning that you cannot restrict it to hold only MyType.

schungx avatar Jan 15 '21 01:01 schungx

@schungx Thank you very much for your help this is what I needed!

Pebaz avatar Jan 15 '21 20:01 Pebaz

I'm using Rhai as a DSL for my memory profiler.

koute avatar Aug 17 '21 06:08 koute

We are using rhai in our new GraphQL router project: https://github.com/apollographql/router

The router has a "plugin" framework which allows customer to write plugins in rust which may inspect or modify the flow of data through the router. We have a rhai plugin, which exposes router functionality so that plugins can also be written in rhai. This is nice for our customers, since it's much simpler to write a rhai plugin than a rust plugin.

Support is deemed to be experimental at the moment, but our experience so far is good!

garypen avatar May 12 '22 10:05 garypen

This is interesting. Is your payload mostly binary-encoded or text-encoded (like JSON)?

Are you manipulating low-level transport streams with Rhai or pre-filled data objects?

BTW, it is usually simpler for the user to provide an overloaded version of a function that takes a string (as function name) in addition to one that takes an FnPtr. This way, the user can skip the Fn creation step. The implementation is usually simply to have the string version construct an FnPtr and then call the FnPtr version.

    let request_callback = Fn("process_request");
    service.map_request(request_callback);
    let response_callback = Fn("process_response");
    service.map_response(response_callback);

    // can also call like this
    service.map_request("process_request");
    service.map_response("process_response");

    // and the FnPtr versions will support this
    service.map_request(|req| { ... });
    service.map_response(|resp| { ... });

This is similar to early JavaScript style.

schungx avatar May 12 '22 10:05 schungx

It's text-encoded (JSON), so it's mainly about manipulating pre-filled data objects.

Your comment made me chuckle because I originally (before I found out about Fn()) was just calling functions by string representation. I can't make my mind up if that looks better or not, but I'll try it out in a few examples so people are aware it exists.

We are using closures in one of the examples in a soon to land PR...

garypen avatar May 12 '22 11:05 garypen

Your comment made me chuckle because I originally (before I found out about Fn()) was just calling functions by string representation. I can't make my mind up if that looks better or not, but I'll try it out in a few examples so people are aware it exists.

Why not both? I find Rhai's function overloading to be very useful in this regard, almost like writing JavaScript.

But you have to physically overload the function with a version that takes &str parameter in order for that to work, so it is essentially a duplicated API.

Another tip:

    // Leverage constants propagation to make scripts run faster
    const request_callback = Fn("process_request");
    service.map_request(request_callback);
    const response_callback = Fn("process_response");
    service.map_response(response_callback);

schungx avatar May 12 '22 13:05 schungx

We are using rhai in vSMTP, a mail transfer agent made with rust.

Instead of filtering emails with a standard configuration format (like json or toml) we use Rhai to make powerful rules for filtering, enabling you to execute behavior on specific email addresses, clients, ip addresses etc ...

We are constantly trying to optimize the "rule engine" (the part that handles rhai) because the server needs to be really fast. But with the help of the team & rhai's great docs we are getting there :)

ltabis avatar May 16 '22 14:05 ltabis

We are constantly trying to optimize the "rule engine" (the part that handles rhai) because the server needs to be really fast. But with the help of the team & rhai's great docs we are getting there :)

Let us know if you have an issue with this. The trick with performance is to avoid cloning like the plague, and sometimes it is not obvious.

You can also join the Discord channel for discussions.

schungx avatar May 16 '22 14:05 schungx

BTW, just another tip-up. In your docs, you can link to https://rhai.rs/book/ref for a "Language Reference" section that contains only the scripting language, not the Rust engine bits. It would be easier on your users.

schungx avatar May 16 '22 15:05 schungx

I'm using Rhai in https://github.com/YaLTeR/bxt-rs to script the goal and constraints for a brute-force optimizer. At first it was Lua (luajit), but then I couldn't figure out how to make it cross-compile out of the box on all system configurations that I care about, and tried Rhai as a pure-Rust option. Seems to work great so far; on the small scripts that I'm using it doesn't seem any slower than luajit.

YaLTeR avatar Sep 12 '22 00:09 YaLTeR

it doesn't seem any slower than luajit.

If you're not repeatedly running a script in a tight loop, then the JIT doesn't really show its power...

schungx avatar Sep 12 '22 03:09 schungx

During the optimization process normally the rest of the code takes much longer than the goal checking script, so yeah.

One performance bottleneck that I did hit with both luajit and Rhai is passing large arrays to the script (I guess specifically converting to luajit's tables or Rhai's Dynamic type). The script accepts either a single struct with a few fields (player data for the last state) or an array with several hundred of those structs (player data for all states). Ideally I'd unconditionally pass all states but it's quite slow to convert. Not sure how to improve this in a way that doesn't require writing manual field access or serialization code.

YaLTeR avatar Sep 12 '22 03:09 YaLTeR

An option is to wrap that data structure in an Rc<Vec<Rc<Item>>>. Then it is shared access and in general very very fast.

But then you'll have to register the relevant API's to access elements in the array (e.g. indexers) and fields access for Item. The array must hold Rc-wrapped values because you don't want to be copying items whenever you access an array slot - an indexer cannot return a ref mut to the parent data.

But for high performance work when you don't want to copy things, it is worth it.

schungx avatar Sep 12 '22 04:09 schungx

Others found via Used by:

  • https://github.com/ballerine-io/ballerine
  • https://github.com/rustic-rs/rustic
  • https://github.com/rabbit-digger/rabbit-digger-pro
  • https://github.com/markusmoenig/ForgedThoughts
  • https://github.com/markusmoenig/Eldiron
  • https://github.com/PikuseruConsole/pikuseru
  • https://github.com/Notgnoshi/generative
  • https://github.com/BrettMayson/HEMTT
  • https://github.com/mkeeter/fidget
  • https://github.com/phimuemue/openschafkopf
  • https://github.com/FyraLabs/anda
  • https://github.com/nervosnetwork/ckb
  • https://github.com/makspll/bevy_mod_scripting
  • https://github.com/zdz/ServerStatus-Rust
  • https://github.com/comtrya/comtrya
  • https://github.com/fermyon/bartholomew
  • https://github.com/cortesi/canopy
  • https://github.com/leshow/dhcpm
  • https://github.com/chaosprint/glicol
  • https://github.com/tikv/raft-engine
  • https://github.com/cargo-generate/cargo-generate

(Consider converting this issue to a Discussion, sticky it and link to it from docs.)

erlend-sh avatar Apr 08 '23 08:04 erlend-sh

I am using RHAI in https://rpgfx.com/ RPG Studio

ryankopf avatar Feb 17 '24 23:02 ryankopf