4个版本

0.1.6 2021年6月24日
0.1.5 2021年5月27日
0.1.1 2021年4月25日

#5 in #kdb

Apache-2.0

105KB
674

!!注意!! 此crate已迁移到 kdbplus,其中包含IPC模块。

Rust封装的kdb+ C API

编程语言q(kdb+是用q编写的数据库)只提供C API,但有时外部库提供Rust接口而不提供C/C++接口。从其性能来看,Rust仍然可以构建kdb+的共享库。此库是为了满足这种自然的需求(如果你愿意,是愿望)。由于除了创建这样的封装器外,没有其他方法来编写kdb+的共享库,因此某人提供封装器可能是有意义的,这在这里已经完成。

为了避免编写太大的unsafe块,从而导致优化不良,大多数原生C API函数都提供有包装函数,具有一点人体工程学安全和直观的实现,作为特质方法。唯一的例外是knkk,它们使用省略号(...)作为其参数。这些函数与其他C API函数一起在native命名空间下提供。

安装

Cargo.toml中使用kdb_c_api作为库名称。


[dependencies]
kdb_c_api="^0.1"

示例

C API封装器使用示例包含在c_api_examples文件夹中。这些示例反映了kdb_c_api库中的示例,并且这些函数也用于库的简单测试。测试是在tests/.q下进行的,通过加载从示例构建的共享库中定义的函数。

以下是一些示例

C API风格

use kdb_c_api::*;
use kdb_c_api::native::*;

#[no_mangle]
pub extern "C" fn create_symbol_list(_: K) -> K{
  unsafe{
    let mut list=ktn(qtype::SYMBOL as i32, 0);
    js(&mut list, ss(str_to_S!("Abraham")));
    js(&mut list, ss(str_to_S!("Isaac")));
    js(&mut list, ss(str_to_S!("Jacob")));
    js(&mut list, sn(str_to_S!("Josephine"), 6));
    list
  }
}
 
#[no_mangle]
pub extern "C" fn catchy(func: K, args: K) -> K{
  unsafe{
    let result=ee(dot(func, args));
    if (*result).qtype == qtype::ERROR{
      println!("error: {}", S_to_str((*result).value.symbol));
      // Decrement reference count of the error object
      r0(result);
      KNULL
    }
    else{
      result
    }
  }
}

#[no_mangle]
pub extern "C" fn dictionary_list_to_table() -> K{
  unsafe{
    let dicts=knk(3);
    let dicts_slice=dicts.as_mut_slice::<K>();
    for i in 0..3{
      let keys=ktn(qtype::SYMBOL as i32, 2);
      let keys_slice=keys.as_mut_slice::<S>();
      keys_slice[0]=ss(str_to_S!("a"));
      keys_slice[1]=ss(str_to_S!("b"));
      let values=ktn(qtype::INT as i32, 2);
      values.as_mut_slice::<I>()[0..2].copy_from_slice(&[i*10, i*100]);
      dicts_slice[i as usize]=xD(keys, values);
    }
    // Format list of dictionary as a table.
    // ([] a: 0 10 20i; b: 0 100 200i)
    k(0, str_to_S!("{[dicts] -1 _ dicts, (::)}"), dicts, KNULL)
  } 
}

q可以使用这些函数这样使用

q)summon:`libc_api_examples 2: (`create_symbol_list; 1)
q)summon[]
`Abraham`Isaac`Jacob`Joseph
q)`Abraham`Isaac`Jacob`Joseph ~ summon[]
q)catchy: `libc_api_examples 2: (`catchy; 2);
q)catchy[$; ("J"; "42")]
42
q)catchy[+; (1; `a)]
error: type
q)unfortunate_fact: `libc_api_examples 2: (`dictionary_list_to_table; 1);
q)unfortunate_fact[]
a  b  
------
0  0  
10 100
20 200

Rust风格

以下示例没有编写unsafe代码。您可以看到包装函数在代码中的舒适呼吸。

use kdb_c_api::*;

#[no_mangle]
pub extern "C" fn create_symbol_list2(_: K) -> K{
  let mut list=new_simple_list(qtype::SYMBOL, 0);
  list.push_symbol("Abraham").unwrap();
  list.push_symbol("Isaac").unwrap();
  list.push_symbol("Jacob").unwrap();
  list.push_symbol_n("Josephine", 6).unwrap();
  list
}

#[no_mangle]
fn no_panick(func: K, args: K) -> K{
  let result=error_to_string(apply(func, args));
  if result.get_type() == qtype::ERROR{
    println!("FYI: {}", result.get_symbol().unwrap());
    // Decrement reference count of the error object which is no longer used.
    decrement_reference_count(result);
    KNULL
  }
  else{
    println!("success!");
    result
  }
}

#[no_mangle]
pub extern "C" fn create_table2(_: K) -> K{
  // Build keys
  let keys=new_simple_list(qtype::SYMBOL, 2);
  let keys_slice=keys.as_mut_slice::<S>();
  keys_slice[0]=internalize(str_to_S!("time"));
  keys_slice[1]=internalize_n(str_to_S!("temperature_and_humidity"), 11);

  // Build values
  let values=new_simple_list(qtype::COMPOUND, 2);
  let time=new_simple_list(qtype::TIMESTAMP, 3);
  // 2003.10.10D02:24:19.167018272 2006.05.24D06:16:49.419710368 2008.08.12D23:12:24.018691392
  time.as_mut_slice::<J>().copy_from_slice(&[119067859167018272_i64, 201766609419710368, 271897944018691392]);
  let temperature=new_simple_list(qtype::FLOAT, 3);
  temperature.as_mut_slice::<F>().copy_from_slice(&[22.1_f64, 24.7, 30.5]);
  values.as_mut_slice::<K>().copy_from_slice(&[time, temperature]);
  
  flip(new_dictionary(keys, values))
}

以下是q代码

q)summon:`libc_api_examples 2: (`create_symbol_list2; 1)
q)summon[]
`Abraham`Isaac`Jacob`Joseph
q)chill: `libc_api_examples 2: (`no_panick; 2);
q)chill[$; ("J"; "42")]
success!
42
q)chill[+; (1; `a)]
FYI: type
q)climate_change: libc_api_examples 2: (`create_table2; 1);
q)climate_change[]
time                          temperature
-----------------------------------------
2003.10.10D02:24:19.167018272 22.1       
2006.05.24D06:16:49.419710368 24.7       
2008.08.12D23:12:24.018691392 30.5  

测试

通过将函数加载到q进程中进行测试,使用tests/.q中的示例函数进行测试。


rust_kdb_c_api]$ cargo build
rust_kdb_c_api]$ cp target/debug.libc_api_examples.so tests/
rust_kdb_c_api]$ cd tests
tests]$ q test.q
Initialized something, probably it is your mindset.
bool: true
bool: false
byte: 0xc4
GUID: 8c6b-8b-64-68-156084
short: 10
int: 42
int: 122
int: 7336
int: 723
int: 14240
int: 2056636
long: -109210
long: 43200123456789
long: -325389000000021
real: 193810.31
float: -37017.09330000
float: 742.41927468
char: "k"
symbol: `locust
string: "gnat"
string: "grasshopper"
error: type
What do you see, son of man?: a basket of summer fruit
What do you see, son of man?: boiling pot, facing away from the north
symbol: `rust
success!
FYI: type
おいしい!
おいしい!
おいしい!
おいしい!
おいしい!
おいしい!
おいしい!
おいしい!
おいしい!
おいしい!
"Collect the clutter of apples!"
test result: ok. 122 passed; 0 failed
What are the three largest elements?: `belief`love`hope
q)

文档

此crate的文档在crates.io页面上。

有关C API本身的详细信息,请参阅KX网站的文档。

注意

此库的目的是用于构建共享库;因此删除了一些无关函数。例如,连接到kdb+的函数(如 khpu)不包括在内。

无运行时依赖