rhaiscript / rhai

Rhai - An embedded scripting language for Rust.
https://crates.io/crates/rhai
Apache License 2.0
3.73k stars 175 forks source link

Projects using Rhai #69

Open stevedonovan opened 6 years ago

stevedonovan commented 6 years ago

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

luciusmagn commented 6 years ago

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

zesterer commented 6 years ago

@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?

luciusmagn commented 6 years ago

I'd say here, or you can write me an email at luk.hozda@gmail.com. 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 notifications@github.com 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 .

GopherJ commented 4 years ago

casbin-rs is also using rhai!

MarkuBu commented 4 years ago

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

schungx commented 4 years ago

@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.

MarkuBu commented 4 years ago

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

schungx commented 4 years ago

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.

MarkuBu commented 4 years ago

Ok, thanks.

sunng87 commented 4 years ago

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.

schungx commented 4 years ago

No prob!

sunng87 commented 4 years ago

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

Pebaz commented 3 years ago

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.

schungx commented 3 years ago

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 commented 3 years ago

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.

Pebaz commented 3 years ago

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

koute commented 3 years ago

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

garypen commented 2 years ago

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!

schungx commented 2 years ago

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.

garypen commented 2 years ago

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...

schungx commented 2 years ago

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);
ltabis commented 2 years ago

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 :)

schungx commented 2 years ago

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 commented 2 years ago

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.

YaLTeR commented 2 years ago

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.

schungx commented 2 years ago

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...

YaLTeR commented 2 years ago

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.

schungx commented 2 years ago

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.

erlend-sh commented 1 year ago

Others found via Used by:

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

ryankopf commented 6 months ago

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