Wrong number of arguments when using mget with redis-rs - redis

I'm trying to access Redis using Rust with the following:
extern crate redis;
use redis::{Client, Commands, Connection, RedisResult};
fn main() {
let redis_client = Client::open("redis://127.0.0.1/").unwrap();
let redis_conn = redis_client.get_connection().unwrap();
let mut keys_to_get = vec![];
keys_to_get.push("random_key_1".to_string());
keys_to_get.push("random_key_2".to_string());
let redis_result: String = redis_conn.get(keys_to_get).unwrap();
}
When I run cargo run I get:
Running `target/debug/test_resdis`
thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: An error was signalled by the server: wrong number of arguments for 'get' command', ../src/libcore/result.rs:746
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: Process didn't exit successfully: `target/debug/test_resdis` (exit code: 101)
Am I doing something wrong, or is it a bug?

Running your program against a netcat server shows the following requests made:
*3
$3
GET
$12
random_key_1
$12
random_key_2
The GET command should be an MGET.
I believe this to be a bug in the implementation:
impl<T: ToRedisArgs> ToRedisArgs for Vec<T> {
fn to_redis_args(&self) -> Vec<Vec<u8>> {
ToRedisArgs::make_arg_vec(self)
}
}
impl<'a, T: ToRedisArgs> ToRedisArgs for &'a [T] {
fn to_redis_args(&self) -> Vec<Vec<u8>> {
ToRedisArgs::make_arg_vec(*self)
}
fn is_single_arg(&self) -> bool {
ToRedisArgs::is_single_vec_arg(*self)
}
}
Under the hood, the library inspects the key type to know if it's multivalued or not, using ToRedisArgs::is_single_arg, which has a default implementation of true.
As you can see, a slice implements ToRedisArgs::is_single_arg, but a Vec does not. This also suggests a workaround: treat the vector like a slice:
redis_conn.get(&*keys_to_get)
This issue has now been filed with the library.

Related

Cannot move io::Error out of Peekable Result

I'm just trying to propagate the IO error:
enum MyError {
EOF,
IO(std::io::Error),
}
fn peek_byte<R>(mut p: Peekable<Bytes<R>>) -> Result<u8, MyError>
where
R: Read,
{
match p.peek() {
None => Err(MyError::EOF),
Some(Err(e)) => Err(MyError::IO(*e)), // <==== error is here
Some(Ok(byte)) => Ok(*byte),
}
}
But, I get the following error:
error[E0507]: cannot move out of `*e` which is behind a shared reference
--> src/main.rs:17:41
|
17 | Some(Err(e)) => Err(MyError::IO(*e)),
| ^^ move occurs because `*e` has type `std::io::Error`, which does not implement the `Copy` trait
I actually understand all of this. I know why I'm getting the error, and what the error means. What I don't know is how to accomplish my task and propagate the IO error into my error type.
I have tried e, *e, e.clone(), *e.clone(), *(e.clone()), but they all either produce a "type mismatch" or a "cannot move" error.
The Peekable iterator holds ownership of the next value of its internal iterator and returns references via peek, but if you actually want the owned value you just call next as usual (which does advance the iterator but I think that's okay in this case since you're not actually consuming any content from the iterator but just trying to return an error):
use std::io;
use std::io::Bytes;
use std::io::Read;
use std::iter::Peekable;
enum MyError {
EOF,
IO(io::Error),
}
fn peek_byte<R>(mut p: Peekable<Bytes<R>>) -> Result<u8, MyError>
where
R: Read,
{
match p.peek() {
None => Err(MyError::EOF),
Some(Err(e)) => Err(MyError::IO(p.next().unwrap().unwrap_err())),
Some(Ok(byte)) => Ok(*byte),
}
}
playground

How do I fix "may not be safely transferred across an unwind boundary" for VaList?

I am trying to override/wrap the Libc vprintf(format, va_list) function with Rust code. To do so, I need to pass a VaList argument into unsafe code that also needs to catch unwind errors:
#![feature(c_variadic)]
extern crate libc;
use libc::{c_char, c_int};
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
if true {
::std::panic::catch_unwind(|| hook_fn(format, args)).ok()
} else {
None
}
.unwrap_or_else(|| hook_fn(format, args))
}
pub unsafe fn hook_fn(format: *const c_char, args: std::ffi::VaList) -> c_int {
0
}
fn main() {
println!("Hello, world!");
}
My code does not compile:
error[E0277]: the type `&mut std::ffi::VaListImpl<'_>` may not be safely transferred across an unwind boundary
--> src/main.rs:8:9
|
8 | ::std::panic::catch_unwind(|| hook_fn(format, args)).ok()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------------ within this `[closure#src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`
| |
| `&mut std::ffi::VaListImpl<'_>` may not be safely transferred across an unwind boundary
|
= help: within `[closure#src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`, the trait `std::panic::UnwindSafe` is not implemented for `&mut std::ffi::VaListImpl<'_>`
= note: `std::panic::UnwindSafe` is implemented for `&std::ffi::VaListImpl<'_>`, but not for `&mut std::ffi::VaListImpl<'_>`
= note: required because it appears within the type `std::ffi::VaList<'_, '_>`
= note: required because it appears within the type `[closure#src/main.rs:8:36: 8:60 format:&*const i8, args:std::ffi::VaList<'_, '_>]`
Some types, especially FFI types, can cause Undefined Behaviour if used after a panic. This safety is tracked by whether or not a type implements UnwindSafe, and VaList does not.
This is explained in the first "help" line of the error message:
= help: within `[closure#src/main.rs:8:36: 8:61 format:&*const i8, args:std::ffi::VaList<'_, '_>]`,
the trait `std::panic::UnwindSafe` is not implemented for `&mut std::ffi::VaListImpl<'_>`
The first "note" also gives you a possible solution:
note: `std::panic::UnwindSafe` is implemented for `&std::ffi::VaListImpl<'_>`, but not for `&mut std::ffi::VaListImpl<'_>`
It's telling you that it is safe to share immutable references to a VaListImpl across an unwind boundary. So you can fix your code by passing the value by reference instead:
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
if true {
::std::panic::catch_unwind(|| hook_fn(format, &args)).ok()
} else {
None
}
.unwrap_or_else(|| hook_fn(format, &args))
}
pub unsafe fn hook_fn(format: *const c_char, args: &std::ffi::VaList) -> c_int {
0
}
This helped fix the problem.
Not sure if this is the right way to fix this. Peter Halls suggestion above might still be right one. But it did not seem to fix the error for me.
#![feature(c_variadic)]
extern crate libc;
use libc::{c_char, c_int};
pub unsafe extern "C" fn vprintf(format: *const c_char, args: std::ffi::VaList) -> c_int {
let ap : VaListImpl = args.clone();
if true {
::std::panic::catch_unwind(|| hook_fn(format, ap.clone())).ok()
} else {
None
}
.unwrap_or_else(|| hook_fn(format, args))
}
pub unsafe fn hook_fn(format: *const c_char, args: std::ffi::VaList) -> c_int {
0
}
fn main() {
println!("Hello, world!");
}

How to create a vector of all decorated functions from a specific module?

I have a file main.rs and a file rule.rs. I want to define functions in rule.rs to be included in the Rules::rule vector without having to push them one by one. I'd prefer a loop to push them.
main.rs:
struct Rules {
rule: Vec<fn(arg: &Arg) -> bool>,
}
impl Rules {
fn validate_incomplete(self, arg: &Arg) -> bool {
// iterate through all constraints and evaluate, if false return and stop
for constraint in self.incomplete_rule_constraints.iter() {
if !constraint(&arg) {
return false;
}
}
true
}
}
rule.rs:
pub fn test_constraint1(arg: &Arg) -> bool {
arg.last_element().total() < 29500
}
pub fn test_constraint2(arg: &Arg) -> bool {
arg.last_element().total() < 35000
}
Rules::rule should be populated with test_constraint1 and test_constraint2.
In Python, I could add a decorator #rule_decorator above the constraints which you want to be included in the Vec, but I don't see an equivalent in Rust.
In Python, I could use dir(module) to see all available methods/attributes.
Python variant:
class Rules:
def __init__(self, name: str):
self.name = name
self.rule = []
for member in dir(self):
method = getattr(self, member)
if "rule_decorator" in dir(method):
self.rule.append(method)
def validate_incomplete(self, arg: Arg):
for constraint in self.incomplete_rule_constraints:
if not constraint(arg):
return False
return True
With the rule.py file:
#rule_decorator
def test_constraint1(arg: Arg):
return arg.last_element().total() < 29500
#rule_decorator
def test_constraint1(arg: Arg):
return arg.last_element().total() < 35000
All functions with a rule_decorator are added to the self.rule list and checked off by the validate_incomplete function.
Rust does not have the same reflection features as Python. In particular, you cannot iterate through all functions of a module at runtime. At least you can't do that with builtin tools. It is possible to write so called procedural macros which let you add custom attributes to your functions, e.g. #[rule_decorator] fn foo() { ... }. With proc macros, you can do almost anything.
However, using proc macros for this is way too over-engineered (in my opinion). In your case, I would simply list all functions to be included in your vector:
fn test_constraint1(arg: u32) -> bool {
arg < 29_500
}
fn test_constraint2(arg: u32) -> bool {
arg < 35_000
}
fn main() {
let rules = vec![test_constraint1 as fn(_) -> _, test_constraint2];
// Or, if you already have a vector and need to add to it:
let mut rules = Vec::new();
rules.extend_from_slice(
&[test_constraint1 as fn(_) -> _, test_constraint2]
);
}
A few notes about this code:
I replaced &Arg with u32, because it doesn't have anything to do with the problem. Please omit unnecessary details from questions on StackOverflow.
I used _ in the number literals to increase readability.
The strange as fn(_) -> _ cast is sadly necessary. You can read more about it in this question.
You can, with some tweaks and restrictions, achieve your goals. You'll need to use the inventory crate. This is limited to Linux, macOS and Windows at the moment.
You can then use inventory::submit to add values to a global registry, inventory::collect to build the registry, and inventory::iter to iterate over the registry.
Due to language restrictions, you cannot create a registry for values of a type that you do not own, which includes the raw function pointer. We will need to create a newtype called Predicate to use the crate:
use inventory; // 0.1.3
struct Predicate(fn(&u32) -> bool);
inventory::collect!(Predicate);
struct Rules;
impl Rules {
fn validate_incomplete(&self, arg: &u32) -> bool {
inventory::iter::<Predicate>
.into_iter()
.all(|Predicate(constraint)| constraint(arg))
}
}
mod rules {
use super::Predicate;
pub fn test_constraint1(arg: &u32) -> bool {
*arg < 29500
}
inventory::submit!(Predicate(test_constraint1));
pub fn test_constraint2(arg: &u32) -> bool {
*arg < 35000
}
inventory::submit!(Predicate(test_constraint2));
}
fn main() {
if Rules.validate_incomplete(&42) {
println!("valid");
} else {
println!("invalid");
}
}
There are a few more steps you'd need to take to reach your originally-stated goal:
"a vector"
You can collect from the provided iterator to build a Vec.
"decorated functions"
You can write your own procedural macro that will call inventory::submit!(Predicate(my_function_name)); for you.
"from a specific module"
You can add the module name into the Predicate struct and filter on that later.
See also:
How can I statically register structures at compile time?

Working with UDP using mio and getting an error "MutBuf is not implemented for the type MutSliceBuf"

For learning purposes I am currently trying to write small program which will implement echo-server for UDP packets which will work on a certain set of ports (say 10000-60000). So as it wouldn't be so good to spam 50k threads for this I need to use asynchronous IO and mio is excellent match for this task. But I've got a problem right from the start with this code:
extern crate mio;
extern crate bytes;
use mio::udp::*;
use bytes::MutSliceBuf;
fn main() {
let addr = "127.0.0.1:10000".parse().unwrap();
let socket = UdpSocket::bound(&addr).unwrap();
let mut buf = [0; 128];
socket.recv_from(&mut MutSliceBuf::wrap(&mut buf));
}
It is almost full copypaste from of mio's test_udp_socket.rs.But while mio's tests successfully pass through, then I try to compile this code I am getting following error:
src/main.rs:12:12: 12:55 error: the trait `bytes::buf::MutBuf` is not implemented for the type `bytes::buf::slice::MutSliceBuf<'_>` [E0277]
src/main.rs:12 socket.recv_from(&mut MutSliceBuf::wrap(&mut buf));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:12:12: 12:55 help: run `rustc --explain E0277` to see a detailed explanation
But examining code of src/buf/slice.rs from bytes crate (local copy of it too) we can clearly see what this trait was implemented:
impl<'a> MutBuf for MutSliceBuf<'a> {
fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
fn advance(&mut self, mut cnt: usize) {
cnt = cmp::min(cnt, self.remaining());
self.pos += cnt;
}
unsafe fn mut_bytes<'b>(&'b mut self) -> &'b mut [u8] {
&mut self.bytes[self.pos..]
}
}
It's probably something trivial, but I can't find it... What could be a problem which causes this error?
I am using rustc 1.3.0 (9a92aaf19 2015-09-15), crates mio and bytes is gotten straight from github.
Using Cargo with
[dependencies]
mio = "*"
bytes = "*"
this runs for me. Using the Github dependency,
[dependencies.mio]
git = "https://github.com/carllerche/mio.git"
gives the error you mention.
Strangely, version 0.4 depends on
bytes = "0.2.11"
whereas master depends on
git = "https://github.com/carllerche/bytes"
rev = "7edb577d0a"
which is only version 0.2.10. Strange.
The problem is that you end up getting two bytes dependencies compiled, so the error is more like
the trait `mio::bytes::buf::MutBuf` is not implemented for the type `self::bytes::buf::slice::MutSliceBuf<'_>`
The simplest way I see to fix this is to just use both packages from crates.io.
[dependencies]
mio = "*"
bytes = "*"
Another way is to use
[dependencies.bytes]
git = "https://github.com/carllerche/bytes"
rev = "7edb577d0a"
in your own Cargo.toml, such that you share versions.

Unable to read file contents to string - Result does not implement any method in scope named `read_to_string`

I followed the code to open a file from Rust by Example:
use std::{env, fs::File, path::Path};
fn main() {
let args: Vec<_> = env::args().collect();
let pattern = &args[1];
if let Some(a) = env::args().nth(2) {
let path = Path::new(&a);
let mut file = File::open(&path);
let mut s = String::new();
file.read_to_string(&mut s);
println!("{:?}", s);
} else {
//do something
}
}
However, I got a message like this:
error[E0599]: no method named `read_to_string` found for type `std::result::Result<std::fs::File, std::io::Error>` in the current scope
--> src/main.rs:11:14
|
11 | file.read_to_string(&mut s);
| ^^^^^^^^^^^^^^ method not found in `std::result::Result<std::fs::File, std::io::Error>`
What am I doing wrong?
Let's look at your error message:
error[E0599]: no method named `read_to_string` found for type `std::result::Result<std::fs::File, std::io::Error>` in the current scope
--> src/main.rs:11:14
|
11 | file.read_to_string(&mut s);
| ^^^^^^^^^^^^^^ method not found in `std::result::Result<std::fs::File, std::io::Error>`
The error message is pretty much what it says on the tin - the type Result does not have the method read_to_string. That's actually a method on the trait Read.
You have a Result because File::open(&path) can fail. Failure is represented with the Result type. A Result may be either an Ok, which is the success case, or an Err, the failure case.
You need to handle the failure case somehow. The easiest is to just die on failure, using expect:
let mut file = File::open(&path).expect("Unable to open");
You'll also need to bring Read into scope to have access to read_to_string:
use std::io::Read;
I'd highly recommend reading through The Rust Programming Language and working the examples. The chapter Recoverable Errors with Result will be highly relevant. I think these docs are top-notch!
If your method returns Result<String, io::Error>, you can use ? on the functions that return a Result:
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
If you cannot return a Result<String, io::Error> then you have to handle error case using expect as mentioned in the accepted answer or matching on the Result and panicking:
let file = File::open(&opt_raw.config);
let file = match file {
Ok(file) => file,
Err(error) => {
panic!("Problem opening the file: {:?}", error)
}
};
For more information, please refer to Recoverable Errors with Result.