rustis 0.19.3

Redis async driver for Rust
Documentation
#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
/*!
rustis is a Redis client for Rust.
# Philosophy
* Low allocations
* Full async library
* Lock free implementation
* Rust idiomatic API

# Features
* Support all [Redis Commands](https://redis.io/commands/) until Redis 8.0
* Async support ([tokio](https://tokio.rs/) or [async-std](https://async.rs/))
* Different client types:
  * Single client
  * [Multiplexed](https://redis.com/blog/multiplexing-explained/) client
  * Pooled client manager (based on [bb8](https://docs.rs/bb8/latest/bb8/))
* Automatic command batching
* Advanced reconnection & retry strategy
* [Pipelining](https://redis.io/docs/manual/pipelining/) support
* Configuration with Redis URL or dedicated builder
* [TLS](https://redis.io/docs/latest/operate/oss_and_stack/management/security/encryption/) support
* [Transaction](https://redis.io/docs/manual/transactions/) support
* [Pub/sub](https://redis.io/docs/manual/pubsub/) support
* [Sentinel](https://redis.io/docs/manual/sentinel/) support
* [LUA Scripts/Functions](https://redis.io/docs/manual/programmability/) support
* [Cluster](https://redis.io/docs/manual/scaling/) support
* [Client-side caching](https://redis.io/docs/latest/develop/reference/client-side-caching/) support

# Optional Features
| Feature | Description |
| ------- | ----------- |
| `tokio-runtime` | [Tokio](https://tokio.rs/) runime (default) |
| `async-std-runtime` | [async-std](https://async.rs/) runtime (optional) |
| `tokio-rustls` | Tokio Rustls TLS support (optional) |
| `tokio-native-tls` | Tokio native_tls TLS support (optional) |
| `async-std-native-tls` | async-std native_tls TLS support (optional) |
| `json` | Enables JSON (de)serialization support via `serde_json` |
| `client-cache` | Enables client-side caching support |
| `pool` | Pooled client manager (optional) |

# Protocol Compatibility

Rustis uses the RESP3 protocol **exclusively**.

The `HELLO 3` command is automatically sent when establishing a connection.
Therefore, your Redis server **must support RESP3** (Redis ≥6.0+ with RESP3 enabled).

If you use Redis 5 or older, or your Redis 6+ server still defaults to RESP2,
**Rustis will not work.**

To verify your server supports RESP3:
```bash
redis-cli --raw HELLO 3
```
If you see server info (role, version, etc.), you're good to go.
If you get an error, upgrade Redis.

# Basic Usage

```
use rustis::{
    client::Client,
    commands::{FlushingMode, ServerCommands, StringCommands},
    Result,
};

#[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?;

    // sends the command SET to Redis. This command is defined in the StringCommands trait
    client.set("key", "value").await?;

    // sends the command GET to Redis. This command is defined in the StringCommands trait
    let value: String = client.get("key").await?;
    println!("value: {value:?}");

    Ok(())
}
```

# Client
See the module [`client`] to discover which are the 3
usages of the [`Client`](client::Client) struct and how to configure it.

You will also learn how to use pipeline, pub/sub and transactions.

# RESP
RESP is the [Redis Serialization Protocol](https://redis.io/docs/reference/protocol-spec/).

See the module [`resp`] to discover how **rustis**
allows programmers to communicate with Redis in a Rust idiomatic way.

You will learn how to:
* Manipulate the **rustis** object model, the enum [`Value`](resp::Value), which is a generic Rust data structure over RESP.
* Convert Rust type into Rust Commands with the [`Command`](resp::Command) struct and the [`Args`](resp::Args) trait.
* Convert Rust command responses into Rust type with serde and helpful marker traits.

# Commands
In order to send [Commands](https://redis.io/commands/) to the Redis server,
**rustis** offers two API levels:
* High-level Built-in commands that implement all [Redis 7.0](https://redis.com/blog/redis-7-generally-available/) commands +
  [Redis Stack](https://redis.io/docs/stack/) commands.
* Low-level Generic command API to express any request that may not exist in **rustis**:
  * new official commands not yet implemented by **rustis**.
  * commands exposed by additional [Redis modules](https://redis.io/resources/modules/)
    not included in [Redis Stack](https://redis.io/docs/stack/).

## Built-in commands
See the module [`commands`] to discover how Redis built-in commands are organized in different traits.

## Generic command API
To use the generic command API, you can use the [`cmd`](crate::resp::cmd) function to specify the name of the command,
followed by one or multiple calls to the [`Commmand::arg`](crate::resp::Command::arg) associated function to add arguments to the command.

This command can then be passed as a parameter to one of the following associated functions,
depending on the client, transaction or pipeline struct used:
* [`send`](crate::client::Client::send)
* [`send_and_forget`](crate::client::Client::send_and_forget)
* [`send_batch`](crate::client::Client::send_batch)

```
use rustis::{client::Client, resp::cmd, Result};

#[cfg_attr(feature = "tokio-runtime", tokio::main)]
#[cfg_attr(feature = "async-std-runtime", async_std::main)]
async fn main() -> Result<()> {
    let client = Client::connect("127.0.0.1:6379").await?;

    client
        .send::<()>(
            cmd("MSET")
                .arg("key1")
                .arg("value1")
                .arg("key2")
                .arg("value2")
                .arg("key3")
                .arg("value3")
                .arg("key4")
                .arg("value4"),
            None,
        )
        .await?;

    let values: Vec<String> = client
        .send(
            cmd("MGET").arg("key1").arg("key2").arg("key3").arg("key4"),
            None,
        )
        .await?;

    assert_eq!(vec!["value1", "value2", "value3", "value4"], values);

    Ok(())
}
```

# Client-side caching
See the module [`cache`] to discover how you can implement client-side caching.
*/

#[cfg(feature = "client-cache")]
pub mod cache;
pub mod client;
pub mod commands;
mod error;
mod network;
pub mod resp;

#[cfg(feature = "pool")]
pub use bb8;
pub use error::*;
use network::*;

/// Library general result type.
pub type Result<T> = std::result::Result<T, Error>;
/// Library general future type.
pub type Future<'a, T> = futures_util::future::BoxFuture<'a, Result<T>>;

#[cfg(all(feature = "tokio-runtime", feature = "async-std-runtime"))]
compile_error!(
    "feature \"tokio-runtime\" and feature \"async-std-runtime\" cannot be enabled at the same time."
);

#[cfg(all(feature = "pool", feature = "async-std-runtime"))]
compile_error!("feature \"pool\" is only compatible with \"tokio-runtime\" (bb8 constraint).");

#[cfg(all(feature = "tokio-native-tls", feature = "tokio-rustls"))]
compile_error!(
    "Features `tokio-native-tls` and `tokio-rustls` cannot be enabled at the same time."
);

#[cfg(test)]
mod tests;