Giter Site home page Giter Site logo

aerospike-client-rust's People

Contributors

bmuddha avatar dnaka91 avatar florianeichin avatar jhecking avatar jlr52 avatar jonas32 avatar khaf avatar nassor avatar soro avatar vthriller avatar x87-va avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aerospike-client-rust's Issues

CDT lists/maps size operation fails with ParameterError

Running the unit tests results in two failures:

---- src::cdt_map::map_operations stdout ----
thread 'src::cdt_map::map_operations' panicked at 'called `Result::unwrap()` on an `Err` value: Error(ServerError(ParameterError), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

---- src::cdt_list::cdt_list stdout ----
thread 'src::cdt_list::cdt_list' panicked at 'called `Result::unwrap()` on an `Err` value: Error(ServerError(ParameterError), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })', libcore/result.rs:945:5

Server logs show the following warning:

Nov 18 2019 01:54:03 GMT: WARNING (rw): (write.c:1079) {test} write_master: has read op but read flag not set <Digest>:0xbd7a1b71a449d964b52298514b042b9416040ae5

Tests don't pass on fresh Master pull

I'm running macOS 10.14.6.

Reproduction Steps:

git clone https://github.com/aerospike/aerospike-client-rust.git \
 && docker run -v ${HOME}/.aerospike/data:/opt/aerospike/data -e "NAMESPACE=test" --rm -d -p 3000:3000 --name aerospike aerospike/aerospike-server \
 && cd aerospike-client-rust \
 && cargo test

Results:

running 20 tests
test bin::tests::into_bins ... ok
test net::parser::tests::read_addr_part ... ok
test net::host::tests::to_hosts ... ok
test key::tests::unsupported_float_key ... ok
test key::tests::unsupported_u64_key ... ok
test net::parser::tests::read_addr_tuple ... ok
test query::filter::tests::geo_filter_macros ... ok
test net::parser::tests::read_hosts ... ok
test record::tests::ttl_expiration_future ... ok
test record::tests::ttl_expiration_past ... ok
test record::tests::ttl_never_expires ... ok
test result_code::tests::from_result_code ... ok
test result_code::tests::from_unknown_result_code ... ok
test result_code::tests::into_string ... ok
test result_code::tests::unknown_into_string ... ok
test value::tests::as_geo ... ok
test value::tests::as_string ... ok
test key::tests::int_keys ... ok
test key::tests::string_keys ... ok
test key::tests::blob_keys ... ok

test result: ok. 20 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/client-0cb4beb2f607c922

running 5 tests
test cluster_name ... ok
test nodes ... ok
test get_node ... ok
test node_names ... ok
test close ... ok

test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/lib-33687cbfd16d35e7

running 27 tests
test src::batch::batch_get ... ok
test src::cdt_bitwise::cdt_bitwise ... ok
test src::cdt_list::cdt_list ... ok
test src::cdt_map::map_operations ... ok
test src::exp::expression_rec_ops ... FAILED
test src::exp::expression_commands ... ok
test src::hll::hll ... ok
test src::index::recreate_index ... ok
test src::kv::connect ... ok
test src::exp::expression_condition ... ok
test src::query::query_multi_consumer ... ok
test src::query::query_nobins ... ok
test src::exp::expression_data_types ... ok
test src::exp::expression_compare ... ok
test src::query::query_node ... ok
test src::query::query_single_consumer ... ok
test src::exp_hll::expression_hll ... ok
test src::task::index_task_test ... ok
test src::truncate::truncate ... ok
test src::scan::scan_multi_consumer ... ok
test src::udf::execute_udf ... ok
test src::scan::scan_single_consumer ... ok
test src::scan::scan_node ... ok
test src::task::register_task_test ... ok
test src::exp_bitwise::expression_bitwise ... ok
test src::exp_list::expression_list ... ok
test src::exp_map::expression_map ... ok

failures:

---- src::exp::expression_rec_ops stdout ----
thread 'src::exp::expression_rec_ops' panicked at 'assertion failed: `(left == right)`
  left: `0`,
 right: `100`: DEVICE SIZE Test Failed', tests/src/exp.rs:244:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Running cargo clippy:

warning: this could be a `const fn`
   --> src/value.rs:221:5
    |
221 | /     pub fn is_nil(&self) -> bool {
222 | |         match *self {
223 | |             Value::Nil => true,
224 | |             _ => false,
225 | |         }
226 | |     }
    | |_____^
    |
note: the lint level is defined here
   --> src/lib.rs:25:40
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |                                        ^^^^^^^^^^^^^^^
    = note: `#[warn(clippy::missing_const_for_fn)]` implied by `#[warn(clippy::nursery)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: match expression looks like `matches!` macro
   --> src/value.rs:222:9
    |
222 | /         match *self {
223 | |             Value::Nil => true,
224 | |             _ => false,
225 | |         }
    | |_________^ help: try this: `matches!(*self, Value::Nil)`
    |
note: the lint level is defined here
   --> src/lib.rs:25:9
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |         ^^^^^^^^^^^
    = note: `#[warn(clippy::match_like_matches_macro)]` implied by `#[warn(clippy::all)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro

warning: this could be a `const fn`
  --> src/bin.rs:70:5
   |
70 | /     pub fn is_all(&self) -> bool {
71 | |         match *self {
72 | |             Bins::All => true,
73 | |             _ => false,
74 | |         }
75 | |     }
   | |_____^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: match expression looks like `matches!` macro
  --> src/bin.rs:71:9
   |
71 | /         match *self {
72 | |             Bins::All => true,
73 | |             _ => false,
74 | |         }
   | |_________^ help: try this: `matches!(*self, Bins::All)`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro

warning: this could be a `const fn`
  --> src/bin.rs:78:5
   |
78 | /     pub fn is_none(&self) -> bool {
79 | |         match *self {
80 | |             Bins::None => true,
81 | |             _ => false,
82 | |         }
83 | |     }
   | |_____^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: match expression looks like `matches!` macro
  --> src/bin.rs:79:9
   |
79 | /         match *self {
80 | |             Bins::None => true,
81 | |             _ => false,
82 | |         }
   | |_________^ help: try this: `matches!(*self, Bins::None)`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro

warning: redundant closure found
   --> src/batch/batch_executor.rs:102:44
    |
102 |             map.entry(node).or_insert_with(|| vec![]).push(idx);
    |                                            ^^^^^^^^^ help: remove closure as shown: `$crate::vec::Vec::new`
    |
note: the lint level is defined here
   --> src/lib.rs:25:9
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |         ^^^^^^^^^^^
    = note: `#[warn(clippy::redundant_closure)]` implied by `#[warn(clippy::all)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure

warning: this could be a `const fn`
   --> src/cluster/node.rs:139:5
    |
139 | /     fn services_name(&self) -> &'static str {
140 | |         if self.client_policy.use_services_alternate {
141 | |             "services-alternate"
142 | |         } else {
143 | |             "services"
144 | |         }
145 | |     }
    | |_____^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: comparison to empty slice
   --> src/cluster/node.rs:196:36
    |
196 |             Some(friend_string) if friend_string == "" => return Ok(friends),
    |                                    ^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `friend_string.is_empty()`
    |
note: the lint level is defined here
   --> src/lib.rs:25:9
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |         ^^^^^^^^^^^
    = note: `#[warn(clippy::comparison_to_empty)]` implied by `#[warn(clippy::all)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)`
   --> src/cluster/node.rs:290:9
    |
290 | /         Message::info(&mut conn, commands).or_else(|e| {
291 | |             conn.invalidate();
292 | |             Err(e)
293 | |         })
    | |__________^
    |
note: the lint level is defined here
   --> src/lib.rs:25:9
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |         ^^^^^^^^^^^
    = note: `#[warn(clippy::bind_instead_of_map)]` implied by `#[warn(clippy::all)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
help: try this
    |
290 |         Message::info(&mut conn, commands).map_err(|e| {
291 |             conn.invalidate();
292 |             e
    |

warning: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)`
   --> src/cluster/mod.rs:249:22
    |
249 |           let tokens = PartitionTokenizer::new(&mut conn).or_else(|e| {
    |  ______________________^
250 | |             conn.invalidate();
251 | |             Err(e)
252 | |         })?;
    | |__________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
help: try this
    |
249 |         let tokens = PartitionTokenizer::new(&mut conn).map_err(|e| {
250 |             conn.invalidate();
251 |             e
    |

warning: wildcard match will miss any future added variants
   --> src/cluster/mod.rs:324:17
    |
324 |                 _ => {
    |                 ^ help: try this: `std::prelude::v1::Err(..)`
    |
note: the lint level is defined here
   --> src/lib.rs:25:22
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |                      ^^^^^^^^^^^^^^^^
    = note: `#[warn(clippy::match_wildcard_for_single_variants)]` implied by `#[warn(clippy::pedantic)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants

warning: wildcard match will miss any future added variants
  --> src/commands/batch_read_command.rs:93:17
   |
93 |                 _ => continue, // Node is currently inactive. Retry.
   |                 ^ help: try this: `std::prelude::v1::Err(..)`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants

warning: match expression looks like `matches!` macro
   --> src/commands/buffer.rs:511:27
    |
511 |               let each_op = match operation.data {
    |  ___________________________^
512 | |                 OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_) => true,
513 | |                 _ => false,
514 | |             };
    | |_____________^ help: try this: `matches!(operation.data, OperationData::CdtMapOp(_) | OperationData::CdtBitOp(_))`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro

warning: comparison to empty slice
   --> src/commands/buffer.rs:606:12
    |
606 |         if namespace != "" {
    |            ^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!namespace.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:611:12
    |
611 |         if set_name != "" {
    |            ^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!set_name.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:653:12
    |
653 |         if namespace != "" {
    |            ^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!namespace.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:657:12
    |
657 |         if set_name != "" {
    |            ^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!set_name.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:712:12
    |
712 |         if statement.namespace != "" {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!statement.namespace.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:717:12
    |
717 |         if statement.set_name != "" {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!statement.set_name.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:723:16
    |
723 |             if index_name != "" {
    |                ^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!index_name.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:810:12
    |
810 |         if statement.namespace != "" {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!statement.namespace.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:820:12
    |
820 |         if statement.set_name != "" {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!statement.set_name.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:905:12
    |
905 |         if key.namespace != "" {
    |            ^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!key.namespace.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
   --> src/commands/buffer.rs:910:12
    |
910 |         if key.set_name != "" {
    |            ^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!key.set_name.is_empty()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
    --> src/commands/buffer.rs:1073:12
     |
1073 |         if key.namespace != "" {
     |            ^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!key.namespace.is_empty()`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: comparison to empty slice
    --> src/commands/buffer.rs:1077:12
     |
1077 |         if key.set_name != "" {
     |            ^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!key.set_name.is_empty()`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1196:9
     |
1196 | /         if let Some(pos) = pos {
1197 | |             Ok(self.data_buffer[pos])
1198 | |         } else {
1199 | |             let res = self.data_buffer[self.data_offset];
1200 | |             self.data_offset += 1;
1201 | |             Ok(res)
1202 | |         }
     | |_________^
     |
note: the lint level is defined here
    --> src/lib.rs:25:22
     |
25   | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
     |                      ^^^^^^^^^^^^^^^^
     = note: `#[warn(clippy::option_if_let_else)]` implied by `#[warn(clippy::pedantic)]`
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1196 |         pos.map_or_else(|| {
1197 |             let res = self.data_buffer[self.data_offset];
1198 |             self.data_offset += 1;
1199 |             Ok(res)
1200 |         }, |pos| Ok(self.data_buffer[pos]))
     |

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1206:9
     |
1206 | /         if let Some(pos) = pos {
1207 | |             Ok(self.data_buffer[pos] as i8)
1208 | |         } else {
1209 | |             let res = self.data_buffer[self.data_offset] as i8;
1210 | |             self.data_offset += 1;
1211 | |             Ok(res)
1212 | |         }
     | |_________^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1206 |         pos.map_or_else(|| {
1207 |             let res = self.data_buffer[self.data_offset] as i8;
1208 |             self.data_offset += 1;
1209 |             Ok(res)
1210 |         }, |pos| Ok(self.data_buffer[pos] as i8))
     |

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1217:9
     |
1217 | /         if let Some(pos) = pos {
1218 | |             Ok(NetworkEndian::read_u16(&self.data_buffer[pos..pos + len]))
1219 | |         } else {
1220 | |             let res = NetworkEndian::read_u16(
...    |
1224 | |             Ok(res)
1225 | |         }
     | |_________^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1217 |         pos.map_or_else(|| {
1218 |             let res = NetworkEndian::read_u16(
1219 |                 &self.data_buffer[self.data_offset..self.data_offset + len],
1220 |             );
1221 |             self.data_offset += len;
1222 |             Ok(res)
   ...

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1235:9
     |
1235 | /         if let Some(pos) = pos {
1236 | |             Ok(NetworkEndian::read_u32(&self.data_buffer[pos..pos + len]))
1237 | |         } else {
1238 | |             let res = NetworkEndian::read_u32(
...    |
1242 | |             Ok(res)
1243 | |         }
     | |_________^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1235 |         pos.map_or_else(|| {
1236 |             let res = NetworkEndian::read_u32(
1237 |                 &self.data_buffer[self.data_offset..self.data_offset + len],
1238 |             );
1239 |             self.data_offset += len;
1240 |             Ok(res)
   ...

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1253:9
     |
1253 | /         if let Some(pos) = pos {
1254 | |             Ok(NetworkEndian::read_u64(&self.data_buffer[pos..pos + len]))
1255 | |         } else {
1256 | |             let res = NetworkEndian::read_u64(
...    |
1260 | |             Ok(res)
1261 | |         }
     | |_________^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1253 |         pos.map_or_else(|| {
1254 |             let res = NetworkEndian::read_u64(
1255 |                 &self.data_buffer[self.data_offset..self.data_offset + len],
1256 |             );
1257 |             self.data_offset += len;
1258 |             Ok(res)
   ...

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1277:9
     |
1277 | /         if let Some(pos) = pos {
1278 | |             Ok(NetworkEndian::read_f32(&self.data_buffer[pos..pos + len]))
1279 | |         } else {
1280 | |             let res = NetworkEndian::read_f32(
...    |
1284 | |             Ok(res)
1285 | |         }
     | |_________^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1277 |         pos.map_or_else(|| {
1278 |             let res = NetworkEndian::read_f32(
1279 |                 &self.data_buffer[self.data_offset..self.data_offset + len],
1280 |             );
1281 |             self.data_offset += len;
1282 |             Ok(res)
   ...

warning: use Option::map_or_else instead of an if let/else
    --> src/commands/buffer.rs:1290:9
     |
1290 | /         if let Some(pos) = pos {
1291 | |             Ok(NetworkEndian::read_f64(&self.data_buffer[pos..pos + len]))
1292 | |         } else {
1293 | |             let res = NetworkEndian::read_f64(
...    |
1297 | |             Ok(res)
1298 | |         }
     | |_________^
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
     |
1290 |         pos.map_or_else(|| {
1291 |             let res = NetworkEndian::read_f64(
1292 |                 &self.data_buffer[self.data_offset..self.data_offset + len],
1293 |             );
1294 |             self.data_offset += len;
1295 |             Ok(res)
   ...

warning: `self.write_u8(0)?` is being shadowed
    --> src/commands/buffer.rs:1407:9
     |
1407 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
     |
note: the lint level is defined here
    --> src/lib.rs:25:22
     |
25   | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
     |                      ^^^^^^^^^^^^^^^^
     = note: `#[warn(clippy::shadow_unrelated)]` implied by `#[warn(clippy::pedantic)]`
note: initialization happens here
    --> src/commands/buffer.rs:1407:9
     |
1407 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
note: previous binding is here
    --> src/commands/buffer.rs:1406:33
     |
1406 |     pub fn write_geo(&mut self, val: &str) -> Result<usize> {
     |                                 ^^^
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `self.write_u8(0)?` is being shadowed
    --> src/commands/buffer.rs:1408:9
     |
1408 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
     |
note: initialization happens here
    --> src/commands/buffer.rs:1408:9
     |
1408 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
note: previous binding is here
    --> src/commands/buffer.rs:1407:9
     |
1407 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `self.write_u8(0)?` is being shadowed
    --> src/commands/buffer.rs:1409:9
     |
1409 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
     |
note: initialization happens here
    --> src/commands/buffer.rs:1409:9
     |
1409 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
note: previous binding is here
    --> src/commands/buffer.rs:1408:9
     |
1408 |         self.write_u8(0)?;
     |         ^^^^^^^^^^^^^^^^^
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: wildcard match will miss any future added variants
   --> src/commands/single_command.rs:103:17
    |
103 |                 _ => continue, // Node is currently inactive. Retry.
    |                 ^ help: try this: `std::prelude::v1::Err(..)`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants

warning: this could be a `const fn`
  --> src/commands/mod.rs:66:1
   |
66 | / pub fn keep_connection(err: &Error) -> bool {
67 | |     match *err {
68 | |         Error(ErrorKind::ServerError(result_code), _) => match result_code {
69 | |             ResultCode::KeyNotFoundError => true,
...  |
73 | |     }
74 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: match expression looks like `matches!` macro
  --> src/commands/mod.rs:68:58
   |
68 |           Error(ErrorKind::ServerError(result_code), _) => match result_code {
   |  __________________________________________________________^
69 | |             ResultCode::KeyNotFoundError => true,
70 | |             _ => false,
71 | |         },
   | |_________^ help: try this: `matches!(result_code, ResultCode::KeyNotFoundError)`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro

warning: this could be a `const fn`
   --> src/expressions/lists.rs:690:1
    |
690 | / fn get_value_type(return_type: ListReturnType) -> ExpType {
691 | |     if (return_type as u8 & !(ListReturnType::Inverted as u8)) == ListReturnType::Values as u8 {
692 | |         ExpType::LIST
693 | |     } else {
694 | |         ExpType::INT
695 | |     }
696 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
   --> src/expressions/maps.rs:833:1
    |
833 | / fn get_value_type(return_type: MapReturnType) -> ExpType {
834 | |     let t = return_type as u8 & !(MapReturnType::Inverted as u8);
835 | |     if t == MapReturnType::Key as u8 || t == MapReturnType::Value as u8 {
836 | |         ExpType::LIST
...   |
841 | |     }
842 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: use Option::map_or instead of an if let/else
   --> src/expressions/mod.rs:129:9
    |
129 | /         if let Some(bin) = bin {
130 | |             FilterExpression {
131 | |                 cmd,
132 | |                 val,
...   |
148 | |             }
149 | |         }
    | |_________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else
help: try
    |
129 |         bin.map_or(FilterExpression {
130 |                 cmd,
131 |                 val,
132 |                 bin: None,
133 |                 flags,
134 |                 module,
  ...

warning: parameter of type `HashMap` should be generalized over different hashers
   --> src/expressions/mod.rs:666:21
    |
666 | pub fn map_val(val: HashMap<Value, Value>) -> FilterExpression {
    |                     ^^^^^^^^^^^^^^^^^^^^^
    |
note: the lint level is defined here
   --> src/lib.rs:25:22
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |                      ^^^^^^^^^^^^^^^^
    = note: `#[warn(clippy::implicit_hasher)]` implied by `#[warn(clippy::pedantic)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
help: consider adding a type parameter
    |
666 | pub fn map_val<S: ::std::hash::BuildHasher>(val: HashMap<Value, Value, S>) -> FilterExpression {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^      ^^^^^^^^^^^^^^^^^^^^^^^^

warning: this could be a `const fn`
   --> src/expressions/mod.rs:703:1
    |
703 | / pub fn and(exps: Vec<FilterExpression>) -> FilterExpression {
704 | |     FilterExpression {
705 | |         cmd: Some(ExpOp::And),
706 | |         val: None,
...   |
712 | |     }
713 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
   --> src/expressions/mod.rs:721:1
    |
721 | / pub fn or(exps: Vec<FilterExpression>) -> FilterExpression {
722 | |     FilterExpression {
723 | |         cmd: Some(ExpOp::Or),
724 | |         val: None,
...   |
730 | |     }
731 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
   --> src/msgpack/decoder.rs:222:1
    |
222 | / fn is_ext(byte: u8) -> bool {
223 | |     match byte {
224 | |         0xc7 | 0xc8 | 0xc9 | 0xd4 | 0xd5 | 0xd6 | 0xd7 | 0xd8 => true,
225 | |         _ => false,
226 | |     }
227 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: match expression looks like `matches!` macro
   --> src/msgpack/decoder.rs:223:5
    |
223 | /     match byte {
224 | |         0xc7 | 0xc8 | 0xc9 | 0xd4 | 0xd5 | 0xd6 | 0xd7 | 0xd8 => true,
225 | |         _ => false,
226 | |     }
    | |_____^ help: try this: `matches!(byte, 0xc7 | 0xc8 | 0xc9 | 0xd4 | 0xd5 | 0xd6 | 0xd7 | 0xd8)`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro

warning: `buf.write_u8(marker)?` is being shadowed
   --> src/msgpack/encoder.rs:227:9
    |
227 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:227:9
    |
227 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:225:61
    |
225 | pub fn pack_byte(buf: &mut Option<&mut Buffer>, marker: u8, val: u8) -> Result<usize> {
    |                                                             ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(MSGPACK_MARKER_BOOL_TRUE)?` is being shadowed
   --> src/msgpack/encoder.rs:245:13
    |
245 |             buf.write_u8(MSGPACK_MARKER_BOOL_TRUE)?;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:245:13
    |
245 |             buf.write_u8(MSGPACK_MARKER_BOOL_TRUE)?;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:242:49
    |
242 | pub fn pack_bool(buf: &mut Option<&mut Buffer>, val: bool) -> Result<usize> {
    |                                                 ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(MSGPACK_MARKER_BOOL_FALSE)?` is being shadowed
   --> src/msgpack/encoder.rs:247:13
    |
247 |             buf.write_u8(MSGPACK_MARKER_BOOL_FALSE)?;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:247:13
    |
247 |             buf.write_u8(MSGPACK_MARKER_BOOL_FALSE)?;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:245:13
    |
245 |             buf.write_u8(MSGPACK_MARKER_BOOL_TRUE)?;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: manual `Range::contains` implementation
   --> src/msgpack/encoder.rs:257:16
    |
257 |         val if val >= 16 && val < 2 ^ 16 => pack_i16(buf, 0xde, length as i16),
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(16..2 ^ 16).contains(&val)`
    |
note: the lint level is defined here
   --> src/lib.rs:25:9
    |
25  | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
    |         ^^^^^^^^^^^
    = note: `#[warn(clippy::manual_range_contains)]` implied by `#[warn(clippy::all)]`
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains

warning: manual `Range::contains` implementation
   --> src/msgpack/encoder.rs:266:16
    |
266 |         val if val >= 16 && val < 2 ^ 16 => pack_i16(buf, 0xdc, length as i16),
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(16..2 ^ 16).contains(&val)`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains

warning: `buf.write_u8(ParticleType::BLOB as u8)?` is being shadowed
   --> src/msgpack/encoder.rs:286:9
    |
286 |         buf.write_u8(ParticleType::BLOB as u8)?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:286:9
    |
286 |         buf.write_u8(ParticleType::BLOB as u8)?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:281:49
    |
281 | pub fn pack_blob(buf: &mut Option<&mut Buffer>, val: &[u8]) -> Result<usize> {
    |                                                 ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(ParticleType::STRING as u8)?` is being shadowed
   --> src/msgpack/encoder.rs:299:9
    |
299 |         buf.write_u8(ParticleType::STRING as u8)?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:299:9
    |
299 |         buf.write_u8(ParticleType::STRING as u8)?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:294:51
    |
294 | pub fn pack_string(buf: &mut Option<&mut Buffer>, val: &str) -> Result<usize> {
    |                                                   ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(ParticleType::GEOJSON as u8)?` is being shadowed
   --> src/msgpack/encoder.rs:324:9
    |
324 |         buf.write_u8(ParticleType::GEOJSON as u8)?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:324:9
    |
324 |         buf.write_u8(ParticleType::GEOJSON as u8)?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:319:49
    |
319 | fn pack_geo_json(buf: &mut Option<&mut Buffer>, val: &str) -> Result<usize> {
    |                                                 ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: manual `Range::contains` implementation
   --> src/msgpack/encoder.rs:334:16
    |
334 |         val if val >= 0 && val < 2 ^ 7 => pack_half_byte(buf, val as u8),
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..2 ^ 7).contains(&val)`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains

warning: `buf.write_u8(marker)?` is being shadowed
   --> src/msgpack/encoder.rs:367:9
    |
367 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:367:9
    |
367 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:365:60
    |
365 | pub fn pack_i16(buf: &mut Option<&mut Buffer>, marker: u8, val: i16) -> Result<usize> {
    |                                                            ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(marker)?` is being shadowed
   --> src/msgpack/encoder.rs:376:9
    |
376 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:376:9
    |
376 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:374:60
    |
374 | pub fn pack_i32(buf: &mut Option<&mut Buffer>, marker: u8, val: i32) -> Result<usize> {
    |                                                            ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(marker)?` is being shadowed
   --> src/msgpack/encoder.rs:385:9
    |
385 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:385:9
    |
385 |         buf.write_u8(marker)?;
    |         ^^^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:383:60
    |
383 | pub fn pack_i64(buf: &mut Option<&mut Buffer>, marker: u8, val: i64) -> Result<usize> {
    |                                                            ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(0xcf)?` is being shadowed
   --> src/msgpack/encoder.rs:398:9
    |
398 |         buf.write_u8(0xcf)?;
    |         ^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:398:9
    |
398 |         buf.write_u8(0xcf)?;
    |         ^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:392:48
    |
392 | pub fn pack_u64(buf: &mut Option<&mut Buffer>, val: u64) -> Result<usize> {
    |                                                ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(0xca)?` is being shadowed
   --> src/msgpack/encoder.rs:407:9
    |
407 |         buf.write_u8(0xca)?;
    |         ^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:407:9
    |
407 |         buf.write_u8(0xca)?;
    |         ^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:405:48
    |
405 | pub fn pack_f32(buf: &mut Option<&mut Buffer>, val: f32) -> Result<usize> {
    |                                                ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: `buf.write_u8(0xcb)?` is being shadowed
   --> src/msgpack/encoder.rs:416:9
    |
416 |         buf.write_u8(0xcb)?;
    |         ^^^^^^^^^^^^^^^^^^^
    |
note: initialization happens here
   --> src/msgpack/encoder.rs:416:9
    |
416 |         buf.write_u8(0xcb)?;
    |         ^^^^^^^^^^^^^^^^^^^
note: previous binding is here
   --> src/msgpack/encoder.rs:414:48
    |
414 | pub fn pack_f64(buf: &mut Option<&mut Buffer>, val: f64) -> Result<usize> {
    |                                                ^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated

warning: use Option::map_or instead of an if let/else
   --> src/net/connection.rs:100:9
    |
100 | /         if let Some(idle_dl) = self.idle_deadline {
101 | |             Instant::now() >= idle_dl
102 | |         } else {
103 | |             false
104 | |         }
    | |_________^ help: try: `self.idle_deadline.map_or(false, |idle_dl| Instant::now() >= idle_dl)`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else

warning: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)`
  --> src/net/connection_pool.rs:86:9
   |
86 | /         connection.set_timeout(timeout).or_else(|err| {
87 | |             internals.num_conns -= 1;
88 | |             Err(err)
89 | |         })?;
   | |__________^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
help: try this
   |
86 |         connection.set_timeout(timeout).map_err(|err| {
87 |             internals.num_conns -= 1;
88 |             err
   |

warning: this could be a `const fn`
   --> src/operations/lists.rs:177:1
    |
177 | / pub fn list_order_flag(order: ListOrderType, pad: bool) -> u8 {
178 | |     if let ListOrderType::Ordered = order {
179 | |         return 0xc0;
180 | |     }
...   |
184 | |     0x40
185 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
   --> src/operations/maps.rs:195:1
    |
195 | / pub(crate) fn map_write_op(policy: &MapPolicy, multi: bool) -> CdtMapOpType {
196 | |     match policy.write_mode {
197 | |         MapWriteMode::Update => {
198 | |             if multi {
...   |
218 | |     }
219 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
   --> src/operations/maps.rs:221:1
    |
221 | / fn map_order_arg(policy: &MapPolicy) -> Option<CdtArgument> {
222 | |     match policy.write_mode {
223 | |         MapWriteMode::UpdateOnly => None,
224 | |         _ => Some(CdtArgument::Byte(policy.order as u8)),
225 | |     }
226 | | }
    | |_^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
  --> src/operations/scalar.rs:43:1
   |
43 | / pub fn get_bin(bin_name: &str) -> Operation {
44 | |     Operation {
45 | |         op: OperationType::Read,
46 | |         ctx: DEFAULT_CTX,
...  |
49 | |     }
50 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
  --> src/operations/scalar.rs:53:1
   |
53 | / pub fn put<'a>(bin: &'a Bin) -> Operation<'a> {
54 | |     Operation {
55 | |         op: OperationType::Write,
56 | |         ctx: DEFAULT_CTX,
...  |
59 | |     }
60 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
  --> src/operations/scalar.rs:63:1
   |
63 | / pub fn append<'a>(bin: &'a Bin) -> Operation<'a> {
64 | |     Operation {
65 | |         op: OperationType::Append,
66 | |         ctx: DEFAULT_CTX,
...  |
69 | |     }
70 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
  --> src/operations/scalar.rs:73:1
   |
73 | / pub fn prepend<'a>(bin: &'a Bin) -> Operation<'a> {
74 | |     Operation {
75 | |         op: OperationType::Prepend,
76 | |         ctx: DEFAULT_CTX,
...  |
79 | |     }
80 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: this could be a `const fn`
  --> src/operations/scalar.rs:83:1
   |
83 | / pub fn add<'a>(bin: &'a Bin) -> Operation<'a> {
84 | |     Operation {
85 | |         op: OperationType::Incr,
86 | |         ctx: DEFAULT_CTX,
...  |
89 | |     }
90 | | }
   | |_^
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: field assignment outside of initializer for an instance created with Default::default()
  --> src/policy/write_policy.rs:75:9
   |
75 |         wp.generation = gen;
   |         ^^^^^^^^^^^^^^^^^^^^
   |
note: the lint level is defined here
  --> src/lib.rs:25:9
   |
25 | #![warn(clippy::all, clippy::pedantic, clippy::nursery)]
   |         ^^^^^^^^^^^
   = note: `#[warn(clippy::field_reassign_with_default)]` implied by `#[warn(clippy::all)]`
note: consider initializing the variable with `policy::write_policy::WritePolicy { generation: gen, expiration: exp, ..Default::default() }` and removing relevant reassignments
  --> src/policy/write_policy.rs:74:9
   |
74 |         let mut wp = WritePolicy::default();
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default

warning: wildcard match will miss any future added variants
  --> src/record.rs:77:21
   |
77 |                     _ => Some(Duration::new(1u64, 0)),
   |                     ^ help: try this: `std::prelude::v1::Err(..)`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants

warning: this could be a `const fn`
   --> src/result_code.rs:216:5
    |
216 | /     pub fn from_u8(n: u8) -> ResultCode {
217 | |         match n {
218 | |             0 => ResultCode::Ok,
219 | |             1 => ResultCode::ServerError,
...   |
281 | |         }
282 | |     }
    | |_____^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn

warning: 76 warnings emitted

cdt_context::ctx_map_key_create not working as expected

here's a repro following the example from the docs here

#[test]
fn test() {
    use aerospike::{self, operations::{maps, cdt_context}};

    let ac = aerospike::Client::new(&aerospike::ClientPolicy::default(), &"0.0.0.0:3000".to_string()).unwrap();
    let key = as_key!("test", "test", "test");
    ac.put(
        &aerospike::WritePolicy::default(),
        &key,
        &[as_bin!("m", as_map!("name" => "chuck norris"))]
    );
    ac.operate(
        &aerospike::WritePolicy::default(),
        &key,
        &[
            maps::increment_value(
                &maps::MapPolicy::default(),
                "m",
                &as_val!("jokes"),
                &as_val!(317)
            ).set_context(&[
                cdt_context::ctx_map_key_create(as_val!("stats"), maps::MapOrder::KeyOrdered),
                cdt_context::ctx_map_key_create(as_val!("accolades"), maps::MapOrder::KeyOrdered),
            ])
        ]
    );
    assert_eq!(
        "{}",
        ac.get(
            &aerospike::ReadPolicy::default(),
            &key,
            aerospike::Bins::Some(vec!["m".to_string()])
        ).unwrap().bins.get("m").unwrap().to_string()
    )
}

i did the assert_eq! as a convenience to see what's inside bin "m" and i get

thread 'tests::test' panicked at 'assertion failed: `(left == right)`
  left: `"{}"`,
 right: `"{String(\"name\"): String(\"chuck norris\")}"`' ...

when i add a .unwrap() to the ac.operate(...) above it turns out it's actually erroring with thread 'tests::test' panicked at 'called `Result::unwrap()` on an `Err` value: Error(ServerError(Unknown(26)), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })'

from here, 26 means AS_ERR_OP_NOT_APPLICABLE Operation isn't able to be applied to the current contents of the bin. which seems weird to me because this works with the python client. am i missing something?

Host Alias Validation

Hello,

I just ran into an issue with Node Name Validation.
My services use consul as service discovery for the Aerospike Hosts.
This results in using aerospike.service.consul:3000 as the hosts parameter.
I first did that with the nodejs client and everything worked well.
The Rust client aborts with the error

[2021-01-07T05:54:06Z ERROR aerospike::cluster] Failed to validate seed host: aerospike.service.consul:3000
[2021-01-07T05:54:06Z ERROR aerospike::cluster] Error: Invalid cluster node: Missing node name

The function validate_alias in https://github.com/aerospike/aerospike-client-rust/blob/master/src/cluster/node_validator.rs#L61 throws that.
Is there any specific reason why the Rust client does that and the nodejs client not?
Is this error related to #10?

Expansion of serialization feature

I have structured data and I'd like a convenient mechansim for keeping that structure while pushing and pulling to and from aerospike. It looks like there may have been some initial work done here, but I'd like to push that bar further.

I'm proposing a trait, AerospikeRecord, that can be applied to an arbitrary Rust structure provided it meets certain criteria. The API would look something like this:

let client = build_aerospike_client(...);  // not included in API...
let record = SomeRecord {...};  // not included in API...

// Check if the record is in aerospike
if exists_record(&record, &client)? != true {

  // Create the record in aerospike
  set_record(&value, &client)?;

  // Retrieve the record from aerospike
  let aerospike_copy: SomeRecord = get_record(&record, &client)?;

  // Update the record in aerospike
  let updated_record = SomeRecord { ... };
  set_record(&updated_record, &client)?;
  
   // Delete the record from aerospike
   remove_record(&updated_record, &client)?;
 
}

The trait would have a variety of different methods to support the API above

pub trait AerospikeRecord: ... {
    /// Builds a stringified version of the record's key
    fn aerospike_record_key(&self) -> String;
   
    /// Builds aerospike bin name for this record
    ///   default: "payload"
    fn aerospike_bin_name(&self) -> String;

    /// Returns the timeout in seconds
    ///   A timeout of 0 indicates that the value will never be culled
    ///   Default:  whatever AEROSPIKE_TIMEOUT has (or 0)
    fn aerospike_timeout(&self) -> u32;

    /// Returns the namespace
    ///   Default:  whatever AEROSPIKE_NAMESPACE has (or "undefined")
    fn aerospike_namespace() -> String;

    /// Returns the set name
    ///   Default:  whatever AEROSPIKE_SET_NAME has (or "undefined")
    fn aerospike_set_name() -> String;

    /// Builds record data for aerospike entry
    ///   Default:  uses data from above
    fn aerospike_as_bins(&self) -> Vec<Bin>;

    /// Builds an aerospike key from record
    ///   Default:  uses data from above
    fn aerospike_key(&self) -> Key;

    /// Builds an aerospike key using parameters
    fn aerospike_build_key(&self, namespace: &str, set_name: &str) -> Key;

    /// Build dyn AerospikeRecord from aerospike::Record
    fn aerospike_from_record(&self, aerospike_record: Record) -> Self;
}

For a default behavior, the only thing that would need to be implemented for a given structure would be the aerospike_record_key. I think this makes sense because the key could be any kind of value within a given record. It might even need to be a composite key made of several values or a calculated set of values. But this allows the maintainer to decide how to build that key explicitly.

struct Foo {
    bar: String
    }
    
impl AerospikeRecord for Foo {
    fn aerospike_record_key(&self) -> String {
        self.bar.clone()
    }
    

Any of the other traits can easily be overwritten:

impl AerospikeRecord for Foo {
    ...
    
    fn aerospike_namespace() -> String {
        let default = String::from("real-time");
        let fall_through = std::env::var("AEROSPIKE_NAMESPACE").unwrap_or(default);
        std::env::var("FOO_AEROSPIKE_NAMESPACE").unwrap_or(fall_through)
    }
    
}

One caveat is that I'd need to make changes to the Bin lifetime. Right now, the way that it's implemented, it's impossible to do this:

    impl Into<Vec<Bin>> for TestRecord {
        fn into(self) -> Vec<Bin> {
            let json_string = serde_json::to_string(&self).unwrap_or_else(|_| String::default());
            vec![as_bin!("key", self.aerospike_record_key()), as_bin!("payload", json_string)]
        }
    }

Bin<'a> requires that the control of the lifetime be outside of its use. As a result, you'd need to carry that lifetime all the way up to the top of the call stack or set it to Bin<'static> and remain for the lifetime of the program. It's hard to know why the lifetimes are there in the first place as they only seem to make the API more complicated than is necessary. As a more general statement, I suspect some of the other lifetime requirements could also be removed but I don't have a use case for them right now. And, I wonder if this may be why the API doesn't get as much usage.

Looking for documentation to setup aerospike cluster

I am trying to cargo test but reached error after setting up vagrant up https://www.aerospike.com/docs/operations/install/vagrant/mac

I verified I can ssh into vagrant and insert element and that 127.0.0.1 3000 is able to be telnet

Error:

test node_names ... FAILED
test nodes ... FAILED
test get_node ... FAILED

failures:

---- node_names stdout ----
thread 'node_names' panicked at 'called `Result::unwrap()` on an `Err` value: Error(Connection("Failed to connect to host(s). The network connection(s) to cluster nodes may have timed out, or the cluster may be in a state of flux."), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })', tests/common/mod.rs:43:20
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- nodes stdout ----
thread 'nodes' panicked at 'Once instance has previously been poisoned', src/libstd/sync/once.rs:395:21

---- get_node stdout ----
thread 'get_node' panicked at 'Once instance has previously been poisoned', src/libstd/sync/once.rs:395:21


failures:
    get_node
    node_names
    nodes

test result: FAILED. 1 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test client'

Can someone point me a direction for minimum steps to run cargo test? Is there local cluster install instruction lying somewhere?

`expressions::cond` with `cdt_context::ctx_map_key` not working as expected

this is a repost from #104 (comment) since it's a more specific issue about the expressions branch PR #100

here's a repro with aerospike:ce-5.6.0.13

#[test]
fn test2() {
    use aerospike::{self, expressions, operations::{self, maps, cdt_context, lists}};

    let ac = aerospike::Client::new(
        &aerospike::ClientPolicy::default(), &"0.0.0.0:3000".to_string()
    ).unwrap();
    let key = aerospike::as_key!("test", "test", "test");
    ac.put(
        &aerospike::WritePolicy::default(),
        &key,
        &[aerospike::as_bin!("bin", aerospike::as_map!())]
    ).unwrap();
    ac.operate(
        &aerospike::WritePolicy::default(),
        &key,
        &[
            operations::exp::write_exp(
                "bin",
                &expressions::cond(
                    vec![
                        expressions::eq(
                            expressions::maps::get_by_key(
                                maps::MapReturnType::Count,
                                expressions::ExpType::INT,
                                expressions::string_val("key".to_string()),
                                expressions::map_bin("bin".to_string()),
                                &[]
                            ),
                            expressions::int_val(0)
                        ),
                        expressions::maps::put(
                            &maps::MapPolicy::default(),
                            expressions::string_val("key".to_string()),
                            expressions::list_val(vec![]),
                            expressions::map_bin("bin".to_string()),
                            &[]
                        ),
                        expressions::unknown(),
                    ]
                ),
                operations::exp::ExpWriteFlags::Default
            ),
            operations::lists::append(
                &operations::lists::ListPolicy::new(
                    operations::lists::ListOrderType::Ordered,
                    operations::lists::ListWriteFlags::Default
                ),
                "bin",
                &aerospike::as_val!("val")
            )
            .set_context(&[
                cdt_context::ctx_map_key(aerospike::as_val!("key")),
            ])
        ]
    ).unwrap();
    println!("{:?}", ac.get(&aerospike::ReadPolicy::default(), &key, aerospike::Bins::All).unwrap().bins);
    ac.operate(
        &aerospike::WritePolicy::default(),
        &key,
        &[
            operations::lists::remove_by_value(
                "bin", &aerospike::as_val!("val"), operations::lists::ListReturnType::None
            ).set_context(&[operations::cdt_context::ctx_map_key(aerospike::as_val!("key"))]),
        ]
    ).unwrap();
    println!("{:?}", ac.get(&aerospike::ReadPolicy::default(), &key, aerospike::Bins::All).unwrap().bins);
    ac.operate(
        &aerospike::WritePolicy::default(),
        &key,
        &[
            operations::exp::write_exp(
                "bin",
                &expressions::cond(vec![
                    expressions::eq(
                        expressions::lists::size(
                            expressions::map_bin("bin".to_string()),
                            &[operations::cdt_context::ctx_map_key(aerospike::as_val!("key"))]
                        ),
                        expressions::int_val(0)
                    ),
                    expressions::maps::remove_by_key(
                        expressions::string_val("key".to_string()),
                        expressions::map_bin("bin".to_string()),
                        &[]
                    ),
                    expressions::unknown()
                ]),
                operations::exp::ExpWriteFlags::EvalNoFail
            )
        ]
    ).unwrap();
    println!("{:?}", ac.get(&aerospike::ReadPolicy::default(), &key, aerospike::Bins::All).unwrap().bins);
}

output:

{"bin": HashMap({String("key"): List([String("val")])})}
{"bin": HashMap({String("key"): List([])})}
thread 'tests::store::test2' panicked at 'index out of bounds: the len is 125 but the index is 125', .../.cargo/git/checkouts/aerospike-client-rust-34a63ba2784a38de/231a73e/src/commands/buffer.rs:1330:9

the failing removal write expression works fine using the python client

import aerospike
from aerospike_helpers import cdt_ctx, expressions
from aerospike_helpers.operations import expression_operations

ac = aerospike.client({'hosts': [('localhost', 3000)]})
ac.connect()
key = ('test', 'test', 'test')
ac.put(key, {'bin': {'key': []}})
print(ac.get(key)[2])
ac.operate(
    key,
    [
        expression_operations.expression_write(
            'bin',
            expressions.Cond(
                expressions.Eq(expressions.ListSize([cdt_ctx.cdt_ctx_map_key('key')], expressions.MapBin('bin')), 0),
                expressions.MapRemoveByKey(None, 'key', 'bin'),
                expressions.Unknown()
            ).compile(),
            aerospike.EXP_WRITE_EVAL_NO_FAIL
        )
    ]
)
print(ac.get(key)[2])
{'bin': {'key': []}}
{'bin': {}}

so this isn't a problem with expressions::cond in general since the initial map put works fine and replacing

expressions::lists::size(
    expressions::map_bin("bin".to_string()),
    &[operations::cdt_context::ctx_map_key(aerospike::as_val!("key"))]
)

with expressions::int_val(0) (a trivial equality) works as expected

{"bin": HashMap({String("key"): List([String("val")])})}
{"bin": HashMap({String("key"): List([])})}
{"bin": HashMap({})}

and cdt_context::ctx_map_key works in different contexts (like the initial list append) so i'm lead to believe it's something about the combo of the two

Memory allocation fails for queries and scans when index is missing

This issue targets the as_eq filter.
When a as_eq filter is created with a string value, but the bin does not have a string type Secondary Index, it can fail memory allocation. It does not fail, if the filter is any other than as_eq or the bin has an Index. Also integer values are safe. Even with perfect conditions for this error, it seems not to fail everytime.
This is a hard to reproduce bug. For more about it, see this comment

// Update
I just found out, that also Numeric Queries on a String type Index bin can cause this to happen. Seems to be even more reproduceable.

Secondary index queries fail with parameter error on Aerospike Server 3.15.1.x

Query operations using a secondary index filter fail on Aerospike Server 3.15.1.x. The server returns a parameter error (status code 4). The same queries work against Aerospike Server 3.15.0.x and earlier.

The error is caused by an incorrectly sized AS_MSG_FIELD_TYPE_INDEX_RANGE field in the protocol message. Server versions 3.15.0.x and prior are processing the query despite the incorrect field size but server 3.15.1.x returns a parameter error instead. (Ref. aerospike/aerospike-server@69a81d9)

Support new peers info protocol

Use new peers list protocol introduced in AS v3.10 for more efficient node discovery.

Note: Requires Aerospike Server version 3.10 or later.

FloatValue enum uses u32 and u64 types instead of f32 and f64

Hi!

I'm trying to use FloatValue and it looks weird that it has u32 and u64 in the enum declaration instead of f32 and f64 correspondingly:

/// Container for floating point bin values stored in the Aerospike database.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum FloatValue {
/// Container for single precision float values.
F32(u32),
/// Container for double precision float values.
F64(u64),
}

So in order to use for example f32 value it is necessary to invoke mem::transmute_copy::<u32, f32>.

More to_type functions for Value

Value currently only has a to_string method.
As far as i understand thats more meant as some sort of "debug" function to just print whats inside the value.
I guess it might be a good idea to add more functions for other Data Types.
This functions could return a Result with the Value or an Error if the Type is not correct.
Currently the only way to do this is pattern matching. But if you need to match for example 10 bins, that becomes very ugly.
The type of the bins is probably known in most applications anyways. A strictly typed language like rust more or less forces you to know when you write it.
Im thinking about something like

pub fn to_map(&self) -> Result<HashMap<Value, Value>, TypeError> {
    match &self {
        Value::HashMap(map) => Ok(map)
        _ => Err(TypeError::new())
    }
}

pub fn to_list(&self) -> Result<Vec<Value>, TypeError> {
    match &self {
        Value::List(list) => Ok(list)
        _ => Err(TypeError::new())
    }
}

In the end it will not change how this fields are matched, but it reduces the boilerplate and nesting required to parse the record into a struct for example. In that case, you probably want to throw an Error if a bin type does not match the struct type.
Any thoughts on this?

Benchmark Suite

Create a benchmark suite to measure client performance in terms of throughput (transactions/second) as well as overhead (e.g. memory consumption). Goal is to be able to run the benchmark before/after major changes and before every release in order to detect performance degradations. Secondary goal is to be able to compare the client performance to that of other Aerospike clients, e.g. C, Java, Go, etc.

Ref.: Java client benchmark: https://github.com/aerospike/aerospike-client-java/tree/master/benchmarks

CDT Operations for List, Map and Bitwise

Hello,

currently the client only supports a limited set of operations for the custom data types and bitwise.
Is there a specific reasons only the few currently are supported or was there just no time to implement the others like list remove by value?
Im probably going to implement them, but i was curious why some are supported and some are not.
Also the list cdt seems to be not fully implemented (return types etc)

Normalizing and standardizing environments

Given the issues I had experienced with just the testing aspect, I am proposing here a Makefile shim which standardizes specific, common development operations including but not limited to:

  • builds
  • qa
  • style
  • testing

The primary goal here is to limit the amount of ramp-up time anyone new would need to have in order to start contributing and simultaneously reduce the differences across development environments so that debugging differences becomes simple.

Additionally, I think the shim could also be used in CI though I'm not sure I have actually access to the Travis output (it looked like notifications were sent to a team specifically at Aerospike). Despite being sanctioned under the Aerospike umbrella, since this particular project community driven, it makes me wonder if Github's Actions are a better option. The only downside I see here is that a Makefile approach is probably limited to a Posix environment. As a consequence, it probably wouldn't work for Appveyor/Windows.

Build fails using rustc 1.26.2

Rust 1.26.2 was the minimum supported Rust version (MSRV), but now cargo build fails to build using that version:

$ cargo build
 Downloading lazy_static v1.4.0
 Downloading log v0.4.8
 Downloading rand v0.5.6
 Downloading error-chain v0.12.1
 Downloading byteorder v1.3.2
 Downloading rand v0.3.23
 Downloading time v0.1.42
 Downloading libc v0.2.65
 Downloading rand v0.4.6
 Downloading gcc v0.3.55
 Downloading cfg-if v0.1.10
error: unable to get packages from source

Caused by:
  failed to parse manifest at `/Users/jhecking/.cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-0.1.10/Cargo.toml`

Caused by:
  feature `rename-dependency` is required

this Cargo does not support nightly features, but if you
switch to nightly channel you can add
`cargo-features = ["rename-dependency"]` to enable this feature

$ rustc --version
rustc 1.26.2 (594fb253c 2018-06-01)

Memory leaks

The Client::batch_get function seems to make a lot memory leaks. After thousands call the process memory grow up to 10 GB. The same requests with simply Client::get looks good. The target is x86_64-unknown-linux-gnu

Client Sharing

Hi team,

We are new to Rust and we are trying something to achieve here, like other languages, we want to create a client and share the same with many parts of our code.

We cannot find a simple way to share the client with other functions in the code, as we don't find a sample anywhere, it would be helpful if anyone gives a simple example.

Thanks

Small change to put API.

I'm working on an Elixir nif using Rust and rustler to access an Aerospike server from Elixir. I'm new to Rust and had an issue trying to implement a wrapper for put and needed some help. You can see the full discussion on the rust-lang forum here: https://users.rust-lang.org/t/newbie-ownership-issue/17079

My issue was trying to translate an Elixir Map into a &[&Bin] to pass to put. I needed to generate a [Bin] and then do:

let bins = bins.iter().collect::<Vec<_>>();

to generate the [&Bin]

They made the suggestion:

fn put<A: AsRef<Bin>>(..., bins: &[A]) ...
// or if a slice isn’t necessary and iterator works
fn put<I: IntoIterator<Item=A>, A: AsRef<Bin>>(iter: I) ...

Keeping in mind that I'm a Rust newbie, I thought I'd mention it here.

Client panic when reading ordered list/map from server

When fetching a CDT bin with an ordered list/map from the server, the client panics with an error message "Msgpack header skipped. You should not see this message".

Note: It's not currently possible to create an ordered list/map using only the Rust client. Therefore, this error can only occur when other clients (C, Java, etc.) are used to write ordered lists/maps to an Aerospike cluster and this data is subsequently read using the Rust client.

Support for other batch operations? (write/exists/...)

Hi!

I noticed that last year, you added support for batch-read. For the small program I'm writing, I would have loved to have batch-exists.
I was just wondering if this was an easy fix for you guys, or if I need to use another language than Rust for this project.

Thanks!
Alexis

Aerospike Expression API

The Client should support the new Expression API as main target for the 1.0 release. Draft PR will follow soon.

FilterExpression in Query policy

First of all, thanks for amazing work done with this library.

I came across an optional FilterExpression in QueryPolicy,

pub filter_expression: Option<FilterExpression>,

So I was wondering about few things:

  1. Does the filter expression affect all subsequent queries once set?
  2. Is it a good idea to use it in order to filter records from large dataset, do those filters apply before secondary index based filtering or after?
  3. Is it better to use UDF, if you need to perform filtering on multiple fields, as currently only one sindex based filter is allowed for query?

Thanks in advance, cheers!

List append_items unexpected list entries

There is a bug with the append_items list operation, resulting in adding 2 int values in front of the values.
I'm not sure what the first one (always 0) is, but the second one looks like the length of the value list that should be appended.

image

This is reproducible with every execution of the append_items operation.
Using a batch of single append operations works as workaround.
Server is 5.2.0.5 EE.

Client.is_connected() returns true even after client.close() is called

hi

am trying with a simple code to check the basics of Rust client, but the client.close() is not working.

#[macro_use]
extern crate aerospike;

use std::env;
use std::sync::Arc;
use std::time::Instant;
use std::thread;

use aerospike::Client;
use aerospike::{Bins, ClientPolicy, ReadPolicy, WritePolicy};
use aerospike::operations;

fn main() {
    let mut cpolicy = ClientPolicy::default();
    let user = env::var("AEROSPIKE_USER")
        .unwrap_or(String::from("admin"));
    let password = env::var("AEROSPIKE_PASSWORD")
        .unwrap_or(String::from("admin"));
    cpolicy.set_user_password(user, password).unwrap();
    let hosts = env::var("AEROSPIKE_HOSTS")
        .unwrap_or(String::from("127.0.0.1:3000"));
    let client = Client::new(&cpolicy, &hosts)
        .expect("Failed to connect to cluster");
    let client = Arc::new(client);

    let now = Instant::now();

    let rpolicy = ReadPolicy::default();
    let wpolicy = WritePolicy::default();
    let key = as_key!("tempspace", "test", "test");

    let bins = [
        as_bin!("int", 999),
        as_bin!("str", "Hello, World!"),
    ];
    client.put(&wpolicy, &key, &bins).unwrap();
    let rec = client.get(&rpolicy, &key, Bins::All);
    println!("Record: {}", rec.unwrap());

    client.touch(&wpolicy, &key).unwrap();
    let rec = client.get(&rpolicy, &key, Bins::All);
    println!("Record: {}", rec.unwrap());

    let rec = client.get(&rpolicy, &key, Bins::None);
    println!("Record Header: {}", rec.unwrap());

    let exists = client.exists(&wpolicy, &key).unwrap();
    println!("exists: {}", exists);

    let bin = as_bin!("int", "123");
    let ops = &vec![operations::put(&bin), operations::get()];
    let op_rec = client.operate(&wpolicy, &key, ops);
    println!("operate: {}", op_rec.unwrap());

    let existed = client.delete(&wpolicy, &key).unwrap();
    println!("existed (should be true): {}", existed);

    let existed = client.delete(&wpolicy, &key).unwrap();
    println!("existed (should be false): {}", existed);

    client.close().expect("unable to close the connection");

    if client.is_connected() {
        println!("After close call-connected to AS servers");
    } else {
        println!("After close call-not connected");
    }

    println!("total time: {:?}", now.elapsed());

}

output observed is:

    Finished dev [unoptimized + debuginfo] target(s) in 1.14s
     Running `target/debug/hello-world`
Record: key: None, bins: {int: 999, str: Hello, World!}, generation: 1, ttl: none
Record: key: None, bins: {str: Hello, World!, int: 999}, generation: 2, ttl: none
Record Header: key: None, bins: {}, generation: 2, ttl: none
exists: true
operate: key: None, bins: {int: 123, str: Hello, World!}, generation: 3, ttl: none
existed (should be true): true
existed (should be false): false
After close call-connected to AS servers
total time: 2.902384ms

Async Client

I would like to start a discussion about making this async.
@khaf already mentioned that this is planned anyways.
Before i will start to test around, i would like to get a two questions cleared.
If you have any additional ideas or feedback on that, please share it!

1: Project layout
There are three ways to look at that. First one would be splitting in two crates (one repo with sub crates), 1 sync and 1 async. Would result in maintaining 2 codebases (some parts could be shared) but would probably be cleaner and with less overhead. Way two would be building async native and implementing sync via manual blocking via feature flag. Third one would be dropping the sync support. Either way, this will be a breaking change because it will require users to use a runtime.

2: Tokio or async-std? Tokio is more mature and way more adopted in the ecosystem. Based on that, i would decide for Tokio.

Message pack appears to calculate integer boundaries incorrectly

There are several instances of this specific pattern, though I only find it in the one file.

See: https://github.com/aerospike/aerospike-client-rust/blob/master/src/msgpack/encoder.rs#L257

And a playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b2ebb5a04b0a8464862963e413f57155

In this line, it kind of looks like 2 ^ 16 implies 2 raised to the power of 16. However, Rust will calculate this as a bitwise operation and will result in 18. So I think in this specific instance, if a value is less than 16, then we'll pack a half byte. If it's between 16 and 18, then we'll pack an i16. Otherwise, we'll pack an i32. And my assumption here is that we're nearly always packing an i32. This isn't a "breaking" bug, but it definitely would lead to inefficiencies for some use-cases and it should be really easy to build a test-case.

I looked at git blame, and I think this has been a bug for several years.

HLL Datatype and Operations

The Client should feature HLL Operations and Expressions for a 1.0 Release.
The PR for HLL is already finished. It just misses the Tests (same as the FilterExpressions PR).
I will merge request this as soon as the other one is merged.
By the way, the Documentation of HyperLogLog seems broken: https://www.aerospike.com/docs/guides/hyperloglog
It only shows 404 and the Links to the HyperLogLog Page also dont work.

Please assign me.

Accept batch read response without key digest

The current batch read response protocol sends back the digest for every record. This information was used to verify that the batch index (also sent back for every record) pointed to the correct key entry. Because the digest is not strictly necessary, we plan to eventually remove it from the batch response protocol.

E.g. Java client change (CLIENT-1119): aerospike/aerospike-client-java@27a855a

Support Predicate Filtering

Hello,

i just started to implement the Rust Client into one of my Services.
While doing that, i found out that it is not supporting Predicate Filtering filtering. It would be great if this Client would also support it.
Querying for multiple secondary bins is really hacky without this.

Thanks
Jonas

Feature Request: Rust UDF

It would be great to be able to write native modules similar to how this can be done with Redis. Is that on the road map?

TLS support

Support for Transport Layer Security for all communication between the client and all cluster nodes. Support for all 3 TLS security modes:

  • Standard Authentication
  • Mutual Authentication
  • Encryption-Only

Note: Requires Aerospike Enterprise Server Version 3.11 or later.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.