Search code examples
rustsnips

How do I convert arrays to a snips-nlu-rs whitelist or blacklist?


I use snips and built a C library. I want to connect the library to my Node environment with Rust.

JavaScript

var ffi = require('ffi');
const ArrayType = require('ref-array');
var nlu = require('./nlu');

const StringArray = ArrayType('string');


var nlulib = '../cargo/target/x86_64-apple-darwin/release/libp_public_transport_nlu.dylib'

var nlu = ffi.Library(nlulib, {
    "load": ['pointer', ['string']],
    "execute": ['string', ['pointer', 'string', StringArray]]
});


var ptrToEngine = nlu.load("../snips_public_transport_engine");
var responseNLU = nlu.execute(ptrToEngine, "myQuery", ['bestIntent'], ['worstIntent']);

Rust

#[no_mangle]
pub extern "C" fn execute(engine_pointer: *mut SnipsNluEngine, query: *const c_char, whitelist: &[u8], blacklist: &[u8]) -> CString {    
    let query_c_str = unsafe { CStr::from_ptr(query) };
    let query_string = match query_c_str.to_str().map(|s| s.to_owned()){
        Ok(string) => string,
        Err(e) => e.to_string()
    };

    let engine = unsafe {
        assert!(!engine_pointer.is_null());
        &mut *engine_pointer
    };

    let result = engine.parse(query_string.trim(), None, None).unwrap();
    let result_json = serde_json::to_string_pretty(&result).unwrap();

    CString::new(result_json).unwrap()
}

The engine.parse function expects Into<Option<Vec<&'a str>>> as a parameter instead of None, so I need to convert the whitelist and blacklist into this format.


Solution

  • After much struggle with it, I found a solution. I know, this won't be the best that has ever been existing, but it's a solution :)

    pub extern "C" fn execute(engine_pointer: *mut SnipsNluEngine, query: *const c_char, whitelist: *const *const c_char) -> CString {
        let query_c_str = unsafe { CStr::from_ptr(query) };
        let query_string = match query_c_str.to_str().map(|s| s.to_owned()){
            Ok(string) => string,
            Err(e) => e.to_string()
        };
    
        let engine = unsafe {
            assert!(!engine_pointer.is_null());
            &mut *engine_pointer
        };
    
    
        // count length of whitelist
        let mut whitelist_count = 0;
        let mut wc = whitelist;
        unsafe {
            while *wc != std::ptr::null() {
                whitelist_count += 1;
                wc = wc.offset(1);
            }
        }
    
        // get single elements pointer from pointer
        let sliced_whitelist = unsafe { slice::from_raw_parts(whitelist, whitelist_count) };
    
        // get string for every pointer
        let mut string_list_whitelist: Vec<String> = vec![];
    
        for i in 0..whitelist_count {
            let whitelist_element = sliced_whitelist[i];
            let whitelist_value = unsafe { CStr::from_ptr(whitelist_element) };
    
            let string_whitelist: String = match whitelist_value.to_str().map(|s| s.to_owned()){
                Ok(string) => string,
                Err(e) => e.to_string()
            };
    
            string_list_whitelist.insert(0, string_whitelist);
        }
    
        let mut snips_whitelist: Vec<&str> = vec![];
    
        for i in 0..whitelist_count {
            let whitelist_element_str: &str = &string_list_whitelist[i][..];
    
            snips_whitelist.insert(0, whitelist_element_str);
        }
    
    
        // create an optional for the whitelist
        let mut snips_whitelist_optional: Option<Vec<&str>> = None;
    
        if whitelist_count != 0 {
            snips_whitelist_optional = Some(snips_whitelist);
        }
    
        // parsing
        let result = engine.parse(query_string.trim(), snips_whitelist_optional, snips_blacklist_optional).unwrap();
        let result_json = serde_json::to_string_pretty(&result).unwrap();
    
        CString::new(result_json).unwrap()
    
    }
    

    Hint: a Nullpointer (e.g. ref.NULL) has to be sent at the end of the whitelist string array. Alternatively, you can send the array length as parameter instead of counting the list length.