darkredis/
lib.rs

1#![cfg_attr(not(feature = "bench"), warn(missing_docs))]
2#![warn(missing_debug_implementations)]
3#![deny(unsafe_code)]
4//For async doctests, it is easier to write out the doctest explicitly using tokio::main.
5#![allow(clippy::needless_doctest_main)]
6
7//! Asyncronous redis client built using futures and async await, with optional connection pooling.
8//! ```
9//! use darkredis::*;
10//!
11//! # #[cfg_attr(feature = "runtime_tokio", tokio::main)]
12//! # #[cfg_attr(feature = "runtime_async_std", async_std::main)]
13//! # async fn main() {
14//! // Create a connection pool with 4 connections
15//! let pool = ConnectionPool::create("127.0.0.1:6379".into(), None, 4).await.unwrap();
16//! let mut connection = pool.get().await; // Grab a connection from the pool
17//!
18//! connection.set("some-key", "Hello, world!").await.unwrap();
19//! assert_eq!(connection.get("some-key").await.unwrap(), Some("Hello, world!".into()));
20//! # connection.del("some-key").await.unwrap();
21//! # }
22//! ```
23
24#[cfg(all(feature = "runtime_tokio", feature = "runtime_async_std"))]
25compile_error!("The `runtime_tokio` and `runtime_async_std` features are mutually exclusive!");
26
27#[cfg(not(any(feature = "runtime_tokio", feature = "runtime_async_std")))]
28compile_error!("Expected one of the features `runtime_tokio` or `runtime_async_std`");
29
30#[macro_use]
31extern crate quick_error;
32
33mod command;
34mod connection;
35mod connectionpool;
36mod error;
37
38///Export the ToSocketAddrs trait to be used for deadpool-darkredis. You probably won't need this unless you're implementing an adapter crate for a different connection pool.
39#[cfg(feature = "runtime_async_std")]
40pub use async_std::net::ToSocketAddrs;
41#[cfg(feature = "runtime_tokio")]
42pub use tokio::net::ToSocketAddrs;
43
44#[cfg(feature = "bench")]
45pub mod test;
46
47#[cfg(all(not(feature = "bench"), test))]
48mod test;
49
50pub use command::{Command, CommandList};
51pub use connection::{
52    builder::MSetBuilder, Connection, HScanBuilder, HScanStream, Message, MessageStream, PMessage,
53    PMessageStream, ResponseStream, ScanBuilder, ScanStream,
54};
55pub use connectionpool::ConnectionPool;
56pub use error::Error;
57
58///Result type used in the whole crate.
59pub type Result<T> = std::result::Result<T, Error>;
60
61///Enum depicting the various possible responses one can get from Redis.
62#[derive(Debug, PartialEq)]
63pub enum Value {
64    ///A Redis `OK` response.
65    Ok,
66    ///Nil Response.
67    Nil,
68    ///Array response.
69    Array(Vec<Value>),
70    ///Integer response.
71    Integer(isize),
72    ///String response. This cannot be a `String` type, because Redis strings need not be valid UTF-8, unlike Rust.
73    String(Vec<u8>),
74}
75
76impl Value {
77    ///Returns the inner `isize` of a [`Value::Integer`](enum.Value.html#Integer.v).
78    ///# Panics
79    ///Panics if `self` is not a [`Value::Integer`](enum.Value.html#Integer.v)
80    #[inline]
81    pub fn unwrap_integer(self) -> isize {
82        if let Value::Integer(i) = self {
83            i
84        } else {
85            panic!("expected integer value, got {:?}", self)
86        }
87    }
88
89    ///Returns the inner `Vec<Value>` of a `Value::Array`.
90    ///# Panics
91    ///Panics if `self` is not a [`Value::Array`](enum.Value.html#Array.v)
92    #[inline]
93    pub fn unwrap_array(self) -> Vec<Value> {
94        if let Value::Array(a) = self {
95            a
96        } else {
97            panic!("expected array value, got {:?}", self)
98        }
99    }
100
101    ///Returns the inner `Vec<u8>` of a [`Value::String`](enum.Value.html#String.v).
102    ///# Panics
103    ///Panics if `self` is not a [`Value::String`](enum.Value.html#String.v)
104    #[inline]
105    pub fn unwrap_string(self) -> Vec<u8> {
106        if let Value::String(s) = self {
107            s
108        } else {
109            panic!("expected string value, got {:?}", self)
110        }
111    }
112
113    ///Returns `true` if `self` is nonzero.
114    ///# Panics
115    ///Panics if `self is not a [`Value::Integer`](enum.Value.html#Integer.v)
116    #[inline]
117    pub fn unwrap_bool(self) -> bool {
118        self.unwrap_integer() != 0
119    }
120
121    ///Returns `self` as a vector of Redis strings.
122    ///# Panics
123    ///Panics if `self` is not a [`Value::Array`](enum.Value.html#Array.v) or not all the elements are strings.
124    #[inline]
125    pub fn unwrap_string_array(self) -> Vec<Vec<u8>> {
126        self.unwrap_array()
127            .into_iter()
128            .map(|v| v.unwrap_string())
129            .collect()
130    }
131
132    ///Like `unwrap_string`, but returns an `Option` instead of panicking.
133    #[inline]
134    pub fn optional_string(self) -> Option<Vec<u8>> {
135        match self {
136            Value::String(s) => Some(s),
137            _ => None,
138        }
139    }
140
141    ///Like `unwrap_array`, but returns an `Option` instead of panicking.
142    #[inline]
143    pub fn optional_array(self) -> Option<Vec<Value>> {
144        match self {
145            Value::Array(a) => Some(a),
146            _ => None,
147        }
148    }
149
150    ///Like `unwrap_integer`, but returns an `Option` instead of panicking.
151    #[inline]
152    pub fn optional_integer(self) -> Option<isize> {
153        match self {
154            Value::Integer(i) => Some(i),
155            _ => None,
156        }
157    }
158
159    ///Like `unwrap_bool`, but returns an `Option` instead of panicking.
160    #[inline]
161    pub fn optional_bool(self) -> Option<bool> {
162        self.optional_integer().map(|i| i != 0)
163    }
164}
165
166///An enum corresponding to every Redis type.
167#[derive(Debug, Clone, PartialEq)]
168pub enum DataType {
169    ///A simple string.
170    String,
171    ///A List.
172    List,
173    ///A set.
174    Set,
175    ///A sorted set.
176    ZSet,
177    ///A hash set.
178    Hash,
179    ///A stream.
180    Stream,
181}