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}