~ioiojo/include-fnl

Embed Fennel modules in Rust
export include_fnl_config::Mount from include_fnl
refactor Mount

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~ioiojo/include-fnl
read/write
git@git.sr.ht:~ioiojo/include-fnl

You can also use your local clone with git send-email.

#include-fnl

Embed Fennel modules in Rust.

#Synopsis

Assume we have the following directory structure, where . is a simple Rust library crate containing subdirectory kiwi. Inside kiwi are Fennel modules to embed:

$ tree
.
├── kiwi
│   ├── dine
│      ├── init.fnl
│      └── proximates.fnl
│   ├── food
│      ├── init.fnl
│      └── proximates.fnl
│   ├── cite.fnl
│   ├── date-time.fnl
│   ├── date.fnl
│   ├── time.fnl
│   └── utils.fnl
├── src
│   └── lib.rs
└── Cargo.toml

4 directories, 11 files

Create include.fnl alongside Cargo.toml:

(local include-fnl (require :include-fnl))

{;; Name of Fennel module searcher.
 :kiwi {
   ;; Table of Fennel module paths indexed by module name.
   :provides {:fnl {:kiwi/cite            :kiwi/cite.fnl
                    :kiwi/date            :kiwi/date.fnl
                    :kiwi/date-time       :kiwi/date-time.fnl
                    :kiwi/dine            :kiwi/dine/init.fnl
                    :kiwi/dine/proximates :kiwi/dine/proximates.fnl
                    :kiwi/food            :kiwi/food/init.fnl
                    :kiwi/food/proximates :kiwi/food/proximates.fnl
                    :kiwi/time            :kiwi/time.fnl
                    :kiwi/utils           :kiwi/utils.fnl}
              ;; Embed Fennel release from `fennel-src` crate. Enables
              ;; `(require :fennel)`.
              :lua {:fennel               include-fnl.fennel-path}}}}

#Embed Fennel modules at compile time

main.rs:

use rlua::Lua;

// For enabling the `add_searcher` method on `rlua::Context`.
use rlua_searcher::AddSearcher;

// For enabling `include_fnl!`.
use include_fnl::include_fnl;

fn main() {
    let lua = Lua::new();

    // Embed Fennel modules specified in the `provides` table of the searcher named `kiwi`
    // in `include.fnl`. Fennel sources are AOT-compiled to Lua during Rust comptime.
    // Our source code can access Fennel via `require("fennel")`, because we configured the
    // `kiwi` module searcher to embed the Fennel library.
    let mut kiwi = include_fnl!("kiwi");
    let kiwi_fnl = kiwi.fnl.take().unwrap();
    let kiwi_lua = kiwi.lua.take().unwrap();

    let uuid = lua.context::<_, String>(|lua_ctx| {
        // Enable Lua's `require` to find embedded Fennel modules (AOT-compiled to Lua).
        //
        // N.B. Fennel is not yet accessible via `require("fennel")`, because `kiwi_fnl`
        // contains only Fennel source code. If you need to access Fennel, load `kiwi_lua`.
        lua_ctx.add_searcher(kiwi_fnl).unwrap();

        lua_ctx
            .load(r#"local utils = require("kiwi/utils"); return utils.uuid()"#)
            .eval()
            .unwrap()
    });

    // e.g. "d717c6d8-ebed-47ca-8c21-2b6624846ddc"
    eprintln!("{}", uuid);

    let version = lua.context::<_, String>(|lua_ctx| {
        // Enable Lua's `require` to find Lua modules (including Fennel itself) - in this
        // case, only Fennel itself. We configure Lua modules separately from Fennel
        // modules because Fennel modules require a compilation step.
        lua_ctx.add_searcher(kiwi_lua).unwrap();

        lua_ctx
            .load(r#"local fennel = require("fennel"); return fennel.version"#)
            .eval()
            .unwrap()
    });

    assert_eq!(&version, "1.0.0");
}

#Load modules at runtime

main.rs:

use rlua::Lua;

// For enabling the `add_path_searcher_fnl` method on `rlua::Context`.
use fennel_searcher::AddSearcherFnl;

// For enabling the `add_path_searcher` method on `rlua::Context`.
use rlua_searcher::AddSearcher;

// For enabling `load_fnl!`.
use include_fnl::load_fnl;

fn main() {
    let lua = Lua::new();

    // Configure Fennel modules specified in the `provides` table of the searcher named
    // `kiwi` in `include.fnl` to be compiled to Lua at runtime (on demand). With Fennel
    // accessible via module name `fennel`.
    let mut kiwi = load_fnl!("kiwi");
    let kiwi_fnl = kiwi.fnl.take().unwrap();
    let kiwi_lua = kiwi.lua.take().unwrap();

    let uuid = lua.context::<_, String>(|lua_ctx| {
        // Enable Lua's `require` to find Fennel modules.
        lua_ctx.add_path_searcher_fnl(kiwi_fnl).unwrap();

        lua_ctx
            .load(r#"local utils = require("kiwi/utils"); return utils.uuid()"#)
            .eval()
            .unwrap()
    });

    // e.g. "d717c6d8-ebed-47ca-8c21-2b6624846ddc"
    eprintln!("{}", uuid);

    let version = lua.context::<_, String>(|lua_ctx| {
        // Enable Lua's `require` to find Lua modules (including Fennel itself) - in this
        // case, only Fennel itself.
        lua_ctx.add_path_searcher(kiwi_lua).unwrap();

        lua_ctx
            .load(r#"local fennel = require("fennel"); return fennel.version"#)
            .eval()
            .unwrap()
    });

    assert_eq!(&version, "1.0.0");
}

#License

Licensed under either of

at your option.

#Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Do not follow this link