valkeymodule-rs
This crate provides an idiomatic Rust API for the Valkey Modules API. It allows writing Valkey modules in Rust, without needing to use raw pointers or unsafe code. See here for the most recent API documentation.
This repo was forked from redismodule-rs. We appreciate the contributions of the original authors.
Running the example module
- Install Rust
- Install Valkey, most likely using your favorite package manager (Homebrew on Mac, APT or YUM on Linux)
- Run
cargo build --example hello - Start a valkey server with the
hellomodule- Linux:
valkey-server --loadmodule ./target/debug/examples/libhello.so - Mac:
valkey-server --loadmodule ./target/debug/examples/libhello.dylib
- Linux:
- Open a valkey-cli, and run
HELLO.MUL 31 11.
Writing your own module
See the examples directory for some sample modules.
This crate tries to provide high-level wrappers around the standard Valkey Modules API, while preserving the API's basic concepts. Therefore, following the Valkey Modules API documentation will be mostly relevant here as well.
Feature Flags
System Allocator
This feature flag is ideal for unit testing where the engine server is not running, and we do not have access to the Valkey engine allocator, so we can use the system allocator instead.
To optionally enter the System.alloc code paths in alloc.rs specify this in Cargo.toml of your module:
[]
= ["valkey-module/enable-system-alloc"]
For unit tests with System.alloc use this:
For integration tests with ValkeyAlloc use this:
Unit testing without a Valkey server
The test-shims feature provides Context::test(), CommandFilterCtx::test(), and ValkeyString::test() for unit tests that run without starting a Valkey process. Add valkey-module with this feature to your development dependencies, using the same version or source as your normal dependency:
[]
= { = "...", = ["test-shims"] }
The feature automatically enables the system allocator required by tests. When configured as a development dependency, the test-only APIs are available to unit tests without enabling them in production builds.
Use Context::test() when a command handler needs a context. Its expect_* methods configure values returned by supported context APIs. Use ValkeyString::test() to construct binary-safe command arguments; it accepts any value implementing Into<Vec<u8>>, including strings and arbitrary bytes:
The test context currently supports configuring the server version, client IDs, client names, client usernames, the current user, ACL-user authentication, and client deauthentication. Configure Context::get_server_version() with expect_get_server_version(major, minor, patch). Calls to set_module_options are accepted as a no-op because their effects require a running server. Context::create_string() also works with a test context:
let context = test;
let value = context.create_string;
assert_eq!;
Use CommandFilterCtx::test() to create a TestCommandFilterCtx for testing command-filter logic. The test wrapper dereferences to CommandFilterCtx, so it can be passed directly to a helper that contains the filter behavior:
use CommandFilterCtx;
let mut context = test;
context
.expect_args_count
.expect_arg_get
.expect_arg_get
.expect_arg_get
.expect_get_client_id;
rewrite_set;
assert_eq!;
assert_eq!;
assert_eq!;
expect_args_count() configures the reported number of arguments, while expect_arg_get() configures the binary-safe value at an individual position. The test context also supports command lookup, client ID lookup, and argument replacement, insertion, and deletion. Insertions and deletions update the argument count and shift subsequent arguments.
Run these tests normally:
The first call to Context::test(), CommandFilterCtx::test(), or ValkeyString::test() installs process-wide test callbacks. Do not invoke the test shims inside a running Valkey process; setup rejects installation after the real Valkey API has been initialized. Only explicitly shimmed APIs work without Valkey. Other APIs, including ValkeyString::append(), still require a running server.
Redis Compatibility
This feature flag is useful in case you have a Module that needs to be loaded on both Valkey and Redis Servers. In this case, you can use the use-redismodule-api flag so that the Module is loaded using the RedisModule API Initialization for compatibility.
To use this feature by conditionally, specify the following in your Cargo.toml:
[]
= ["valkey-module/use-redismodule-api"]
= []