Crate kdb[][src]

rust-kdb is an idiomatic Rust wrapper around the KDB+ C API. It supports manipulating K objects efficiently using zero cost abstractions, conversion to and from rust native types, and creation and editing of K lists/dictionaries using iterators.

The design goals of the library:

  1. Performance
  2. Provide an idiomatic rust API
  3. Safety

Why you might like it

  1. It's really fast. The abstractions around the KDB types have zero overhead so while it feels like you are using rust types with all the trimmings, it is as fast as calling the raw C API directly.
  2. It's safe! Using the C API is full of pitfalls that cause undefined behaviour. The abstractions in rust-kdb manage these for you, so that you don't need to worry about freeing your KDB objects or weird behaviour.
  3. It's just like using other rust data types. We've worked hard to make Lists work like Rust vectors, and to add similar convenience functions to dictionaries.

Why you might not like it

  1. Type conversions are common. It's not unusual to see rust-kdb code littered with .try_into().unwrap() Especially when working with mixed lists. This is a consequence of retrofitting the kdb type system into Rust. These type conversions are cheap (from/into are free, try_from/try_into are a single check of the KDB type code) But they do dirty the code somewhat.
  2. It's incomplete. It currently lacks support for tables and not all functions have been included. The plan is to include these features in time.

Creating KDB types

KDB deals with atoms and lists. rust-kdb maps this to the Atom And List generic types. We create a kdb type using a KBox. Just like a Rust Box wraps Rust heap managed pointers, KBox wraps KDB managed pointers.

To create a new 32-bit integer atom:

use kdb::KBox;
let a = KBox::new_atom(42);
assert_eq!(a.value(), 42);

To create a list of bytes:

let mut l = KBox::<List<u8>>::new_list();
for i in 1..=10 {
    l.push(i);   
}
assert_eq!(l.len(), 10);

Working with unknown types

KDB is dynamically typed, in that each type is an instance of a k object This is similar to variant types in C++. In rust-kdb, we manage this with the Any type.

The Any type can be used in place of any valid KDB value (atom or list). You can't do much with it, except try to convert it to a different type, using the TryFrom/TryInto traits.

use kdb::*;
use std::convert::{TryFrom, TryInto};

let a = KBox::new_atom(42);
let b: KBox<Any> = a.into();
let c: KBox<Atom<i32>> = b.try_into().unwrap();

Writing embedded KDB plug-ins

Writing embedded plugins is straightforward using rust-kdb. Youll need to use the "embedded" feature for your plugin to use the correct library bindings.

Below is an example of a simple KDB plugin

use kdb::*;
use std::convert::TryFrom;
use std::f64::consts::PI;

/// Calculates the circumference of a circle. Returns a null value if the radius is not a real number.
#[no_mangle]
pub extern "C" fn circumference(radius: &Any) -> Option<KBox<Atom<f64>>> {
    if let Ok(r) = <&Atom<f64>>::try_from(radius) {
        return Some(KBox::new_atom(r.value() * r.value() * PI));
    }
    None
}

Key points:

  1. Note that KDB parameters in extern "C" functions are references to KDB types, rather than a KBox. In KDB, the caller owns the parameters. Using a KBox here will likely cause a segfault.
  2. The return type is always either a KBox or Option<KBox>. This is equivalent to returning a K pointer. Always return an owned type.
  3. You can use typed atoms for parameters, not just Any. Bear in mind that this is unsafe as it is possible for q code to call the function with a type other than that one. Any is always safest.

Re-exports

pub use array_iterator;
pub use uuid;

Modules

kapi

Provides ffi definitions for the KDB C API.

Macros

cast

Cast a KBox, &KBox or &Any to another KDB type.

list

Create a list from a set of supplied values.

Structs

Any

Any represents any KDB value regardless of type. Unlike atoms or lists you can't do anything with it, except for convert it into an atom or a list. It is ABI compatible with a K object, so it can be safely used as a parameter or return type for a function. See the chapter on embedded functions for more information.

Atom

Atoms are the base primitive values in rust-kdb. You can create a new atom by calling KBox::new_atom, or using the From/Into traits on a value.

Connection

Represents a connection to a remote or embedded KDB instance, which can be used to send and query data on that instance.

Date

Represents the number of days since 1 Jan 2000.

DateTime

Represents a date and time in KDB. Conversions between the Unix Epoch and the KDB Epoch are done automatically.

Dictionary

A key value based dictionary.

KBox

Represents a memory managed K pointer. They are the KDB equivalent of a Rust Box, a zero overhead wrapper around a K pointer. It will call r0 to decrement the reference count when it is dropped.

KError

Represents an error in KDB.

List

Lists are the KDB equivalent of Rust's Vec. They contain collections of values and their contents be looked up by index.

Minute

Represents the number of minutes since midnight (00:00).

Month

The number of months since January 2000.

Second

Represents the number of seconds since midnight (00:00)

Symbol

Represents a KDB Symbol (interned string) Implements basic symbol operations for efficiency Can be converted to/from strings

Table

Represents a table (a dictionary of columns) in KDB

Time

The number of milliseconds since midnight.

Timespan

Represents an elapsed span of time

Timestamp

Represents a timestamp in KDB. Conversions between the Unix Epoch and the KDB Epoch are done automatically.

Enums

ConnectionError

The error type for connecting to KDB.

ConversionError

Error type for converting from/to kdb types.

Error

The error type for Q query execution.

SerializationMode

Describes how to perform serialization when using b9_serialize.

Functions

b9_serialize

Serialize a K object using KDB serialization.

d9_deserialize

Decode a serialized K object.

init

[not-embedded] Initialize the kdb memory subsystem. this is required when using generator functions in a standalone kdb application. This is equivalent to calling khp("", -1) in the C api.

symbol

Helper for succinctly creating a symbol. If the string passed in is not a valid symbol, i.e. it contains embedded nuls, then this function will panic.