• Stars
    star
    492
  • Rank 89,476 (Top 2 %)
  • Language
    C
  • License
    MIT License
  • Created over 10 years ago
  • Updated about 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Rust library to interface with Lua

hlua

This library is a high-level binding for Lua 5.2. You don't have access to the Lua stack, all you can do is read/write variables (including callbacks) and execute Lua code.

Build Status

How to install it?

Add this to the Cargo.toml file of your project

[dependencies]
hlua = "0.3"

How to use it?

extern crate hlua;
use hlua::Lua;

The Lua struct is the main element of this library. It represents a context in which you can execute Lua code.

let mut lua = Lua::new();     // mutable is mandatory

You can check the documentation here.

Reading and writing variables

lua.set("x", 2);
lua.execute::<()>("x = x + 1").unwrap();
let x: i32 = lua.get("x").unwrap();  // x is equal to 3

Reading and writing global variables of the Lua context can be done with set and get. The get function returns an Option<T> and does a copy of the value.

The base types that can be read and written are: i8, i16, i32, u8, u16, u32, f32, f64, bool, String. &str can be written but not read.

If you wish so, you can also add other types by implementing the Push and LuaRead traits.

Executing Lua

let x: u32 = lua.execute("return 6 * 2;").unwrap();    // equals 12

The execute function takes a &str and returns a Result<T, ExecutionError> where T: LuaRead.

You can also call execute_from_reader which takes a std::io::Read as parameter. For example you can easily execute the content of a file like this:

lua.execute_from_reader::<()>(File::open(&Path::new("script.lua")).unwrap())

Writing functions

In order to write a function, you must wrap it around hlua::functionX where X is the number of parameters. This is for the moment a limitation of Rust's inferrence system.

fn add(a: i32, b: i32) -> i32 {
    a + b
}

lua.set("add", hlua::function2(add));
lua.execute::<()>("local c = add(2, 4)");   // calls the `add` function above
let c: i32 = lua.get("c").unwrap();   // returns 6

In Lua, functions are exactly like regular variables.

You can write regular functions as well as closures:

lua.set("mul", hlua::function2(|a: i32, b: i32| a * b));

Note that the lifetime of the Lua context must be equal to or shorter than the lifetime of closures. This is enforced at compile-time.

let mut a = 5i;

{
    let mut lua = Lua::new();

    lua.set("inc", || a += 1);    // borrows 'a'
    for i in (0 .. 15) {
        lua.execute::<()>("inc()").unwrap();
    }
} // unborrows `a`

assert_eq!(a, 20)
Error handling

If your Rust function returns a Result object which contains an error, then a Lua error will be triggered.

Manipulating Lua tables

Manipulating a Lua table can be done by reading a LuaTable object. This can be achieved easily by reading a LuaTable object.

let mut table: hlua::LuaTable<_> = lua.get("a").unwrap();

You can then iterate through the table with the .iter() function. Note that the value returned by the iterator is an Option<(Key, Value)>, the Option being empty when either the key or the value is not convertible to the requested type. The filter_map function (provided by the standard Iterator trait) is very useful when dealing with this.

for (key, value) in table.iter().filter_map(|e| e) {
    ...
}

You can also retreive and modify individual indices:

let x = table.get("a").unwrap();
table.set("b", "hello");

Calling Lua functions

You can call Lua functions by reading a functions_read::LuaFunction.

lua.execute::<()>("
    function get_five() 
        return 5
    end");

let get_five: hlua::LuaFunction<_> = lua.get("get_five").unwrap();
let value: i32 = get_five.call().unwrap();
assert_eq!(value, 5);

This object holds a mutable reference of Lua, so you can't read or modify anything in the Lua context while the get_five variable exists. It is not possible to store the function for the moment, but it may be in the future.

Reading and writing Rust containers

(note: not yet possible to read all containers, see below)

It is possible to read and write whole Rust containers at once:

lua.set("a", [ 12, 13, 14, 15 ]);
let hashmap: HashMap<i32, f64> = [1., 2., 3.].into_iter().enumerate().map(|(k, v)| (k as i32, *v as f64)).collect();
lua.set("v", hashmap);

If the container has single elements, then the indices will be numerical. For example in the code above, the 12 will be at index 1, the 13 at index 2, etc.

If the container has tuples of two elements, then the first one will be considered as the key and the second one as the value.

This can be useful to create APIs:

fn foo() { }
fn bar() { }

lua.set("mylib", [
    ("foo", hlua::function0(foo)),
    ("bar", hlua::function0(bar))
]);

lua.execute::<()>("mylib.foo()");

It is possible to read a Vec<AnyLuaValue>:

        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { 1, 2, 3 }"#).unwrap();

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(
            read,
            [1., 2., 3.].iter()
                .map(|x| AnyLuaValue::LuaNumber(*x)).collect::<Vec<_>>());

In case table represents sparse array, has non-numeric keys, or indices not starting at 1, .get() will return None, as Rust's Vec doesn't support these features.

It is possible to read a HashMap<AnyHashableLuaValue, AnyLuaValue>:

let mut lua = Lua::new();

lua.execute::<()>(r#"v = { [-1] = -1, ["foo"] = 2, [2.] = 42 }"#).unwrap();

let read: HashMap<_, _> = lua.get("v").unwrap();
assert_eq!(read[&AnyHashableLuaValue::LuaNumber(-1)], AnyLuaValue::LuaNumber(-1.));
assert_eq!(read[&AnyHashableLuaValue::LuaString("foo".to_owned())], AnyLuaValue::LuaNumber(2.));
assert_eq!(read[&AnyHashableLuaValue::LuaNumber(2)], AnyLuaValue::LuaNumber(42.));
assert_eq!(read.len(), 3);

User data

(note: the API here is very unstable for the moment)

When you expose functions to Lua, you may wish to read or write more elaborate objects. This is called a user data.

To do so, you should implement the Push, CopyRead and ConsumeRead for your types. This is usually done by redirecting the call to userdata::push_userdata.

struct Foo;

impl<L> hlua::Push<L> for Foo where L: hlua::AsMutLua<'lua> {
    fn push_to_lua(self, lua: L) -> hlua::PushGuard<L> {
        lua::userdata::push_userdata(self, lua,
            |mut metatable| {
                // you can define all the member functions of Foo here
                // see the official Lua documentation for metatables
                metatable.set("__call", hlua::function0(|| println!("hello from foo")))
            })
    }
}

fn main() {
    let mut lua = lua::Lua::new();
    lua.set("foo", Foo);
    lua.execute::<()>("foo()");       // prints "hello from foo"
}

Creating a Lua module

Note: OBSOLETE ; this is still some pre-Rust-1.0 stuff

This library also includes a second library named rust-hl-lua-module which allows you to create Lua modules in Rust.

To use it, add this to Cargo.toml:

[dependencies.rust-hl-lua-modules]
git = "https://github.com/tomaka/hlua"

Then you can use it like this:

#![feature(phase)]
#[!plugin(rust-hl-lua-modules)]

#[export_lua_module]
pub mod mylib {         // <-- must be the name of the Lua module
    static PI: f32 = 3.141592;

    fn function1(a: int, b: int) -> int {
        a + b
    }

    fn function2(a: int) -> int {
        a + 5
    }

    #[lua_module_init]
    fn init() {
        println!("module initialized!")
    }
}

This module will then be usable by Lua:

> mylib = require("mylib")
module initialized!
> return mylib.function1(2, 4)
6
> return mylib.PI
3.141592

Two syntax extensions are defined:

  • #[export_lua_module]: Must be put in front of a module. The name of the module must be the same as the name of your Lua module.
  • #[lua_module_init]: Can be put in front of a function inside the module. This function will be executed when the module is loaded.

Restrictions:

  • fail!() will crash the program.
  • If you spawn tasks, they will have to end before the hand is given back to lua.

Contributing

Contributions are welcome!

More Repositories

1

redshirt

πŸ§‘β€πŸ”¬ Operating system
Rust
1,424
star
2

rouille

Web framework in Rust
Rust
1,087
star
3

luawrapper

Easy-to-use lua wrapper for C++
C++
98
star
4

wasm-timer

Abstraction over std::time::Instant and tokio_timer that works on WASM
Rust
72
star
5

glium_text

Text rendering with glium
Rust
47
star
6

immi

Immediate mode library in Rust
Rust
32
star
7

spine-rs

Spine loader in Rust
Rust
32
star
8

futures-diagnose

Wraps around a futures::task::Spawn and adds diagnostics to it
Rust
29
star
9

cargo-emscripten

Experiments with Rust and Emscripten
Rust
19
star
10

shared_library

Rust
18
star
11

vorbis-rs

Rust bindings for libvorbis
Rust
15
star
12

mantle-demo

Rust mantle experiments
Rust
14
star
13

rustfest-2018-workshop

Rust
13
star
14

substrate-browser-node-demo

Small demo of a Substrate node running in the browser
JavaScript
13
star
15

resources_package

Package files in your executables with the Rust language
Rust
12
star
16

from_json

Alternative to the Rust standard Json decoder
Rust
10
star
17

substrate-tetris

Tetris built on Substrate
Rust
9
star
18

rust-mingw-docker

🐳 Docker image with Rust configured for x86_64-pc-windows-gnu and i686-pc-windows-gnu
Dockerfile
6
star
19

rustc-emscripten

🐳 Docker image with rustup, rust, cargo, and emscripten
Dockerfile
6
star
20

eui

Easy UI
Rust
6
star
21

2018-rustrush-demo

Demo for the RustRush conference
Rust
5
star
22

glium2

5
star
23

clock_ticks

Rust
5
star
24

example-tiny-http

Example of web server in Rust
Rust
5
star
25

glium-azdo

Approaching zero driver overhead with glium
Rust
5
star
26

mick-jaeger

Rust client for OpenTelemetry, specifically for Jaeger
Rust
5
star
27

ogg-sys

Rust bindings for libogg
C
4
star
28

pocket-resources

Rust
4
star
29

glslang-rs

Interface for the `glslang` library in Rust. Allows you to test your shaders at compile-time.
Rust
4
star
30

rust-templates

Proof of concept: Rust compile-time templates
Rust
4
star
31

rust-android-docker

Docker file for a quick Rust + Android environment
4
star
32

glsl_parser

GLSL parser for Rust
Rust
4
star
33

rust-to-glsl

Rust
3
star
34

corooteen

Rust
3
star
35

vorbis-sys

libvorbis bindings for Rust
Rust
3
star
36

cmake-rs

Easily build projets using CMake with the Rust compiler
Rust
3
star
37

2019-rustlatam-meetup

HTML
3
star
38

polkadot-events

Polkadot events scraper
Rust
3
star
39

rustfest-2017-slides

HTML
3
star
40

xrb

XCB in Rust
Rust
3
star
41

zksummit-20180323-libp2p

Slides for the zkSummit conference about libp2p
HTML
2
star
42

wrrm

"Write-rarely-read-many" container
Rust
2
star
43

wasm-abi-test

Rust
2
star
44

declmagic

Game engine written in Rust with declarative programming mind
Rust
2
star
45

cargo-web

Docker image with cargo web installed
Dockerfile
2
star
46

scoped_tasks_future

Rust
2
star
47

parity-alpine

Parity client running on alpine
2
star
48

flate3

flate2 in pure Rust
Rust
2
star
49

rust-ids-container

Rust container which automatically assigns keys when you insert in it
Rust
1
star
50

glium_voxel

Rust
1
star
51

tomaka.github.io

1
star
52

crates-autodoc

Rust
1
star
53

arduino-leds

Rust
1
star
54

heroku-buildpack-rustc

Buildpack that installs rustc on the system to be used at runtime
Shell
1
star
55

cargo-bug-repro-20200624

Rust
1
star
56

tomaka

1
star
57

rustc-issue-repro

Rust
1
star
58

ui-rs

Rust
1
star
59

web-framework-example

Rust
1
star
60

ole32-sys

Rust bindings to ole32
Rust
1
star
61

lua-sys-rs

1
star
62

advapi32-sys

Rust bindings to advapi32
Rust
1
star
63

rust-arm-linux

Dockerfile
1
star
64

libp2pconf-2018-07-slides

Slides for the state of Rust libp2p
HTML
1
star
65

osmesa-rs

Off-Screen Mesa bindings for Rust
Rust
1
star
66

niysu

Light and easy to use PHP framework
PHP
1
star
67

glutin_window

A Piston window back-end using the Glutin library
Rust
1
star
68

spec

1
star
69

text-render-atlas

Rust
1
star
70

web-framework

Rust
1
star
71

frp-rs

Functional Reactive Programming - Rust
Rust
1
star
72

vorbisfile-sys

Rust bindings for libvorbisfile
C
1
star
73

test-browser-node

JavaScript
1
star