Module resp

Source
Expand description

Defines types related to the RESP protocol and their encoding/decoding

§Object Model

rustis provides an object model in the form of a generic data struct, comparable to the XML DOM, and which matches perfectly the RESP protocol: the enum resp::Value.

Each variant of this enum matches a RESP type.

Because, navigating through a resp::Value instance can be verbose and requires a lot of pattern matching, rustis provides a resp::Value to Rust type conversion with a serde deserializer implementation of a resp::Value reference.

This conversion is easily accessible through the associate function Value::into.

§Command arguments

rustis provides an idiomatic way to pass arguments to commands. Basically a Command is a builder which accepts a command name and one ore more command arguments.

You will notice that each built-in command expects arguments through a set of traits defined in this module.

For each trait, you can add your own implementations for your custom types or request additional implementation for standard types.

§ToArgs

The trait ToArgs allows to convert a complex type into one ore multiple argumentss. Basically, the conversion function can add multiple arguments to an existing argument collection: the CommandArgs struct.

Current implementation provides the following conversions:

  • i8, u16, i16, u32, i32, u64, i64, usize, isize,
  • f32, f64,
  • bool,
  • String, &String, char, &str, BulkString, Vec<u8>, &[u8; N], [u8; N], &[u8]
  • Option<T> where T: SingleArg
  • (T, U)
  • (T, U, V)
  • Vec<T>
  • [T;N]
  • SmallVec<A>
  • BTreeSet<T>
  • HashSet<T, S>
  • BTreeMap<K, V>
  • HashMap<K, V, S>
  • CommandArgs

Nevertheless, ToArgs is not expected directly in built-in commands arguments.

The following traits are used to constraints which implementations of ToArgs are expected by a specific argument of a built-in command.

§SingleArg

Several Redis commands expect a Rust type that should be converted in a single command argument.

rustis uses the trait SingleArg to implement this behavior.

Current implementation provides the following conversions:

  • i8, u16, i16, u32, i32, u64, i64, usize, isize,
  • f32, f64,
  • bool,
  • String, &String, char, &str, BulkString, Vec<u8>, &[u8; N], [u8; N], &[u8]
  • Option<T> where T: SingleArg
§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, StringCommands},
    resp::{CommandArgs, ToArgs, SingleArg},
    Result,
};

pub struct MyI32(i32);

 impl ToArgs for MyI32 {
    #[inline]
    fn write_args(&self, args: &mut CommandArgs) {
        args.arg(self.0);
    }
}

impl SingleArg for MyI32 {}

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.set("key", 12).await?;
    client.set("key", 12i64).await?;
    client.set("key", 12.12).await?;
    client.set("key", true).await?;
    client.set("key", true).await?;
    client.set("key", "value").await?;
    client.set("key", "value".to_owned()).await?;
    client.set("key", 'c').await?;
    client.set("key", b"value").await?;
    client.set("key", &b"value"[..]).await?;
    client.set("key", b"value".to_vec()).await?;
    client.set("key", MyI32(12)).await?;

    Ok(())
}

§SingleArgCollection

Several Redis commands expect a collection with elements that will produced a single command argument each

rustis uses the trait SingleArgCollection to implement this behavior.

Current implementation provides the following conversions:

  • T (for the single item case)
  • Vec<T>
  • [T;N]
  • SmallVec<A>
  • BTreeSet<T>
  • HashSet<T, S>
  • CommandArgs

where each of theses implementations must also implement ToArgs

§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, ListCommands},
    Result,
};
use smallvec::{SmallVec};
use std::collections::{HashSet, BTreeSet};

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.lpush("key", 12).await?;
    client.lpush("key", [12, 13, 14]).await?;
    client.lpush("key", vec![12, 13, 14]).await?;
    client.lpush("key", SmallVec::from([12, 13, 14])).await?;
    client.lpush("key", HashSet::from([12, 13, 14])).await?;
    client.lpush("key", BTreeSet::from([12, 13, 14])).await?;

    client.lpush("key", "value1").await?;
    client.lpush("key", ["value1", "value2", "value13"]).await?;
    client.lpush("key", vec!["value1", "value2", "value13"]).await?;
    client.lpush("key", SmallVec::from(["value1", "value2", "value13"])).await?;
    client.lpush("key", HashSet::from(["value1", "value2", "value13"])).await?;
    client.lpush("key", BTreeSet::from(["value1", "value2", "value13"])).await?;

    Ok(())
}

§MultipleArgsCollection

Several Redis commands expect a collection with elements that will produced multiple command arguments each

rustis uses the trait MultipleArgsCollection to implement this behavior.

Current implementation provides the following conversions:

  • T (for the single item case)
  • Vec<T>
  • [T;N]

where each of theses implementations must also implement ToArgs

§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, SortedSetCommands, ZAddOptions},
    Result,
};
use std::collections::{HashSet, BTreeSet};

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.zadd("key", (1.0, "member1"), ZAddOptions::default()).await?;
    client.zadd("key", [(1.0, "member1"), (2.0, "member2")], ZAddOptions::default()).await?;
    client.zadd("key", vec![(1.0, "member1"), (2.0, "member2")], ZAddOptions::default()).await?;

    Ok(())
}

§KeyValueArgsCollection

Several Redis commands expect one or multiple key/value pairs.

rustis uses the trait KeyValueArgsCollection to implement this behavior.

Current implementation provides the following conversions:

  • (K, V) (for the single item case)
  • Vec<(K, V)>
  • [(K, V);N]
  • SmallVec<A> where A: Array<Item = (K, V)>
  • BTreeMap<K, V>
  • HashMap<K, V, S>

where each of theses implementations must also implement ToArgs

§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, StringCommands},
    Result,
};
use smallvec::{SmallVec};
use std::collections::{HashMap, BTreeMap};

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.mset(("key1", "value1")).await?;
    client.mset([("key1", "value1"), ("key2", "value2")]).await?;
    client.mset(vec![("key1", "value1"), ("key2", "value2")]).await?;
    client.mset(SmallVec::from([("key1", "value1"), ("key2", "value2")])).await?;
    client.mset(HashMap::from([("key1", "value1"), ("key2", "value2")])).await?;
    client.mset(BTreeMap::from([("key1", "value1"), ("key2", "value2")])).await?;

    client.mset(("key1", 12)).await?;
    client.mset([("key1", 12), ("key2", 13)]).await?;
    client.mset(vec![("key1", 12), ("key2", 13)]).await?;
    client.mset(SmallVec::from([("key1", 12), ("key2", 13)])).await?;
    client.mset(HashMap::from([("key1", 12), ("key2", 13)])).await?;
    client.mset(BTreeMap::from([("key1", 12), ("key2", 13)])).await?;

    Ok(())
}

§Command results

rustis provides an idiomatic way to convert command results into Rust types with the help of serde

You will notice that each built-in command returns a PreparedCommand<R> struct where R represents the Response of the command.

The different command traits implementations (Client, Pipeline or Transaction) add a constraint on the reponse R: it must implement serde Deserialize trait.

Indeed, rustis provides a serde implementation of a RESP deserializer. Each custom struct or enum defined as a response of a built-command implements serde Deserialize trait, in order to deserialize it automatically from a RESP Buffer.

Some more advanced traits allow to constraint more which Rust types are allowed for specific commands.

For each trait, you can add your own implementations for your custom types or request additional implementation for standard types.

§PrimitiveResponse

Several Redis commands return a simple primitive response.

rustis uses the trait PrimitiveResponse to implement this behavior.

Current implementation provides the following deserializations from a RESP Buffer:

  • Value
  • ()
  • u8, i8, u16, i16, u32, i32, u64, i64, usize, isize,
  • f32, f64,
  • bool,
  • String,
  • BulkString,
  • Option<T>
§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, StringCommands},
    resp::{PrimitiveResponse, deserialize_byte_buf},
    Result,
};
use serde::Deserialize;

#[derive(Deserialize)]
pub struct MyI32(i32);
impl PrimitiveResponse for MyI32 {}

#[derive(Deserialize)]
pub struct Buffer(#[serde(deserialize_with = "deserialize_byte_buf")] pub Vec<u8>);
impl PrimitiveResponse for Buffer {}

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.set("key", 12).await?;
    let _result: i32 = client.get("key").await?;
    let _result: MyI32 = client.get("key").await?;

    client.set("key", 12.12).await?;
    let _result: f64 = client.get("key").await?;

    client.set("key", true).await?;
    let _result: bool = client.get("key").await?;

    client.set("key", "value").await?;
    let _result: String = client.get("key").await?;
    let _result: Buffer = client.get("key").await?;

    Ok(())
}

§CollectionResponse

Several Redis commands return a collection of items. rustis uses the trait CollectionResponse to implement this behavior.

Current implementation provides the following deserializations from a RESP Buffer:

  • Vec<T>
  • [T;N]
  • SmallVec<A>
  • BTreeSet<T>
  • HashSet<T, S>

where each of theses implementations must also implement Response

§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, ListCommands},
    Result,
};
use smallvec::{SmallVec};
use std::collections::{HashSet, BTreeSet};

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.lpush("key", [12, 13, 14]).await?;
    let _values: Vec<Option<i32>> = client.rpop("key", 3).await?;

    client.lpush("key", [12, 13, 14]).await?;
    let _values: HashSet<Option<i32>> = client.rpop("key", 3).await?;

    client.lpush("key", [12, 13, 14]).await?;
    let _values: BTreeSet<Option<i32>> = client.rpop("key", 3).await?;

    client.lpush("key", [12, 13, 14]).await?;
    let _values: SmallVec<[Option<i32>;3]> = client.rpop("key", 3).await?;

    Ok(())
}

§KeyValueCollectionResponse

Several Redis commands return a collection of key/value pairs rustis uses the trait KeyValueCollectionResponse to implement this behavior.

Current implementation provides the following deserializations from a RESP Buffer:

  • BTreeMap<K, V>
  • HashMap<K, V, S>
  • SmallVec<A> where A: Array<Item = (K, V)>
  • Vec<(K, V>)>

where each of theses implementations must also implement Response

§Example
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, HashCommands},
    Result,
};
use smallvec::{SmallVec};
use std::collections::{HashMap, BTreeMap};

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    // Connect the client to a Redis server from its IP and port
    let client = Client::connect("127.0.0.1:6379").await?;

    // Flush all existing data in Redis
    client.flushdb(FlushingMode::Sync).await?;

    client.hset("key", [("field1", 12), ("field2", 13)]).await?;

    let _values: BTreeMap<String, i32> = client.hgetall("key").await?;
    let _values: HashMap<String, i32> = client.hgetall("key").await?;
    let _values: SmallVec<[(String, i32); 10]> = client.hgetall("key").await?;
    let _values: Vec<(String, i32)> = client.hgetall("key").await?;

    Ok(())
}

Structs§

BulkString
Represents the Bulk String RESP type
Command
Generic command meant to be sent to the Redis Server
CommandArgs
Collection of arguments of Command.
CommandArgsIntoIterator
CommandArgs into iterator
CommandArgsIterator
CommandArgs iterator
Json
Wrapper type that deserializes a Redis bulk string as JSON into a Rust value.
JsonRef
Wrapper type that serializes a Rust value as JSON before sending it to Redis.
KeyValueArgsIterator
A wrapper type that adapts any clonable iterator of (K, V) pairs (where both K and V implement SingleArg) to the KeyValueArgsCollection and ToArgs traits.
KeyValueArgsRefIterator
A wrapper type that adapts any clonable iterator of references to (K, V) pairs (where both K and V implement SingleArg) to the KeyValueArgsCollection and ToArgs traits.
RespArrayChunks
An iterator over a RESP Array in byte slices
RespBuf
Represents a RESP Buffer incoming from the network
RespDeserializer
Serde deserializer for RESP3
RespSerializer
Serde serializer for RESP3
SingleArgIterator
A wrapper type that adapts any clonable iterator of SingleArg items to the SingleArgCollection and ToArgs traits.
SingleArgRefIterator
A wrapper type that adapts any clonable iterator of references to SingleArg items to the SingleArgCollection and ToArgs traits.

Enums§

Value
Generic Redis Object Model

Traits§

CollectionResponse
Marker for a collection response
KeyValueArgsCollection
Marker for key/value collections of Args
KeyValueCollectionResponse
Marker for key/value collection response
MultipleArgsCollection
Generic Marker for Collections of ToArgs
PrimitiveResponse
Marker for a primitive response
Response
Marker for a RESP Response
SingleArg
Generic Marker for single arguments (no collections nor tuples)
SingleArgCollection
Marker for collections of single items of ToArgs
ToArgs
Types compatible with command args

Functions§

cmd
Shortcut function for creating a command.
deserialize_byte_buf
Deserialize a byte buffer (Vec<u8>)
deserialize_bytes
Deserialize a byte slice (&[u8])
deserialize_vec_of_pairs
Deserialize a Vec of pairs from a sequence
deserialize_vec_of_triplets
Deserialize a Vec of triplets from a sequence
key_value_args_iter
Convenience function for constructing a KeyValueArgsIterator from any clonable iterator of (K, V) pairs.
key_value_args_ref_iter
Convenience function for constructing a KeyValueArgsRefIterator from any clonable iterator of references to (K, V) pairs.
serialize_byte_buf
Serialize a byte buffer (&[u8])
single_arg_iter
Convenience function for constructing a SingleArgIterator from any clonable iterator of SingleArg items.
single_arg_ref_iter
Convenience function for constructing a SingleArgRefIterator from any clonable iterator of references to SingleArg items.