#![allow(missing_docs, unsafe_code)]
use core::mem;
use core::ptr;
use core::slice;
use core::str;
use parse::Parser;
use types::{Gcode, Mnemonic, Span, Word};
cfg_if!{
if #[cfg(target_pointer_width = "64")] {
pub const SIZE_OF_PARSER: usize = 64;
pub const SIZE_OF_GCODE: usize = 312;
} else if #[cfg(target_pointer_width = "32")] {
pub const SIZE_OF_PARSER: usize = 36;
pub const SIZE_OF_GCODE: usize = 196;
} else {
compile_error!("FFI bindings aren't (yet) supported on this platform \
because we can't statically determine size of `Parser` \
and `Gcode`");
}
}
#[no_mangle]
pub unsafe extern "C" fn parser_new(
parser: *mut Parser,
src: *const u8,
src_len: i32,
) -> bool {
if src.is_null() || parser.is_null() {
return false;
}
let src = slice::from_raw_parts(src, src_len as usize);
let src = match str::from_utf8(src) {
Ok(s) => s,
Err(_) => return false,
};
let local_parser = Parser::new(src);
ptr::write(parser, local_parser);
true
}
#[no_mangle]
pub unsafe extern "C" fn parser_next(
parser: *mut Parser,
gcode: *mut Gcode,
) -> bool {
let parser = &mut *parser;
match parser.next() {
Some(got) => {
ptr::write(gcode, got);
true
}
None => false,
}
}
#[no_mangle]
pub unsafe extern "C" fn gcode_mnemonic(gcode: *const Gcode) -> Mnemonic {
(&*gcode).mnemonic()
}
#[no_mangle]
pub unsafe extern "C" fn gcode_number(gcode: *const Gcode) -> f32 {
(&*gcode).number()
}
#[no_mangle]
pub unsafe extern "C" fn gcode_major_number(gcode: *const Gcode) -> u32 {
(&*gcode).major_number()
}
#[no_mangle]
pub unsafe extern "C" fn gcode_num_args(gcode: *const Gcode) -> i32 {
(&*gcode).args().len() as i32
}
#[no_mangle]
pub unsafe extern "C" fn gcode_args(gcode: *const Gcode) -> *const Word {
(&*gcode).args().as_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn gcode_arg_value(
gcode: *const Gcode,
letter: char,
value: *mut f32,
) -> bool {
match (&*gcode).value_for(letter) {
Some(n) => {
*value = n;
true
}
None => false,
}
}
#[no_mangle]
pub unsafe extern "C" fn gcode_span(gcode: *const Gcode) -> Span {
(&*gcode).span()
}
#[no_mangle]
pub unsafe extern "C" fn gcode_line_number(
gcode: *const Gcode,
line_number: *mut u32,
) -> bool {
match (&*gcode).line_number() {
Some(n) => {
*line_number = n;
true
}
None => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::mem;
#[test]
fn constant_definitions_are_correct() {
assert_eq!(SIZE_OF_PARSER, mem::size_of::<Parser>());
assert_eq!(SIZE_OF_GCODE, mem::size_of::<Gcode>());
}
#[test]
fn all_ffi_types_are_trivial() {
assert!(!mem::needs_drop::<Parser>());
}
}