Browse Source

Introduce `get_map` which replaces `get_map_or` (#61)

This new function receives a single Fn to pass the data, which is an
option, instead of two functions.

Having a single function let the develeper take ownership of data when
data is found and it is not found, the two more popular cases.

Prior this PR, any data to be stored would have been cloned for each
function.
César D. Rodas 1 year ago
parent
commit
d1605378eb
4 changed files with 728 additions and 865 deletions
  1. 175 220
      src/cmd/hash.rs
  2. 333 382
      src/cmd/list.rs
  3. 216 257
      src/cmd/set.rs
  4. 4 6
      src/db/mod.rs

+ 175 - 220
src/cmd/hash.rs

@@ -21,27 +21,24 @@ use std::{
 pub async fn hdel(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let mut is_empty = false;
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Hash(h) => {
-                let mut h = h.write();
-                let mut total: i64 = 0;
-
-                for key in args.into_iter() {
-                    if h.remove(&key).is_some() {
-                        total += 1;
-                    }
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut h = h.write();
+            let mut total: i64 = 0;
+
+            for key in args.into_iter() {
+                if h.remove(&key).is_some() {
+                    total += 1;
                 }
+            }
 
-                is_empty = h.len() == 0;
+            is_empty = h.len() == 0;
 
-                Ok(total.into())
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )?;
+            Ok(total.into())
+        }
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })?;
 
     if is_empty {
         let _ = conn.db().del(&[key]);
@@ -54,56 +51,47 @@ pub async fn hdel(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
 
 /// Returns if field is an existing field in the hash stored at key.
 pub async fn hexists(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => Ok(if h.read().get(&args[1]).is_some() {
-                1.into()
-            } else {
-                0.into()
-            }),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => Ok(if h.read().get(&args[1]).is_some() {
+            1.into()
+        } else {
+            0.into()
+        }),
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns the value associated with field in the hash stored at key.
 pub async fn hget(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => Ok(h
-                .read()
-                .get(&args[1])
-                .map(|v| Value::new(v))
-                .unwrap_or_default()),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Null),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => Ok(h
+            .read()
+            .get(&args[1])
+            .map(|v| Value::new(v))
+            .unwrap_or_default()),
+        None => Ok(Value::Null),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns all fields and values of the hash stored at key. In the returned value, every field
 /// name is followed by its value, so the length of the reply is twice the size of the hash.
 pub async fn hgetall(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => {
-                let mut ret = vec![];
-
-                for (key, value) in h.read().iter() {
-                    ret.push(Value::new(key));
-                    ret.push(Value::new(value));
-                }
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut ret = vec![];
 
-                Ok(ret.into())
+            for (key, value) in h.read().iter() {
+                ret.push(Value::new(key));
+                ret.push(Value::new(value));
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Array(vec![])),
-    )
+
+            Ok(ret.into())
+        }
+        None => Ok(Value::Array(vec![])),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Increment the specified field of a hash stored at key, and representing a number, by the
@@ -136,61 +124,50 @@ pub async fn hincrby_float(conn: &Connection, args: VecDeque<Bytes>) -> Result<V
 
 /// Returns all field names in the hash stored at key.
 pub async fn hkeys(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => {
-                let mut ret = vec![];
-
-                for key in h.read().keys() {
-                    ret.push(Value::new(key));
-                }
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut ret = vec![];
 
-                Ok(ret.into())
+            for key in h.read().keys() {
+                ret.push(Value::new(key));
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Array(vec![])),
-    )
+
+            Ok(ret.into())
+        }
+        None => Ok(Value::Array(vec![])),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns the number of fields contained in the hash stored at key.
 pub async fn hlen(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => Ok(h.read().len().into()),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => Ok(h.read().len().into()),
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns the values associated with the specified fields in the hash stored at key.
 pub async fn hmget(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Hash(h) => {
-                let h = h.read();
-
-                Ok(args
-                    .iter()
-                    .map(|key| h.get(key).map(|v| Value::new(v)).unwrap_or_default())
-                    .collect::<Vec<Value>>()
-                    .into())
-            }
-            _ => Err(Error::WrongType),
-        },
-        || {
+    conn.db().get_map(&key, |v| match v {
+        Some(Value::Hash(h)) => {
+            let h = h.read();
+
             Ok(args
                 .iter()
-                .map(|_| Value::Null)
+                .map(|key| h.get(key).map(|v| Value::new(v)).unwrap_or_default())
                 .collect::<Vec<Value>>()
                 .into())
-        },
-    )
+        }
+        None => Ok(args
+            .iter()
+            .map(|_| Value::Null)
+            .collect::<Vec<Value>>()
+            .into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns random keys (or values) from a hash
@@ -213,49 +190,46 @@ pub async fn hrandfield(conn: &Connection, args: VecDeque<Bytes>) -> Result<Valu
         _ => (1, true, 1),
     };
 
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => {
-                let mut ret = vec![];
-                let mut i = 0;
-                let mut rand_sorted = BTreeMap::new();
-                let mut rng = rand::thread_rng();
-                let h = h.read();
-
-                for _ in 0..repeat {
-                    for (key, value) in h.iter() {
-                        let rand = rng.gen::<u64>();
-                        rand_sorted.insert((rand, i), (key, value));
-                        i += 1;
-                    }
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut ret = vec![];
+            let mut i = 0;
+            let mut rand_sorted = BTreeMap::new();
+            let mut rng = rand::thread_rng();
+            let h = h.read();
+
+            for _ in 0..repeat {
+                for (key, value) in h.iter() {
+                    let rand = rng.gen::<u64>();
+                    rand_sorted.insert((rand, i), (key, value));
+                    i += 1;
                 }
+            }
 
-                i = 0;
-                for val in rand_sorted.values() {
-                    if single {
-                        return Ok(Value::new(val.0));
-                    }
-
-                    if i == count {
-                        break;
-                    }
+            i = 0;
+            for val in rand_sorted.values() {
+                if single {
+                    return Ok(Value::new(val.0));
+                }
 
-                    ret.push(Value::new(val.0));
+                if i == count {
+                    break;
+                }
 
-                    if with_values {
-                        ret.push(Value::new(val.1));
-                    }
+                ret.push(Value::new(val.0));
 
-                    i += 1;
+                if with_values {
+                    ret.push(Value::new(val.1));
                 }
 
-                Ok(ret.into())
+                i += 1;
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Array(vec![])),
-    )
+
+            Ok(ret.into())
+        }
+        None => Ok(Value::Array(vec![])),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Sets field in the hash stored at key to value. If key does not exist, a new key holding a hash
@@ -265,28 +239,22 @@ pub async fn hmset(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value
     if args.len() % 2 == 1 {
         return Err(Error::InvalidArgsCount("hset".to_owned()));
     }
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Hash(h) => {
-                let mut h = h.write();
-                let mut args = args.clone();
-                loop {
-                    if args.is_empty() {
-                        break;
-                    }
-                    let key = args.pop_front().ok_or(Error::Syntax)?;
-                    let value = args.pop_front().ok_or(Error::Syntax)?;
-                    h.insert(key, value);
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut h = h.write();
+            loop {
+                if args.is_empty() {
+                    break;
                 }
-                Ok(Value::Ok)
+                let key = args.pop_front().ok_or(Error::Syntax)?;
+                let value = args.pop_front().ok_or(Error::Syntax)?;
+                h.insert(key, value);
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+            Ok(Value::Ok)
+        }
+        None => {
             #[allow(clippy::mutable_key_type)]
             let mut h = HashMap::new();
-            let mut args = args.clone();
             loop {
                 if args.is_empty() {
                     break;
@@ -298,8 +266,9 @@ pub async fn hmset(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value
             let len = h.len();
             conn.db().set(key.clone(), h.into(), None);
             Ok(Value::Ok)
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
 
@@ -313,31 +282,25 @@ pub async fn hset(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
     if args.len() % 2 == 1 {
         return Err(Error::InvalidArgsCount("hset".to_owned()));
     }
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Hash(h) => {
-                let mut h = h.write();
-                let mut e: i64 = 0;
-                let mut args = args.clone();
-                loop {
-                    if args.is_empty() {
-                        break;
-                    }
-                    let key = args.pop_front().ok_or(Error::Syntax)?;
-                    let value = args.pop_front().ok_or(Error::Syntax)?;
-                    if h.insert(key, value).is_none() {
-                        e += 1;
-                    }
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut h = h.write();
+            let mut e: i64 = 0;
+            loop {
+                if args.is_empty() {
+                    break;
+                }
+                let key = args.pop_front().ok_or(Error::Syntax)?;
+                let value = args.pop_front().ok_or(Error::Syntax)?;
+                if h.insert(key, value).is_none() {
+                    e += 1;
                 }
-                Ok(e.into())
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+            Ok(e.into())
+        }
+        None => {
             #[allow(clippy::mutable_key_type)]
             let mut h = HashMap::new();
-            let mut args = args.clone();
             loop {
                 if args.is_empty() {
                     break;
@@ -349,8 +312,9 @@ pub async fn hset(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
             let len = h.len();
             conn.db().set(key.clone(), h.into(), None);
             Ok(len.into())
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
 
@@ -364,30 +328,27 @@ pub async fn hsetnx(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Valu
     let key = args.pop_front().ok_or(Error::Syntax)?;
     let sub_key = args.pop_front().ok_or(Error::Syntax)?;
     let value = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Hash(h) => {
-                let mut h = h.write();
-
-                if h.get(&sub_key).is_some() {
-                    Ok(0.into())
-                } else {
-                    h.insert(sub_key.clone(), value.clone());
-                    Ok(1.into())
-                }
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut h = h.write();
+
+            if h.get(&sub_key).is_some() {
+                Ok(0.into())
+            } else {
+                h.insert(sub_key, value);
+                Ok(1.into())
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+        }
+        None => {
             #[allow(clippy::mutable_key_type)]
             let mut h = HashMap::new();
-            h.insert(sub_key.clone(), value.clone());
+            h.insert(sub_key, value);
             let len = h.len();
             conn.db().set(key.clone(), h.into(), None);
             Ok(len.into())
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     if result == Value::Integer(1) {
         conn.db().bump_version(&key);
@@ -399,39 +360,33 @@ pub async fn hsetnx(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Valu
 /// Returns the string length of the value associated with field in the hash stored at key. If the
 /// key or the field do not exist, 0 is returned.
 pub async fn hstrlen(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => Ok(h
-                .read()
-                .get(&args[1])
-                .map(|v| v.len())
-                .unwrap_or_default()
-                .into()),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => Ok(h
+            .read()
+            .get(&args[1])
+            .map(|v| v.len())
+            .unwrap_or_default()
+            .into()),
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns all values in the hash stored at key.
 pub async fn hvals(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Hash(h) => {
-                let mut ret = vec![];
-
-                for value in h.read().values() {
-                    ret.push(Value::new(value));
-                }
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Hash(h)) => {
+            let mut ret = vec![];
 
-                Ok(ret.into())
+            for value in h.read().values() {
+                ret.push(Value::new(value));
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Array(vec![])),
-    )
+
+            Ok(ret.into())
+        }
+        None => Ok(Value::Array(vec![])),
+        _ => Err(Error::WrongType),
+    })
 }
 
 #[cfg(test)]

+ 333 - 382
src/cmd/list.rs

@@ -28,44 +28,41 @@ fn remove_element(
 ) -> Result<Value, Error> {
     let db = conn.db();
     let mut new_len = 0;
-    let result = db.get_map_or(
-        key,
-        |v| match v {
-            Value::List(x) => {
-                let mut x = x.write();
-
-                let limit = if let Some(limit) = limit {
-                    limit
-                } else {
-                    // Return a single element
-                    let ret = Ok((if front { x.pop_front() } else { x.pop_back() })
-                        .map_or(Value::Null, |x| x.clone_value()));
-                    new_len = x.len();
-                    return ret;
-                };
-
-                let mut ret = vec![None; limit];
+    let result = db.get_map(key, |v| match v {
+        Some(Value::List(x)) => {
+            let mut x = x.write();
 
-                for i in 0..limit {
-                    if front {
-                        ret[i] = x.pop_front();
-                    } else {
-                        ret[i] = x.pop_back();
-                    }
-                }
+            let limit = if let Some(limit) = limit {
+                limit
+            } else {
+                // Return a single element
+                let ret = Ok((if front { x.pop_front() } else { x.pop_back() })
+                    .map_or(Value::Null, |x| x.clone_value()));
                 new_len = x.len();
+                return ret;
+            };
+
+            let mut ret = vec![None; limit];
 
-                Ok(ret
-                    .iter()
-                    .flatten()
-                    .map(|m| m.clone_value())
-                    .collect::<Vec<Value>>()
-                    .into())
+            for i in 0..limit {
+                if front {
+                    ret[i] = x.pop_front();
+                } else {
+                    ret[i] = x.pop_back();
+                }
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Null),
-    )?;
+            new_len = x.len();
+
+            Ok(ret
+                .iter()
+                .flatten()
+                .map(|m| m.clone_value())
+                .collect::<Vec<Value>>()
+                .into())
+        }
+        None => Ok(Value::Null),
+        _ => Err(Error::WrongType),
+    })?;
 
     if new_len == 0 {
         let _ = db.del(&[key.clone()]);
@@ -307,27 +304,24 @@ pub async fn brpop(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value
 /// designate elements starting at the tail of the list. Here, -1 means the last element, -2 means
 /// the penultimate and so forth.
 pub async fn lindex(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::List(x) => {
-                let mut index: i64 = bytes_to_number(&args[1])?;
-                let x = x.read();
-
-                let index = if index < 0 {
-                    x.len()
-                        .checked_sub((index * -1) as usize)
-                        .unwrap_or(x.len())
-                } else {
-                    index as usize
-                };
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::List(x)) => {
+            let mut index: i64 = bytes_to_number(&args[1])?;
+            let x = x.read();
+
+            let index = if index < 0 {
+                x.len()
+                    .checked_sub((index * -1) as usize)
+                    .unwrap_or(x.len())
+            } else {
+                index as usize
+            };
 
-                Ok(x.get(index).map_or(Value::Null, |x| x.clone_value()))
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Null),
-    )
+            Ok(x.get(index).map_or(Value::Null, |x| x.clone_value()))
+        }
+        None => Ok(Value::Null),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Inserts element in the list stored at key either before or after the reference value pivot.
@@ -348,41 +342,38 @@ pub async fn linsert(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Val
         _ => return Err(Error::Syntax),
     };
 
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::List(x) => {
-                let pivot = checksum::Ref::new(&pivot);
-                let mut x = x.write();
-                let mut found = false;
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::List(x)) => {
+            let pivot = checksum::Ref::new(&pivot);
+            let mut x = x.write();
+            let mut found = false;
 
-                for (key, val) in x.iter().enumerate() {
-                    if *val == pivot {
-                        let id = if is_before { key } else { key + 1 };
+            for (key, val) in x.iter().enumerate() {
+                if *val == pivot {
+                    let id = if is_before { key } else { key + 1 };
 
-                        let value = checksum::Value::new(value);
-
-                        if id > x.len() {
-                            x.push_back(value);
-                        } else {
-                            x.insert(id as usize, value);
-                        }
+                    let value = checksum::Value::new(value);
 
-                        found = true;
-                        break;
+                    if id > x.len() {
+                        x.push_back(value);
+                    } else {
+                        x.insert(id as usize, value);
                     }
-                }
 
-                if found {
-                    Ok(x.len().into())
-                } else {
-                    Ok((-1).into())
+                    found = true;
+                    break;
                 }
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )?;
+
+            if found {
+                Ok(x.len().into())
+            } else {
+                Ok((-1).into())
+            }
+        }
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
 
@@ -392,14 +383,11 @@ pub async fn linsert(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Val
 /// Returns the length of the list stored at key. If key does not exist, it is interpreted as an
 /// empty list and 0 is returned. An error is returned when the value stored at key is not a list.
 pub async fn llen(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::List(x) => Ok(x.read().len().into()),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::List(x)) => Ok(x.read().len().into()),
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Atomically returns and removes the first/last element (head/tail depending on the wherefrom
@@ -433,56 +421,50 @@ pub async fn lmove(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value
 
     let mut to_create = None;
 
-    let result = db.get_map_or(
-        &source,
-        |v| match v {
-            Value::List(source) => conn.db().get_map_or(
-                &destination,
-                |v| match v {
-                    Value::List(target) => {
-                        let element = if source_is_left {
-                            source.write().pop_front()
-                        } else {
-                            source.write().pop_back()
-                        };
-
-                        if let Some(element) = element {
-                            let ret = element.clone_value();
-                            if target_is_left {
-                                target.write().push_front(element);
-                            } else {
-                                target.write().push_back(element);
-                            }
-                            Ok(ret)
-                        } else {
-                            Ok(Value::Null)
-                        }
-                    }
-                    _ => Err(Error::WrongType),
-                },
-                || {
-                    let mut source = source.write();
-                    let element = if source_is_left {
-                        source.pop_front()
-                    } else {
-                        source.pop_back()
-                    };
-
-                    if let Some(element) = element {
-                        let ret = element.clone_value();
-                        let mut h = VecDeque::new();
-                        h.push_front(element);
-                        to_create = Some(h);
-                        Ok(ret)
+    let result = db.get_map(&source, |v| match v {
+        Some(Value::List(source)) => conn.db().get_map(&destination, |v| match v {
+            Some(Value::List(target)) => {
+                let element = if source_is_left {
+                    source.write().pop_front()
+                } else {
+                    source.write().pop_back()
+                };
+
+                if let Some(element) = element {
+                    let ret = element.clone_value();
+                    if target_is_left {
+                        target.write().push_front(element);
                     } else {
-                        Ok(Value::Null)
+                        target.write().push_back(element);
                     }
-                },
-            ),
+                    Ok(ret)
+                } else {
+                    Ok(Value::Null)
+                }
+            }
+            None => {
+                let mut source = source.write();
+                let element = if source_is_left {
+                    source.pop_front()
+                } else {
+                    source.pop_back()
+                };
+
+                if let Some(element) = element {
+                    let ret = element.clone_value();
+                    let mut h = VecDeque::new();
+                    h.push_front(element);
+                    to_create = Some(h);
+                    Ok(ret)
+                } else {
+                    Ok(Value::Null)
+                }
+            }
             _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Null),
-    );
+        }),
+        None => Ok(Value::Null),
+        _ => Err(Error::WrongType),
+    });
 
     if let Some(to_create) = to_create {
         conn.db().set(destination.clone(), to_create.into(), None);
@@ -555,90 +537,85 @@ pub async fn lpos(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Err
 
     let max_len = max_len.unwrap_or_default();
 
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::List(x) => {
-                let x = x.read();
-                let mut result: Vec<Value> = vec![];
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::List(x)) => {
+            let x = x.read();
+            let mut result: Vec<Value> = vec![];
 
-                let mut values = x
-                    .iter()
-                    .enumerate()
-                    .collect::<Vec<(usize, &checksum::Value)>>();
+            let mut values = x
+                .iter()
+                .enumerate()
+                .collect::<Vec<(usize, &checksum::Value)>>();
 
-                if must_reverse {
-                    values.reverse();
-                }
+            if must_reverse {
+                values.reverse();
+            }
 
-                let mut checks = 1;
-
-                for (id, val) in values.iter() {
-                    if **val == element {
-                        // Match!
-                        if let Some(count) = count {
-                            result.push((*id).into());
-                            if result.len() == count && count != 0 && rank.is_none() {
-                                // There is no point in keep looping. No RANK provided, COUNT is not 0
-                                // therefore we can return the vector of result as IS
-                                return Ok(result.into());
-                            }
-                        } else if let Some(rank) = rank {
-                            result.push((*id).into());
-                            if result.len() == rank {
-                                return Ok((*id).into());
-                            }
-                        } else {
-                            // return first match!
+            let mut checks = 1;
+
+            for (id, val) in values.iter() {
+                if **val == element {
+                    // Match!
+                    if let Some(count) = count {
+                        result.push((*id).into());
+                        if result.len() == count && count != 0 && rank.is_none() {
+                            // There is no point in keep looping. No RANK provided, COUNT is not 0
+                            // therefore we can return the vector of result as IS
+                            return Ok(result.into());
+                        }
+                    } else if let Some(rank) = rank {
+                        result.push((*id).into());
+                        if result.len() == rank {
                             return Ok((*id).into());
                         }
+                    } else {
+                        // return first match!
+                        return Ok((*id).into());
                     }
-                    if checks == max_len {
-                        break;
-                    }
-                    checks += 1;
                 }
+                if checks == max_len {
+                    break;
+                }
+                checks += 1;
+            }
 
-                if let Some(rank) = rank {
-                    let rank = rank - 1;
+            if let Some(rank) = rank {
+                let rank = rank - 1;
 
-                    let result = if rank < result.len() {
-                        (&result[rank..]).to_vec()
-                    } else {
-                        vec![]
-                    };
-
-                    return Ok(if let Some(count) = count {
-                        if count > 0 && count < result.len() {
-                            (&result[0..count]).to_vec().into()
-                        } else {
-                            result.to_vec().into()
-                        }
-                    } else {
-                        result
-                            .to_vec()
-                            .get(0)
-                            .map(|c| c.clone())
-                            .unwrap_or_default()
-                    });
-                }
+                let result = if rank < result.len() {
+                    (&result[rank..]).to_vec()
+                } else {
+                    vec![]
+                };
 
-                if count.is_some() {
-                    Ok(result.into())
+                return Ok(if let Some(count) = count {
+                    if count > 0 && count < result.len() {
+                        (&result[0..count]).to_vec().into()
+                    } else {
+                        result.to_vec().into()
+                    }
                 } else {
-                    Ok(Value::Null)
-                }
+                    result
+                        .to_vec()
+                        .get(0)
+                        .map(|c| c.clone())
+                        .unwrap_or_default()
+                });
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
-            Ok(if count.is_some() {
-                Value::Array(vec![])
+
+            if count.is_some() {
+                Ok(result.into())
             } else {
-                Value::Null
-            })
-        },
-    )
+                Ok(Value::Null)
+            }
+        }
+        None => Ok(if count.is_some() {
+            Value::Array(vec![])
+        } else {
+            Value::Null
+        }),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Insert all the specified values at the head of the list stored at key. If key does not exist,
@@ -652,30 +629,27 @@ pub async fn lpos(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Err
 /// as third element.
 pub async fn lpush(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::List(x) => {
-                let mut x = x.write();
-                for val in args.clone().into_iter() {
-                    x.push_front(checksum::Value::new(val.clone()));
-                }
-                Ok(x.len().into())
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::List(x)) => {
+            let mut x = x.write();
+            for val in args.into_iter() {
+                x.push_front(checksum::Value::new(val.clone()));
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+            Ok(x.len().into())
+        }
+        None => {
             let mut h = VecDeque::new();
 
-            for val in args.clone().into_iter() {
+            for val in args.into_iter() {
                 h.push_front(checksum::Value::new(val));
             }
 
             let len = h.len();
             conn.db().set(key.clone(), h.into(), None);
             Ok(len.into())
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
     Ok(result)
@@ -684,22 +658,19 @@ pub async fn lpush(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value
 /// LPUSHX key element
 pub async fn lpushx(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::List(x) => {
-                let mut x = x.write();
-                for val in args.into_iter() {
-                    x.push_front(checksum::Value::new(val));
-                }
-                Ok(x.len().into())
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::List(x)) => {
+            let mut x = x.write();
+            for val in args.into_iter() {
+                x.push_front(checksum::Value::new(val));
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+            Ok(x.len().into())
+        }
+        None => {
             return Ok(0.into());
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
     Ok(result)
@@ -712,93 +683,87 @@ pub async fn lpushx(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Valu
 /// These offsets can also be negative numbers indicating offsets starting at the end of the list.
 /// For example, -1 is the last element of the list, -2 the penultimate, and so on.
 pub async fn lrange(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::List(x) => {
-                let start: i64 = bytes_to_number(&args[1])?;
-                let end: i64 = bytes_to_number(&args[2])?;
-                let mut ret = vec![];
-                let x = x.read();
-
-                let start = if start < 0 {
-                    x.len()
-                        .checked_sub((start * -1) as usize)
-                        .unwrap_or_default()
-                } else {
-                    (start as usize)
-                };
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::List(x)) => {
+            let start: i64 = bytes_to_number(&args[1])?;
+            let end: i64 = bytes_to_number(&args[2])?;
+            let mut ret = vec![];
+            let x = x.read();
+
+            let start = if start < 0 {
+                x.len()
+                    .checked_sub((start * -1) as usize)
+                    .unwrap_or_default()
+            } else {
+                (start as usize)
+            };
 
-                let end = if end < 0 {
-                    if let Some(x) = x.len().checked_sub((end * -1) as usize) {
-                        x
-                    } else {
-                        return Ok(Value::Array((vec![])));
-                    }
+            let end = if end < 0 {
+                if let Some(x) = x.len().checked_sub((end * -1) as usize) {
+                    x
                 } else {
-                    end as usize
-                };
+                    return Ok(Value::Array((vec![])));
+                }
+            } else {
+                end as usize
+            };
 
-                for (i, val) in x.iter().enumerate().skip(start) {
-                    if i > end {
-                        break;
-                    }
-                    ret.push(val.clone_value());
+            for (i, val) in x.iter().enumerate().skip(start) {
+                if i > end {
+                    break;
                 }
-                Ok(ret.into())
+                ret.push(val.clone_value());
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Array(vec![])),
-    )
+            Ok(ret.into())
+        }
+        None => Ok(Value::Array(vec![])),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Removes the first count occurrences of elements equal to element from the list stored at key
 pub async fn lrem(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    let result = conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::List(x) => {
-                let element = checksum::Ref::new(&args[2]);
-                let limit: i64 = bytes_to_number(&args[1])?;
-                let mut x = x.write();
-
-                let (is_reverse, limit) = if limit < 0 {
-                    (true, -limit)
-                } else {
-                    (false, limit)
-                };
+    let result = conn.db().get_map(&args[0], |v| match v {
+        Some(Value::List(x)) => {
+            let element = checksum::Ref::new(&args[2]);
+            let limit: i64 = bytes_to_number(&args[1])?;
+            let mut x = x.write();
+
+            let (is_reverse, limit) = if limit < 0 {
+                (true, -limit)
+            } else {
+                (false, limit)
+            };
 
-                let mut keep = vec![true; x.len()];
-                let mut removed = 0;
-                let len = x.len();
+            let mut keep = vec![true; x.len()];
+            let mut removed = 0;
+            let len = x.len();
 
-                for i in 0..len {
-                    let i = if is_reverse { len - 1 - i } else { i };
+            for i in 0..len {
+                let i = if is_reverse { len - 1 - i } else { i };
 
-                    if let Some(value) = x.get(i) {
-                        if *value == element {
-                            keep[i] = false;
-                            removed += 1;
-                            if removed == limit {
-                                break;
-                            }
+                if let Some(value) = x.get(i) {
+                    if *value == element {
+                        keep[i] = false;
+                        removed += 1;
+                        if removed == limit {
+                            break;
                         }
                     }
                 }
+            }
 
-                let mut i = 0;
-                x.retain(|_| {
-                    i += 1;
-                    keep[i - 1]
-                });
+            let mut i = 0;
+            x.retain(|_| {
+                i += 1;
+                keep[i - 1]
+            });
 
-                Ok(removed.into())
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )?;
+            Ok(removed.into())
+        }
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&args[0]);
 
@@ -814,28 +779,25 @@ pub async fn lset(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
     let index = args.pop_front().ok_or(Error::Syntax)?;
     let value = args.pop_front().ok_or(Error::Syntax)?;
 
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::List(x) => {
-                let mut index: i64 = bytes_to_number(&index)?;
-                let mut x = x.write();
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::List(x)) => {
+            let mut index: i64 = bytes_to_number(&index)?;
+            let mut x = x.write();
 
-                if index < 0 {
-                    index += x.len() as i64;
-                }
+            if index < 0 {
+                index += x.len() as i64;
+            }
 
-                if let Some(x) = x.get_mut(index as usize) {
-                    *x = checksum::Value::new(value);
-                    Ok(Value::Ok)
-                } else {
-                    Err(Error::OutOfRange)
-                }
+            if let Some(x) = x.get_mut(index as usize) {
+                *x = checksum::Value::new(value);
+                Ok(Value::Ok)
+            } else {
+                Err(Error::OutOfRange)
             }
-            _ => Err(Error::WrongType),
-        },
-        || Err(Error::NotFound),
-    )?;
+        }
+        None => Err(Error::NotFound),
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
 
@@ -846,35 +808,32 @@ pub async fn lset(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
 /// Both start and stop are zero-based indexes, where 0 is the first element of the list (the
 /// head), 1 the next element and so on.
 pub async fn ltrim(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    let result = conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::List(x) => {
-                let mut start: i64 = bytes_to_number(&args[1])?;
-                let mut end: i64 = bytes_to_number(&args[2])?;
-                let mut x = x.write();
-
-                if start < 0 {
-                    start += x.len() as i64;
-                }
+    let result = conn.db().get_map(&args[0], |v| match v {
+        Some(Value::List(x)) => {
+            let mut start: i64 = bytes_to_number(&args[1])?;
+            let mut end: i64 = bytes_to_number(&args[2])?;
+            let mut x = x.write();
+
+            if start < 0 {
+                start += x.len() as i64;
+            }
 
-                if end < 0 {
-                    end += x.len() as i64;
-                }
+            if end < 0 {
+                end += x.len() as i64;
+            }
 
-                let mut i = 0;
-                x.retain(|_| {
-                    let retain = i >= start && i <= end;
-                    i += 1;
-                    retain
-                });
+            let mut i = 0;
+            x.retain(|_| {
+                let retain = i >= start && i <= end;
+                i += 1;
+                retain
+            });
 
-                Ok(Value::Ok)
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Ok),
-    )?;
+            Ok(Value::Ok)
+        }
+        None => Ok(Value::Ok),
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&args[1]);
 
@@ -915,22 +874,17 @@ pub async fn rpoplpush(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<V
 /// is not a list, an error is returned.
 pub async fn rpushx(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::List(x) => {
-                let mut x = x.write();
-                for val in args.into_iter() {
-                    x.push_back(checksum::Value::new(val));
-                }
-                Ok(x.len().into())
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::List(x)) => {
+            let mut x = x.write();
+            for val in args.into_iter() {
+                x.push_back(checksum::Value::new(val));
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
-            return Ok(0.into());
-        },
-    )?;
+            Ok(x.len().into())
+        }
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
     Ok(result)
@@ -941,30 +895,27 @@ pub async fn rpushx(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Valu
 /// is not a list, an error is returned.
 pub async fn rpush(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::List(x) => {
-                let mut x = x.write();
-                for val in args.clone().into_iter() {
-                    x.push_back(checksum::Value::new(val));
-                }
-                Ok(x.len().into())
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::List(x)) => {
+            let mut x = x.write();
+            for val in args.into_iter() {
+                x.push_back(checksum::Value::new(val));
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+            Ok(x.len().into())
+        }
+        None => {
             let mut h = VecDeque::new();
 
-            for val in args.clone().into_iter() {
+            for val in args.into_iter() {
                 h.push_back(checksum::Value::new(val));
             }
 
             let len = h.len();
             conn.db().set(key.clone(), h.into(), None);
             Ok(len.into())
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
     Ok(result)

+ 216 - 257
src/cmd/set.rs

@@ -32,63 +32,53 @@ where
     F1: Fn(&mut HashSet<Bytes>, &HashSet<Bytes>) -> bool,
 {
     let top_key = keys.pop_front().ok_or(Error::Syntax)?;
-    conn.db().get_map_or(
-        &top_key,
-        |v| match v {
-            Value::Set(x) => {
-                #[allow(clippy::mutable_key_type)]
-                let mut all_entries = x.read().clone();
-                for key in keys.iter() {
-                    let mut do_break = false;
-                    let mut found = false;
-                    let _ = conn.db().get_map_or(
-                        key,
-                        |v| match v {
-                            Value::Set(x) => {
-                                found = true;
-                                if !op(&mut all_entries, &x.read()) {
-                                    do_break = true;
-                                }
-                                Ok(Value::Null)
-                            }
-                            _ => Err(Error::WrongType),
-                        },
-                        || Ok(Value::Null),
-                    )?;
-                    if !found && !op(&mut all_entries, &HashSet::new()) {
-                        break;
-                    }
-                    if do_break {
-                        break;
+    conn.db().get_map(&top_key, |v| match v {
+        Some(Value::Set(x)) => {
+            #[allow(clippy::mutable_key_type)]
+            let mut all_entries = x.read().clone();
+            for key in keys.iter() {
+                let mut do_break = false;
+                let mut found = false;
+                let _ = conn.db().get_map(key, |v| match v {
+                    Some(Value::Set(x)) => {
+                        found = true;
+                        if !op(&mut all_entries, &x.read()) {
+                            do_break = true;
+                        }
+                        Ok(Value::Null)
                     }
+                    None => Ok(Value::Null),
+                    _ => Err(Error::WrongType),
+                })?;
+                if !found && !op(&mut all_entries, &HashSet::new()) {
+                    break;
+                }
+                if do_break {
+                    break;
                 }
-
-                Ok(all_entries
-                    .iter()
-                    .map(|entry| Value::new(&entry))
-                    .collect::<Vec<Value>>()
-                    .into())
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+
+            Ok(all_entries
+                .iter()
+                .map(|entry| Value::new(&entry))
+                .collect::<Vec<Value>>()
+                .into())
+        }
+        None => {
             #[allow(clippy::mutable_key_type)]
             let mut all_entries: HashSet<Bytes> = HashSet::new();
             for key in keys.iter() {
                 let mut do_break = false;
-                let _ = conn.db().get_map_or(
-                    key,
-                    |v| match v {
-                        Value::Set(x) => {
-                            if !op(&mut all_entries, &x.read()) {
-                                do_break = true;
-                            }
-                            Ok(Value::Null)
+                let _ = conn.db().get_map(key, |v| match v {
+                    Some(Value::Set(x)) => {
+                        if !op(&mut all_entries, &x.read()) {
+                            do_break = true;
                         }
-                        _ => Err(Error::WrongType),
-                    },
-                    || Ok(Value::Null),
-                )?;
+                        Ok(Value::Null)
+                    }
+                    None => Ok(Value::Null),
+                    _ => Err(Error::WrongType),
+                })?;
                 if do_break {
                     break;
                 }
@@ -99,8 +89,9 @@ where
                 .map(|entry| Value::new(&entry))
                 .collect::<Vec<Value>>()
                 .into())
-        },
-    )
+        }
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Add the specified members to the set stored at key. Specified members that are already a member
@@ -109,30 +100,26 @@ where
 pub async fn sadd(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
     let key_for_not_found = key.clone();
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Set(x) => {
-                let mut x = x.write();
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Set(x)) => {
+            let mut x = x.write();
 
-                let mut len = 0;
+            let mut len = 0;
 
-                for val in args.clone().into_iter() {
-                    if x.insert(val) {
-                        len += 1;
-                    }
+            for val in args.into_iter() {
+                if x.insert(val) {
+                    len += 1;
                 }
-
-                Ok(len.into())
             }
-            _ => Err(Error::WrongType),
-        },
-        || {
+
+            Ok(len.into())
+        }
+        None => {
             #[allow(clippy::mutable_key_type)]
             let mut x = HashSet::new();
             let mut len = 0;
 
-            for val in args.clone().into_iter() {
+            for val in args.into_iter() {
                 if x.insert(val) {
                     len += 1;
                 }
@@ -140,8 +127,9 @@ pub async fn sadd(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
 
             conn.db().set(key_for_not_found, x.into(), None);
             Ok(len.into())
-        },
-    )?;
+        }
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
 
@@ -150,14 +138,11 @@ pub async fn sadd(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
 
 /// Returns the set cardinality (number of elements) of the set stored at key.
 pub async fn scard(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Set(x) => Ok(x.read().len().into()),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Set(x)) => Ok(x.read().len().into()),
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns the members of the set resulting from the difference between the first set and all the
@@ -249,39 +234,33 @@ pub async fn sinterstore(conn: &Connection, mut args: VecDeque<Bytes>) -> Result
 
 /// Returns if member is a member of the set stored at key.
 pub async fn sismember(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Set(x) => {
-                if x.read().contains(&args[1]) {
-                    Ok(1.into())
-                } else {
-                    Ok(0.into())
-                }
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Set(x)) => {
+            if x.read().contains(&args[1]) {
+                Ok(1.into())
+            } else {
+                Ok(0.into())
             }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )
+        }
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns all the members of the set value stored at key.
 ///
 /// This has the same effect as running SINTER with one argument key.
 pub async fn smembers(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Set(x) => Ok(x
-                .read()
-                .iter()
-                .map(|x| Value::new(x))
-                .collect::<Vec<Value>>()
-                .into()),
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Array(vec![])),
-    )
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Set(x)) => Ok(x
+            .read()
+            .iter()
+            .map(|x| Value::new(x))
+            .collect::<Vec<Value>>()
+            .into()),
+        None => Ok(Value::Array(vec![])),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Returns whether each member is a member of the set stored at key.
@@ -290,21 +269,18 @@ pub async fn smembers(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value,
 /// a member of the set or if key does not exist.
 pub async fn smismember(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Set(x) => {
-                let x = x.read();
-                Ok(args
-                    .iter()
-                    .map(|member| if x.contains(member) { 1 } else { 0 })
-                    .collect::<Vec<i32>>()
-                    .into())
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(args.iter().map(|_| 0.into()).collect::<Vec<Value>>().into()),
-    )
+    conn.db().get_map(&key, |v| match v {
+        Some(Value::Set(x)) => {
+            let x = x.read();
+            Ok(args
+                .iter()
+                .map(|member| if x.contains(member) { 1 } else { 0 })
+                .collect::<Vec<i32>>()
+                .into())
+        }
+        None => Ok(args.iter().map(|_| 0.into()).collect::<Vec<Value>>().into()),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Move member from the set at source to the set at destination. This operation is atomic. In
@@ -323,45 +299,39 @@ pub async fn smove(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value
     let source = args.pop_front().ok_or(Error::Syntax)?;
     let destination = args.pop_front().ok_or(Error::Syntax)?;
     let member = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &source,
-        |v| match v {
-            Value::Set(set1) => conn.db().get_map_or(
-                &destination,
-                |v| match v {
-                    Value::Set(set2) => {
-                        let mut set1 = set1.write();
-                        if !set1.contains(&member) {
-                            return Ok(0.into());
-                        }
+    let result = conn.db().get_map(&source, |v| match v {
+        Some(Value::Set(set1)) => conn.db().get_map(&destination, |v| match v {
+            Some(Value::Set(set2)) => {
+                let mut set1 = set1.write();
+                if !set1.contains(&member) {
+                    return Ok(0.into());
+                }
 
-                        if source == destination {
-                            return Ok(1.into());
-                        }
+                if source == destination {
+                    return Ok(1.into());
+                }
 
-                        let mut set2 = set2.write();
-                        set1.remove(&member);
-                        if set2.insert(member.clone()) {
-                            Ok(1.into())
-                        } else {
-                            Ok(0.into())
-                        }
-                    }
-                    _ => Err(Error::WrongType),
-                },
-                || {
-                    set1.write().remove(&member);
-                    #[allow(clippy::mutable_key_type)]
-                    let mut x = HashSet::new();
-                    x.insert(member.clone());
-                    conn.db().set(destination.clone(), x.into(), None);
+                let mut set2 = set2.write();
+                set1.remove(&member);
+                if set2.insert(member.clone()) {
                     Ok(1.into())
-                },
-            ),
+                } else {
+                    Ok(0.into())
+                }
+            }
+            None => {
+                set1.write().remove(&member);
+                #[allow(clippy::mutable_key_type)]
+                let mut x = HashSet::new();
+                x.insert(member.clone());
+                conn.db().set(destination.clone(), x.into(), None);
+                Ok(1.into())
+            }
             _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )?;
+        }),
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })?;
 
     if result == Value::Integer(1) {
         conn.db().bump_version(&source);
@@ -383,32 +353,29 @@ pub async fn spop(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
     let rand = srandmember(conn, args.clone()).await?;
     let key = args.pop_front().ok_or(Error::Syntax)?;
     let mut should_remove = false;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Set(x) => {
-                let mut x = x.write();
-                match &rand {
-                    Value::Blob(value) => {
-                        x.remove(value.as_ref());
-                    }
-                    Value::Array(values) => {
-                        for value in values.iter() {
-                            if let Value::Blob(value) = value {
-                                x.remove(value.as_ref());
-                            }
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Set(x)) => {
+            let mut x = x.write();
+            match &rand {
+                Value::Blob(value) => {
+                    x.remove(value.as_ref());
+                }
+                Value::Array(values) => {
+                    for value in values.iter() {
+                        if let Value::Blob(value) = value {
+                            x.remove(value.as_ref());
                         }
                     }
-                    _ => unreachable!(),
-                };
+                }
+                _ => unreachable!(),
+            };
 
-                should_remove = x.is_empty();
-                Ok(rand)
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(Value::Null),
-    )?;
+            should_remove = x.is_empty();
+            Ok(rand)
+        }
+        None => Ok(Value::Null),
+        _ => Err(Error::WrongType),
+    })?;
 
     if should_remove {
         let _ = conn.db().del(&[key]);
@@ -429,72 +396,67 @@ pub async fn spop(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value,
 /// same element multiple times. In this case, the number of returned elements is the absolute
 /// value of the specified count.
 pub async fn srandmember(conn: &Connection, args: VecDeque<Bytes>) -> Result<Value, Error> {
-    conn.db().get_map_or(
-        &args[0],
-        |v| match v {
-            Value::Set(x) => {
-                let mut rng = rand::thread_rng();
-                let set = x.read();
-
-                let mut items = set
-                    .iter()
-                    .map(|x| (x, rng.gen()))
-                    .collect::<Vec<(&Bytes, i128)>>();
-
-                items.sort_by(|a, b| a.1.cmp(&b.1));
-
-                if args.len() == 1 {
-                    // Two arguments provided, return the first element or null if the array is null
-                    if items.is_empty() {
-                        Ok(Value::Null)
-                    } else {
-                        let item = items[0].0.clone();
-                        Ok(Value::new(&item))
-                    }
+    conn.db().get_map(&args[0], |v| match v {
+        Some(Value::Set(x)) => {
+            let mut rng = rand::thread_rng();
+            let set = x.read();
+
+            let mut items = set
+                .iter()
+                .map(|x| (x, rng.gen()))
+                .collect::<Vec<(&Bytes, i128)>>();
+
+            items.sort_by(|a, b| a.1.cmp(&b.1));
+
+            if args.len() == 1 {
+                // Two arguments provided, return the first element or null if the array is null
+                if items.is_empty() {
+                    Ok(Value::Null)
                 } else {
-                    if items.is_empty() {
-                        return Ok(Value::Array(vec![]));
-                    }
-                    let len = bytes_to_number::<i64>(&args[1])?;
-
-                    if len > 0 {
-                        // required length is positive, return *up* to the requested number and no duplicated allowed
-                        let len: usize = min(items.len(), len as usize);
-                        Ok(items[0..len]
-                            .iter()
-                            .map(|item| Value::new(&item.0))
-                            .collect::<Vec<Value>>()
-                            .into())
-                    } else {
-                        // duplicated results are allowed and the requested number must be returned
-                        let len = (len * -1) as usize;
-                        let total = items.len() - 1;
-                        let mut i = 0;
-                        let items = (0..len)
-                            .map(|_| {
-                                let r = (items[i].0, rng.gen());
-                                i = if i >= total { 0 } else { i + 1 };
-                                r
-                            })
-                            .collect::<Vec<(&Bytes, i128)>>();
-                        Ok(items
-                            .iter()
-                            .map(|item| Value::new(&item.0))
-                            .collect::<Vec<Value>>()
-                            .into())
-                    }
+                    let item = items[0].0.clone();
+                    Ok(Value::new(&item))
                 }
-            }
-            _ => Err(Error::WrongType),
-        },
-        || {
-            Ok(if args.len() == 1 {
-                Value::Null
             } else {
-                Value::Array(vec![])
-            })
-        },
-    )
+                if items.is_empty() {
+                    return Ok(Value::Array(vec![]));
+                }
+                let len = bytes_to_number::<i64>(&args[1])?;
+
+                if len > 0 {
+                    // required length is positive, return *up* to the requested number and no duplicated allowed
+                    let len: usize = min(items.len(), len as usize);
+                    Ok(items[0..len]
+                        .iter()
+                        .map(|item| Value::new(&item.0))
+                        .collect::<Vec<Value>>()
+                        .into())
+                } else {
+                    // duplicated results are allowed and the requested number must be returned
+                    let len = (len * -1) as usize;
+                    let total = items.len() - 1;
+                    let mut i = 0;
+                    let items = (0..len)
+                        .map(|_| {
+                            let r = (items[i].0, rng.gen());
+                            i = if i >= total { 0 } else { i + 1 };
+                            r
+                        })
+                        .collect::<Vec<(&Bytes, i128)>>();
+                    Ok(items
+                        .iter()
+                        .map(|item| Value::new(&item.0))
+                        .collect::<Vec<Value>>()
+                        .into())
+                }
+            }
+        }
+        None => Ok(if args.len() == 1 {
+            Value::Null
+        } else {
+            Value::Array(vec![])
+        }),
+        _ => Err(Error::WrongType),
+    })
 }
 
 /// Remove the specified members from the set stored at key. Specified members that are not a
@@ -502,25 +464,22 @@ pub async fn srandmember(conn: &Connection, args: VecDeque<Bytes>) -> Result<Val
 /// command returns 0.
 pub async fn srem(conn: &Connection, mut args: VecDeque<Bytes>) -> Result<Value, Error> {
     let key = args.pop_front().ok_or(Error::Syntax)?;
-    let result = conn.db().get_map_or(
-        &key,
-        |v| match v {
-            Value::Set(x) => {
-                let mut set = x.write();
-                let mut i = 0;
-
-                args.into_iter().for_each(|value| {
-                    if set.remove(&value) {
-                        i += 1;
-                    }
-                });
+    let result = conn.db().get_map(&key, |v| match v {
+        Some(Value::Set(x)) => {
+            let mut set = x.write();
+            let mut i = 0;
+
+            args.into_iter().for_each(|value| {
+                if set.remove(&value) {
+                    i += 1;
+                }
+            });
 
-                Ok(i.into())
-            }
-            _ => Err(Error::WrongType),
-        },
-        || Ok(0.into()),
-    )?;
+            Ok(i.into())
+        }
+        None => Ok(0.into()),
+        _ => Err(Error::WrongType),
+    })?;
 
     conn.db().bump_version(&key);
 

+ 4 - 6
src/db/mod.rs

@@ -712,21 +712,19 @@ impl Db {
     ///
     /// This function is useful to read non-scalar values from the database. Non-scalar values are
     /// forbidden to clone, attempting cloning will end-up in an error (Error::WrongType)
-    pub fn get_map_or<F1, F2>(&self, key: &Bytes, found: F1, not_found: F2) -> Result<Value, Error>
+    pub fn get_map<F1>(&self, key: &Bytes, found: F1) -> Result<Value, Error>
     where
-        F1: FnOnce(&Value) -> Result<Value, Error>,
-        F2: FnOnce() -> Result<Value, Error>,
+        F1: FnOnce(Option<&Value>) -> Result<Value, Error>,
     {
         let slot = self.slots[self.get_slot(key)].read();
         let entry = slot.get(key).filter(|x| x.is_valid()).map(|e| e.get());
 
         if let Some(entry) = entry {
-            found(entry)
+            found(Some(entry))
         } else {
             // drop lock
             drop(slot);
-
-            not_found()
+            found(None)
         }
     }