Crate vibha

Source
Expand description

Defines the types and helpers for binary/library communication.

The general idea is that the user will run a driver program which calls game_init to get a handle, and then gets lines from the user and passes them to game_process_line, and prints the output. At some point the driving program might try to exit cleanly, and if so it’ll call game_drop. Of course, the driving program might suddenly die at any moment without game_drop ever being called, so I wouldn’t rely on that happening.

Note that all of the interchange types are fully compatible with the C ABI, so you don’t have to use Rust if you don’t want to. As long as you follow the types you can write your DLL and/or driving program in any language you like.

To be loaded properly, your DLL should have one function of each function type given here, named in snake_case without the “Fn” part at the end:

§Building a game DLL with cargo

First, be sure to mark your functions with #[no_mangle] and pub. You must also have “cdylib” as one of your crate-type values for your crate’s library portion. If you want cargo test to work properly, you’ll need “rlib” as well. It’ll look something like this:

[lib]
name = "vibha"
path = "src/lib.rs"
crate-type = ["rlib", "cdylib"]

You can easily ensure that your functions have the correct type at compile time with a simple set of const declarations.

A “complete” example might look something like this.

extern crate vibha;
use vibha::*;
use std::io::Write;
use std::os::raw::c_void;

struct GameState {
  world_seed: u64,
  call_count: u64,
}

#[no_mangle]
pub unsafe extern "C" fn game_init(world_seed: u64) -> *mut c_void {
  Box::into_raw(Box::new(GameState {
    world_seed,
    call_count: 0
  })) as *mut c_void
}

#[no_mangle]
pub unsafe extern "C" fn game_process_line(handle: *mut c_void,
        line: *const u8, line_len: usize, mut buf: *mut u8, buf_len: usize) -> usize {
  if handle.is_null() || line.is_null() || buf.is_null() {
    return 0;
  }
  let user_line = ffi_recover_str(&line, line_len);
  let mut out_buffer = ffi_recover_out_buffer(&mut buf, buf_len);
  let game_state: &mut GameState =
    (handle as *mut GameState).as_mut().expect("game session was null!");
  // do something silly just so we can see an effect
  game_state.call_count += 1;
  if user_line.len() > 0 {
    write!(out_buffer, "{}: {}", game_state.call_count, user_line).ok();
  } else {
    write!(out_buffer, "{}: {}", game_state.call_count, game_state.world_seed).ok();
  }
  out_buffer.position() as usize
}

#[no_mangle]
pub unsafe extern "C" fn game_drop(handle: *mut c_void) {
  Box::from_raw(handle as *mut GameState);
}

#[allow(dead_code)]
const GAME_INIT_CONST: GameInitFn = game_init;
#[allow(dead_code)]
const GAME_PROCESS_LINE_CONST: GameProcessLineFn = game_process_line;
#[allow(dead_code)]
const GAME_DROP_CONST: GameDropFn = game_drop;

Structs§

Enums§

  • Wraps a string slice with a “mode” tag.

Constants§

Functions§

Type Aliases§