redis/
lib.rs

1//! redis-rs is a Rust implementation of a client library for Redis.  It exposes
2//! a general purpose interface to Redis and also provides specific helpers for
3//! commonly used functionality.
4//!
5//! The crate is called `redis` and you can depend on it via cargo:
6//!
7//! ```ini
8//! [dependencies.redis]
9//! version = "*"
10//! ```
11//!
12//! If you want to use the git version:
13//!
14//! ```ini
15//! [dependencies.redis]
16//! git = "https://github.com/redis-rs/redis-rs.git"
17//! ```
18//!
19//! # Basic Operation
20//!
21//! redis-rs exposes two API levels: a low- and a high-level part.
22//! The high-level part does not expose all the functionality of redis and
23//! might take some liberties in how it speaks the protocol.  The low-level
24//! part of the API allows you to express any request on the redis level.
25//! You can fluently switch between both API levels at any point.
26//!
27//! # TLS / SSL
28//!
29//! The user can enable TLS support using either RusTLS or native support (usually OpenSSL),
30//! using the `tls-rustls` or `tls-native-tls` features respectively. In order to enable TLS
31//! for async usage, the user must enable matching features for their runtime - either `tokio-native-tls-comp`,
32//! `tokio-rustls-comp`, `smol-native-tls-comp`, or `smol-rustls-comp`. Additionally, the
33//! `tls-rustls-webpki-roots` allows usage of of webpki-roots for the root certificate store.
34//!
35//! # TCP settings
36//!
37//! The user can set parameters of the underlying TCP connection by setting [io::tcp::TcpSettings] on the connection configuration objects,
38//! and set the TCP parameters in a more specific manner there.
39//!
40//! ## Connection Handling
41//!
42//! For connecting to redis you can use a client object which then can produce
43//! actual connections.  Connections and clients as well as results of
44//! connections and clients are considered [ConnectionLike] objects and
45//! can be used anywhere a request is made.
46//!
47//! The full canonical way to get a connection is to create a client and
48//! to ask for a connection from it:
49//!
50//! ```rust,no_run
51//! extern crate redis;
52//!
53//! fn do_something() -> redis::RedisResult<()> {
54//!     let client = redis::Client::open("redis://127.0.0.1/")?;
55//!     let mut con = client.get_connection()?;
56//!
57//!     /* do something here */
58//!
59//!     Ok(())
60//! }
61//! ```
62//!
63//! ## Connection Pooling
64//!
65//! When using a sync connection, it is recommended to use a connection pool in order to handle
66//! disconnects or multi-threaded usage. This can be done using the `r2d2` feature.
67//!
68//! ```rust,no_run
69//! # #[cfg(feature = "r2d2")]
70//! # fn do_something() {
71//! use redis::TypedCommands;
72//!
73//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
74//! let pool = r2d2::Pool::builder().build(client).unwrap();
75//! let mut conn = pool.get().unwrap();
76//!
77//! conn.set("KEY", "VALUE").unwrap();
78//! let val = conn.get("KEY").unwrap();
79//! # }
80//! ```
81//!
82//! For async connections, connection pooling isn't necessary. The `MultiplexedConnection` is
83//! cheap to clone and can be used safely concurrently from multiple threads, so a single connection can be easily
84//! reused. For automatic reconnections consider using `ConnectionManager` with the `connection-manager` feature.
85//! Async cluster connections also don't require pooling and are thread-safe and reusable.
86//!
87//! ## Optional Features
88//!
89//! There are a few features defined that can enable additional functionality
90//! if so desired.  Some of them are turned on by default.
91//!
92//! * `acl`: enables acl support (enabled by default)
93//! * `tokio-comp`: enables support for async usage with the Tokio runtime (optional)
94//! * `smol-comp`: enables support for async usage with the Smol runtime (optional)
95//! * `geospatial`: enables geospatial support (enabled by default)
96//! * `script`: enables script support (enabled by default)
97//! * `streams`: enables high-level interface for interaction with Redis streams (enabled by default)
98//! * `r2d2`: enables r2d2 connection pool support (optional)
99//! * `bb8`: enables bb8 connection pool support (optional)
100//! * `ahash`: enables ahash map/set support & uses ahash internally (+7-10% performance) (optional)
101//! * `cluster`: enables redis cluster support (optional)
102//! * `cluster-async`: enables async redis cluster support (optional)
103//! * `connection-manager`: enables support for automatic reconnection (optional)
104//! * `rust_decimal`, `bigdecimal`, `num-bigint`: enables type conversions to large number representation from different crates (optional)
105//! * `uuid`: enables type conversion to UUID (optional)
106//! * `sentinel`: enables high-level interfaces for communication with Redis sentinels (optional)
107//! * `json`: enables high-level interfaces for communication with the JSON module (optional)
108//! * `cache-aio`: enables **experimental** client side caching for MultiplexedConnection, ConnectionManager and async ClusterConnection (optional)
109//! * `disable-client-setinfo`: disables the `CLIENT SETINFO` handshake during connection initialization
110//!
111//! ## Connection Parameters
112//!
113//! redis-rs knows different ways to define where a connection should
114//! go.  The parameter to [Client::open] needs to implement the
115//! [IntoConnectionInfo] trait of which there are three implementations:
116//!
117//! * string slices in `redis://` URL format.
118//! * URL objects from the redis-url crate.
119//! * [ConnectionInfo] objects.
120//!
121//! The URL format is `redis://[<username>][:<password>@]<hostname>[:port][/[<db>][?protocol=<protocol>]]`
122//!
123//! If Unix socket support is available you can use a unix URL in this format:
124//!
125//! `redis+unix:///<path>[?db=<db>[&pass=<password>][&user=<username>][&protocol=<protocol>]]`
126//!
127//! For compatibility with some other libraries for Redis, the "unix" scheme
128//! is also supported:
129//!
130//! `unix:///<path>[?db=<db>][&pass=<password>][&user=<username>][&protocol=<protocol>]]`
131//!
132//! ## Executing Low-Level Commands
133//!
134//! To execute low-level commands you can use the [cmd::cmd] function which allows
135//! you to build redis requests.  Once you have configured a command object
136//! to your liking you can send a query into any [ConnectionLike] object:
137//!
138//! ```rust,no_run
139//! fn do_something(con: &mut redis::Connection) -> redis::RedisResult<()> {
140//!     redis::cmd("SET").arg("my_key").arg(42).exec(con)?;
141//!     Ok(())
142//! }
143//! ```
144//!
145//! Upon querying the return value is a result object.  If you do not care
146//! about the actual return value (other than that it is not a failure)
147//! you can always type annotate it to the unit type `()`.
148//!
149//! Note that commands with a sub-command (like "MEMORY USAGE", "ACL WHOAMI",
150//! "LATENCY HISTORY", etc) must specify the sub-command as a separate `arg`:
151//!
152//! ```rust,no_run
153//! fn do_something(con: &mut redis::Connection) -> redis::RedisResult<usize> {
154//!     // This will result in a server error: "unknown command `MEMORY USAGE`"
155//!     // because "USAGE" is technically a sub-command of "MEMORY".
156//!     redis::cmd("MEMORY USAGE").arg("my_key").query::<usize>(con)?;
157//!
158//!     // However, this will work as you'd expect
159//!     redis::cmd("MEMORY").arg("USAGE").arg("my_key").query(con)
160//! }
161//! ```
162//!
163//! ## Executing High-Level Commands
164//!
165//! The high-level interface is similar.  For it to become available you
166//! need to use the `TypedCommands` or `Commands` traits in which case all `ConnectionLike`
167//! objects the library provides will also have high-level methods which
168//! make working with the protocol easier:
169//!
170//! ```rust,no_run
171//! extern crate redis;
172//! use redis::TypedCommands;
173//!
174//! fn do_something(con: &mut redis::Connection) -> redis::RedisResult<()> {
175//!     con.set("my_key", 42)?;
176//!     Ok(())
177//! }
178//! ```
179//!
180//! Note that high-level commands are work in progress and many are still
181//! missing!
182//!
183//! ## Pre-typed Commands
184//!
185//! Because redis inherently is mostly type-less and the protocol is not
186//! exactly friendly to developers, this library provides flexible support
187//! for casting values to the intended results. This is driven through the [FromRedisValue] and [ToRedisArgs] traits.
188//!
189//! In most cases, you may like to use defaults provided by the library, to avoid the clutter and development overhead
190//! of specifying types for each command.
191//!
192//! The library facilitates this by providing the [commands::TypedCommands] and [commands::AsyncTypedCommands]. These traits provide functions
193//! with pre-defined and opinionated return types. For example, `set` returns `()`, avoiding the need
194//! for developers to explicitly type each call as returning `()`.
195//!
196//! ```rust,no_run
197//! use redis::TypedCommands;
198//!
199//! fn fetch_an_integer() -> redis::RedisResult<isize> {
200//!     // connect to redis
201//!     let client = redis::Client::open("redis://127.0.0.1/")?;
202//!     let mut con = client.get_connection()?;
203//!     // `set` returns a `()`, so we don't need to specify the return type manually unlike in the previous example.
204//!     con.set("my_key", 42)?;
205//!     // `get_int` returns Result<Option<isize>>, as the key may not be found, or some error may occur.
206//!     Ok(con.get_int("my_key").unwrap().unwrap())
207//! }
208//! ```
209//!
210//! ## Custom Type Conversions
211//!
212//! In some cases, the user might want to define their own return value types to various Redis calls.
213//! The library facilitates this by providing the [commands::Commands] and [commands::AsyncCommands]
214//! as alternatives to [commands::TypedCommands] and [commands::AsyncTypedCommands] respectively.
215//!
216//! The `arg` method of the command will accept a wide range of types through
217//! the [ToRedisArgs] trait and the `query` method of a command can convert the
218//! value to what you expect the function to return through the [FromRedisValue]
219//! trait. This is quite flexible and allows vectors, tuples, hashsets, hashmaps
220//! as well as optional values:
221//!
222//! ```rust,no_run
223//! # use redis::Commands;
224//! # use std::collections::{HashMap, HashSet};
225//! # fn do_something() -> redis::RedisResult<()> {
226//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
227//! # let mut con = client.get_connection().unwrap();
228//! let count : i32 = con.get("my_counter")?;
229//! let count = con.get("my_counter").unwrap_or(0i32);
230//! let k : Option<String> = con.get("missing_key")?;
231//! let name : String = con.get("my_name")?;
232//! let bin : Vec<u8> = con.get("my_binary")?;
233//! let map : HashMap<String, i32> = con.hgetall("my_hash")?;
234//! let keys : Vec<String> = con.hkeys("my_hash")?;
235//! let mems : HashSet<i32> = con.smembers("my_set")?;
236//! let (k1, k2) : (String, String) = con.mget(&["k1", "k2"])?;
237//! # Ok(())
238//! # }
239//! ```
240//!
241//! # RESP3 support
242//! Since Redis / Valkey version 6, a newer communication protocol called RESP3 is supported.
243//! Using this protocol allows the user both to receive a more varied `Value` results, for users
244//! who use the low-level `Value` type, and to receive out of band messages on the same connection. This allows the user to receive PubSub
245//! messages on the same connection, instead of creating a new PubSub connection (see "RESP3 async pubsub").
246//!
247
248//!
249//! ## RESP3 pubsub
250//! If you're targeting a Redis/Valkey server of version 6 or above, you can receive
251//! pubsub messages from it without creating another connection, by setting a push sender on the connection.
252//!
253//! ```rust,no_run
254//! # #[cfg(feature = "aio")]
255//! # {
256//! # use futures::prelude::*;
257//! # use redis::AsyncTypedCommands;
258//!
259//! # async fn func() -> redis::RedisResult<()> {
260//! let client = redis::Client::open("redis://127.0.0.1/?protocol=resp3").unwrap();
261//! let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
262//! let config = redis::AsyncConnectionConfig::new().set_push_sender(tx);
263//! let mut con = client.get_multiplexed_async_connection_with_config(&config).await?;
264//! con.subscribe(&["channel_1", "channel_2"]).await?;
265//!
266//! loop {
267//!   println!("Received {:?}", rx.recv().await.unwrap());
268//! }
269//! # Ok(()) }
270//! # }
271//! ```
272//!
273//! sync example:
274//!
275//! ```rust,no_run
276//! # {
277//! # use redis::TypedCommands;
278//!
279//! # async fn func() -> redis::RedisResult<()> {
280//! let client = redis::Client::open("redis://127.0.0.1/?protocol=resp3").unwrap();
281//! let (tx, rx) = std::sync::mpsc::channel();
282//! let mut con = client.get_connection().unwrap();
283//! con.set_push_sender(tx);
284//! con.subscribe_resp3(&["channel_1", "channel_2"])?;
285//!
286//! loop {
287//!   std::thread::sleep(std::time::Duration::from_millis(10));
288//!   // the connection only reads when actively polled, so it must constantly send and receive requests.
289//!   _ = con.ping().unwrap();
290//!   println!("Received {:?}", rx.try_recv().unwrap());
291//! }
292//! # Ok(()) }
293//! # }
294//!  ```
295//!
296//! # Iteration Protocol
297//!
298//! In addition to sending a single query, iterators are also supported.  When
299//! used with regular bulk responses they don't give you much over querying and
300//! converting into a vector (both use a vector internally) but they can also
301//! be used with `SCAN` like commands in which case iteration will send more
302//! queries until the cursor is exhausted:
303//!
304//! ```rust,ignore
305//! # fn do_something() -> redis::RedisResult<()> {
306//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
307//! # let mut con = client.get_connection().unwrap();
308//! let mut iter : redis::Iter<isize> = redis::cmd("SSCAN").arg("my_set")
309//!     .cursor_arg(0).clone().iter(&mut con)?;
310//! for x in iter {
311//!     // do something with the item
312//! }
313//! # Ok(()) }
314//! ```
315//!
316//! As you can see the cursor argument needs to be defined with `cursor_arg`
317//! instead of `arg` so that the library knows which argument needs updating
318//! as the query is run for more items.
319//!
320//! # Pipelining
321//!
322//! In addition to simple queries you can also send command pipelines.  This
323//! is provided through the `pipe` function.  It works very similar to sending
324//! individual commands but you can send more than one in one go.  This also
325//! allows you to ignore individual results so that matching on the end result
326//! is easier:
327//!
328//! ```rust,no_run
329//! # fn do_something() -> redis::RedisResult<()> {
330//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
331//! # let mut con = client.get_connection().unwrap();
332//! let (k1, k2) : (i32, i32) = redis::pipe()
333//!     .cmd("SET").arg("key_1").arg(42).ignore()
334//!     .cmd("SET").arg("key_2").arg(43).ignore()
335//!     .cmd("GET").arg("key_1")
336//!     .cmd("GET").arg("key_2").query(&mut con)?;
337//! # Ok(()) }
338//! ```
339//!
340//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
341//! easily do that by switching the pipeline into `atomic` mode.  From the
342//! caller's point of view nothing changes, the pipeline itself will take
343//! care of the rest for you:
344//!
345//! ```rust,no_run
346//! # fn do_something() -> redis::RedisResult<()> {
347//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
348//! # let mut con = client.get_connection().unwrap();
349//! let (k1, k2) : (i32, i32) = redis::pipe()
350//!     .atomic()
351//!     .cmd("SET").arg("key_1").arg(42).ignore()
352//!     .cmd("SET").arg("key_2").arg(43).ignore()
353//!     .cmd("GET").arg("key_1")
354//!     .cmd("GET").arg("key_2").query(&mut con)?;
355//! # Ok(()) }
356//! ```
357//!
358//! You can also use high-level commands on pipelines:
359//!
360//! ```rust,no_run
361//! # fn do_something() -> redis::RedisResult<()> {
362//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
363//! # let mut con = client.get_connection().unwrap();
364//! let (k1, k2) : (i32, i32) = redis::pipe()
365//!     .atomic()
366//!     .set("key_1", 42).ignore()
367//!     .set("key_2", 43).ignore()
368//!     .get("key_1")
369//!     .get("key_2").query(&mut con)?;
370//! # Ok(()) }
371//! ```
372//!
373//! NOTE: Pipelines return a collection of results, even when there's only a single response.
374//!       Make sure to wrap single-result pipeline responses in a collection. For example:
375//!
376//! ```rust,no_run
377//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
378//! # let mut con = client.get_connection().unwrap();
379//! let (k1,): (i32,) = redis::pipe()
380//!     .cmd("SET").arg("key_1").arg(42).ignore()
381//!     .cmd("GET").arg("key_1").query(&mut con).unwrap();
382//! ```
383//!
384//! # Transactions
385//!
386//! Transactions are available through atomic pipelines.  In order to use
387//! them in a more simple way you can use the `transaction` function of a
388//! connection:
389//!
390//! ```rust,no_run
391//! # fn do_something() -> redis::RedisResult<()> {
392//! use redis::Commands;
393//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
394//! # let mut con = client.get_connection().unwrap();
395//! let key = "the_key";
396//! let (new_val,) : (isize,) = redis::transaction(&mut con, &[key], |con, pipe| {
397//!     let old_val : isize = con.get(key)?;
398//!     pipe
399//!         .set(key, old_val + 1).ignore()
400//!         .get(key).query(con)
401//! })?;
402//! println!("The incremented number is: {}", new_val);
403//! # Ok(()) }
404//! ```
405//!
406//! For more information see the `transaction` function.
407//!
408//! # PubSub
409//!
410//! Pubsub is provided through the `PubSub` connection object for sync usage, or the `aio::PubSub`
411//! for async usage.
412//!
413//! Example usage:
414//!
415//! ```rust,no_run
416//! # fn do_something() -> redis::RedisResult<()> {
417//! let client = redis::Client::open("redis://127.0.0.1/")?;
418//! let mut con = client.get_connection()?;
419//! let mut pubsub = con.as_pubsub();
420//! pubsub.subscribe(&["channel_1", "channel_2"])?;
421//!
422//! loop {
423//!     let msg = pubsub.get_message()?;
424//!     let payload : String = msg.get_payload()?;
425//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
426//! }
427//! # }
428//! ```
429//! In order to update subscriptions while concurrently waiting for messages, the async PubSub can be split into separate sink & stream components. The sink can be receive subscription requests while the stream is awaited for messages.
430//!
431//! ```rust,no_run
432//! # #[cfg(feature = "aio")]
433//! use futures_util::StreamExt;
434//! # #[cfg(feature = "aio")]
435//! # async fn do_something() -> redis::RedisResult<()> {
436//! let client = redis::Client::open("redis://127.0.0.1/")?;
437//! let (mut sink, mut stream) = client.get_async_pubsub().await?.split();
438//! sink.subscribe("channel_1").await?;
439//!
440//! loop {
441//!     let msg = stream.next().await.unwrap();
442//!     let payload : String = msg.get_payload().unwrap();
443//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
444//! }
445//! # Ok(()) }
446//! ```
447//!
448#![cfg_attr(
449    feature = "script",
450    doc = r##"
451# Scripts
452
453Lua scripts are supported through the `Script` type in a convenient
454way.  It will automatically load the script if it does not exist and invoke it.
455
456Example:
457
458```rust,no_run
459# fn do_something() -> redis::RedisResult<()> {
460# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
461# let mut con = client.get_connection().unwrap();
462let script = redis::Script::new(r"
463    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
464");
465let result: isize = script.arg(1).arg(2).invoke(&mut con)?;
466assert_eq!(result, 3);
467# Ok(()) }
468```
469
470Scripts can also be pipelined:
471
472```rust,no_run
473# fn do_something() -> redis::RedisResult<()> {
474# let client = redis::Client::open("redis://127.0.0.1/").unwrap();
475# let mut con = client.get_connection().unwrap();
476let script = redis::Script::new(r"
477    return tonumber(ARGV[1]) + tonumber(ARGV[2]);
478");
479let (a, b): (isize, isize) = redis::pipe()
480    .invoke_script(script.arg(1).arg(2))
481    .invoke_script(script.arg(2).arg(3))
482    .query(&mut con)?;
483
484assert_eq!(a, 3);
485assert_eq!(b, 5);
486# Ok(()) }
487```
488
489Note: unlike a call to [`invoke`](ScriptInvocation::invoke), if the script isn't loaded during the pipeline operation,
490it will not automatically be loaded and retried. The script can be loaded using the
491[`load`](ScriptInvocation::load) operation.
492"##
493)]
494//!
495#![cfg_attr(
496    feature = "aio",
497    doc = r##"
498# Async
499
500In addition to the synchronous interface that's been explained above there also exists an
501asynchronous interface based on [`futures`][] and [`tokio`][] or [`smol`](https://docs.rs/smol/latest/smol/).
502 All async connections are cheap to clone, and clones can be used concurrently from multiple threads.
503
504This interface exists under the `aio` (async io) module (which requires that the `aio` feature
505is enabled) and largely mirrors the synchronous with a few concessions to make it fit the
506constraints of `futures`.
507
508```rust,no_run
509use futures::prelude::*;
510use redis::AsyncTypedCommands;
511
512# #[tokio::main]
513# async fn main() -> redis::RedisResult<()> {
514let client = redis::Client::open("redis://127.0.0.1/").unwrap();
515let mut con = client.get_multiplexed_async_connection().await?;
516
517con.set("key1", b"foo").await?;
518
519redis::cmd("SET").arg(&["key2", "bar"]).exec_async(&mut con).await?;
520
521let result = redis::cmd("MGET")
522  .arg(&["key1", "key2"])
523  .query_async(&mut con)
524  .await;
525assert_eq!(result, Ok(("foo".to_string(), b"bar".to_vec())));
526# Ok(()) }
527```
528
529## Runtime support
530The crate supports multiple runtimes, including `tokio` and `smol`. For Tokio, the crate will
531spawn tasks on the current thread runtime. For smol, the crate will spawn tasks on the the global runtime.
532It is recommended that the crate be used with support only for a single runtime. If the crate is compiled with multiple runtimes,
533the user should call [`crate::aio::prefer_tokio`] or [`crate::aio::prefer_smol`] to set the preferred runtime.
534These functions set global state which automatically chooses the correct runtime for the async connection.
535
536"##
537)]
538//!
539//! [`futures`]:https://crates.io/crates/futures
540//! [`tokio`]:https://tokio.rs
541#![cfg_attr(
542    feature = "sentinel",
543    doc = r##"
544# Sentinel
545Sentinel types allow users to connect to Redis sentinels and find primaries and replicas.
546
547```rust,no_run
548use redis::{ Commands, RedisConnectionInfo };
549use redis::sentinel::{ SentinelServerType, SentinelClient, SentinelNodeConnectionInfo };
550
551let nodes = vec!["redis://127.0.0.1:6379/", "redis://127.0.0.1:6378/", "redis://127.0.0.1:6377/"];
552let sentinel_node_connection_info = SentinelNodeConnectionInfo::default()
553  .set_tls_mode(redis::TlsMode::Insecure);
554let mut sentinel = SentinelClient::build(
555    nodes,
556    String::from("primary1"),
557    Some(sentinel_node_connection_info),
558    redis::sentinel::SentinelServerType::Master,
559)
560.unwrap();
561
562let primary = sentinel.get_connection().unwrap();
563```
564
565An async API also exists:
566
567```rust,no_run
568use futures::prelude::*;
569use redis::{ Commands, RedisConnectionInfo };
570use redis::sentinel::{ SentinelServerType, SentinelClient, SentinelNodeConnectionInfo };
571
572# #[tokio::main]
573# async fn main() -> redis::RedisResult<()> {
574let nodes = vec!["redis://127.0.0.1:6379/", "redis://127.0.0.1:6378/", "redis://127.0.0.1:6377/"];
575let sentinel_node_connection_info = SentinelNodeConnectionInfo::default()
576  .set_tls_mode(redis::TlsMode::Insecure);
577let mut sentinel = SentinelClient::build(
578    nodes,
579    String::from("primary1"),
580    Some(sentinel_node_connection_info),
581    redis::sentinel::SentinelServerType::Master,
582)
583.unwrap();
584
585let primary = sentinel.get_async_connection().await.unwrap();
586# Ok(()) }
587```
588"##
589)]
590//!
591//! # Upgrading to version 1
592//!
593//! * Iterators are now safe by default, without an opt out. This means that the iterators return `RedisResult<Value>` instead of `Value`. See [this PR](https://github.com/redis-rs/redis-rs/pull/1641) for background. If you previously used the "safe_iterators" feature to opt-in to this behavior, just remove the feature declaration. Otherwise you will need to adjust your usage of iterators to account for potential conversion failures.
594//! * Parsing values using [FromRedisValue] no longer returns [RedisError] on failure, in order to save the users checking for various server & client errors in such scenarios. if you rely on the error type when using this trait, you will need to adjust your error handling code. [ParsingError] should only be printed, since it does not contain any user actionable info outside of its error message.
595//! * If you used the `tcp_nodelay`, `keep-alive`, or `disable-client-setinfo` features, you'll need to set these values on the connection info you pass to the client use [ConnectionInfo::set_tcp_settings].
596//! * If you create [ConnectionInfo], [RedisConnectionInfo], or [sentinel::SentinelNodeConnectionInfo] objects explicitly, now you need to use the builder pattern setters instead of setting fields.
597//! * if you used `MultiplexedConnection::new_with_response_timeout`, it is replaced by [aio::MultiplexedConnection::new_with_config]. `Client::get_multiplexed_tokio_connection_with_response_timeouts`, `Client::get_multiplexed_tokio_connection`, `Client::create_multiplexed_tokio_connection_with_response_timeout`, `Client::create_multiplexed_tokio_connection` were replaced by [Client::get_multiplexed_async_connection_with_config].
598//! * If you're using `tokio::time::pause()` or otherwise manipulating time, you might need to opt out of timeouts using `AsyncConnectionConfig::new().set_connection_timeout(None).set_response_timeout(None)`.
599//! * Async connections now have default timeouts. If you're using blocking commands or other potentially long running commands, you should adjust the timeouts accordingly.
600//! * If you're manually setting `ConnectionManager`'s retry setting, then please re-examine the values you set. `exponential_base` has been made a f32, and `factor` was replaced by `min_delay`, in order to match the documented behavior, instead of the actual erroneous behavior of past versions.
601//! * Vector set types have been moved into the `vector_sets` module, instead of being exposed directly.
602//! * ErrorKind::TypeError was renamed ErrorKind::UnexpectedReturnType, to clarify its meaning. Also fixed some cases where it and ErrorKind::Parse were used interchangeably.
603//! * Connecting to a wildcard address (`0.0.0.0` or `::`) is now explicitly disallowed and will return an error. This change prevents connection timeouts and provides a clearer error message. This affects both standalone and cluster connections. Users relying on this behavior should now connect to a specific, non-wildcard address.
604//! * If you implemented [crate::FromRedisValue] directly, or used `FromRedisValue::from_redis_value`/`FromRedisValue::from_owned_redis_value`, notice that the trait's semantics changed - now the trait requires an owned value by default, instead of a reference. See [the PR](https://github.com/redis-rs/redis-rs/pull/1784) for details.
605//! * The implicit replacement of `GET` with `MGET` or `SET` with `MSET` has been replaced, and limited these and other commands to only take values that serialize into single redis values, as enforced by a compilation failure. Example:
606//!
607//! ```rust,no_run,compile_fail
608//! use redis::Commands;
609//! fn main() -> redis::RedisResult<()> {
610//!     let client = redis::Client::open("redis://127.0.0.1/")?;
611//!     let mut con = client.get_connection()?;
612//!     // `get` should fail compilation, because it receives multiple values
613//!     _ = con.get(["foo","bar"]);
614//!     Ok(())
615//! }
616//! ```
617//!
618//!
619
620#![deny(non_camel_case_types)]
621#![warn(missing_docs)]
622#![cfg_attr(docsrs, warn(rustdoc::broken_intra_doc_links))]
623// When on docs.rs we want to show tuple variadics in the docs.
624// This currently requires internal/unstable features in Rustdoc.
625#![cfg_attr(
626    docsrs,
627    feature(doc_cfg, rustdoc_internals),
628    expect(
629        internal_features,
630        reason = "rustdoc_internals is needed for fake_variadic"
631    )
632)]
633
634// public api
635#[cfg(feature = "aio")]
636pub use crate::client::AsyncConnectionConfig;
637pub use crate::client::Client;
638#[cfg(feature = "cache-aio")]
639pub use crate::cmd::CommandCacheConfig;
640pub use crate::cmd::{cmd, pack_command, pipe, Arg, Cmd, Iter};
641pub use crate::commands::{
642    Commands, ControlFlow, CopyOptions, Direction, FlushAllOptions, FlushDbOptions,
643    HashFieldExpirationOptions, LposOptions, MSetOptions, PubSubCommands, ScanOptions, SetOptions,
644    SortedSetAddOptions, TypedCommands, UpdateCheck,
645};
646pub use crate::connection::{
647    parse_redis_url, transaction, Connection, ConnectionAddr, ConnectionInfo, ConnectionLike,
648    IntoConnectionInfo, Msg, PubSub, RedisConnectionInfo, TlsMode,
649};
650pub use crate::parser::{parse_redis_value, Parser};
651pub use crate::pipeline::Pipeline;
652
653#[cfg(feature = "script")]
654#[cfg_attr(docsrs, doc(cfg(feature = "script")))]
655pub use crate::script::{Script, ScriptInvocation};
656
657// preserve grouping and order
658#[rustfmt::skip]
659pub use crate::types::{
660    // utility functions
661    from_redis_value_ref,
662    from_redis_value,
663
664    // conversion traits
665    FromRedisValue,
666
667    // utility types
668    InfoDict,
669    NumericBehavior,
670    Expiry,
671    SetExpiry,
672    ExistenceCheck,
673    FieldExistenceCheck,
674    ExpireOption,
675    Role,
676    ReplicaInfo,
677    IntegerReplyOrNoOp,
678	ValueType,
679    RedisResult,
680    RedisWrite,
681    ToRedisArgs,
682    ToSingleRedisArg,
683    ValueComparison,
684
685    // low level values
686    Value,
687    PushKind,
688    VerbatimFormat,
689    ProtocolVersion,
690    PushInfo,
691};
692
693pub use crate::types::{calculate_value_digest, is_valid_16_bytes_hex_digest};
694
695pub use crate::errors::{
696    make_extension_error, ErrorKind, ParsingError, RedisError, RetryMethod, ServerError,
697    ServerErrorKind,
698};
699
700#[cfg(feature = "aio")]
701#[cfg_attr(docsrs, doc(cfg(feature = "aio")))]
702pub use crate::{
703    cmd::AsyncIter, commands::AsyncCommands, commands::AsyncTypedCommands,
704    parser::parse_redis_value_async, types::RedisFuture,
705};
706
707mod macros;
708mod pipeline;
709
710#[cfg(feature = "acl")]
711#[cfg_attr(docsrs, doc(cfg(feature = "acl")))]
712pub use commands::acl;
713
714#[cfg(feature = "aio")]
715#[cfg_attr(docsrs, doc(cfg(feature = "aio")))]
716pub mod aio;
717
718#[cfg(feature = "json")]
719#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
720pub use crate::commands::JsonCommands;
721
722#[cfg(all(feature = "json", feature = "aio"))]
723#[cfg_attr(docsrs, doc(cfg(all(feature = "json", feature = "aio"))))]
724pub use crate::commands::JsonAsyncCommands;
725
726#[cfg(feature = "vector-sets")]
727#[cfg_attr(docsrs, doc(cfg(feature = "vector-sets")))]
728pub use crate::commands::vector_sets;
729
730#[cfg(feature = "geospatial")]
731#[cfg_attr(docsrs, doc(cfg(feature = "geospatial")))]
732pub use commands::geo;
733
734#[cfg(any(feature = "connection-manager", feature = "cluster-async"))]
735mod subscription_tracker;
736
737#[cfg(feature = "cluster")]
738mod cluster_handling;
739
740#[cfg(feature = "cluster")]
741#[cfg_attr(docsrs, doc(cfg(feature = "cluster")))]
742pub use cluster_handling::sync_connection as cluster;
743
744/// Routing information for cluster commands.
745#[cfg(feature = "cluster")]
746#[cfg_attr(docsrs, doc(cfg(feature = "cluster")))]
747pub use cluster_handling::routing as cluster_routing;
748
749#[cfg(feature = "r2d2")]
750#[cfg_attr(docsrs, doc(cfg(feature = "r2d2")))]
751mod r2d2;
752
753#[cfg(all(feature = "bb8", feature = "aio"))]
754#[cfg_attr(docsrs, doc(cfg(all(feature = "bb8", feature = "aio"))))]
755mod bb8;
756
757#[cfg(feature = "streams")]
758#[cfg_attr(docsrs, doc(cfg(feature = "streams")))]
759pub use commands::streams;
760
761#[cfg(feature = "cluster-async")]
762#[cfg_attr(docsrs, doc(cfg(all(feature = "cluster", feature = "aio"))))]
763pub use cluster_handling::async_connection as cluster_async;
764
765#[cfg(feature = "sentinel")]
766#[cfg_attr(docsrs, doc(cfg(feature = "sentinel")))]
767pub mod sentinel;
768
769#[cfg(feature = "tls-rustls")]
770mod tls;
771
772#[cfg(feature = "tls-rustls")]
773#[cfg_attr(docsrs, doc(cfg(feature = "tls-rustls")))]
774pub use crate::tls::{ClientTlsConfig, TlsCertificates};
775
776#[cfg(feature = "cache-aio")]
777#[cfg_attr(docsrs, doc(cfg(feature = "cache-aio")))]
778pub mod caching;
779
780mod client;
781mod cmd;
782mod commands;
783mod connection;
784mod errors;
785/// Module for defining I/O behavior.
786pub mod io;
787mod parser;
788mod script;
789mod types;
790
791macro_rules! check_resp3 {
792    ($protocol: expr) => {
793        if !$protocol.supports_resp3() {
794            return Err(RedisError::from((
795                crate::ErrorKind::InvalidClientConfig,
796                "RESP3 is required for this command",
797            )));
798        }
799    };
800
801    ($protocol: expr, $message: expr) => {
802        if !$protocol.supports_resp3() {
803            return Err(RedisError::from((
804                crate::ErrorKind::InvalidClientConfig,
805                $message,
806            )));
807        }
808    };
809}
810
811pub(crate) use check_resp3;
812
813#[cfg(test)]
814mod tests {
815    use super::*;
816    #[test]
817    fn test_is_send() {
818        const fn assert_send<T: Send>() {}
819
820        assert_send::<Connection>();
821        #[cfg(feature = "cluster")]
822        assert_send::<cluster::ClusterConnection>();
823    }
824}