This question already has an answer here:
Can't understand Rust module system
(1 answer)
Closed 3 years ago.
I am reading the Rust Book, I am in the chapter 7.2, but I must be missing something, because I cannot organize my code in modules, the compiler (rustc 1.32.0) keeps giving me errors.
What I have read
I read rustc --explain E0433, which is the advice of the compiler, but I still cannot solve it.
I checked Rust by examples, and it seems that my code is correct, (my/mod.rs is using module my/nested.rs in its own folder)
I found some info on Internet, but it is of 4 years ago, and include the use of use, which is not yet in the book.
I also checked this question, but I am not using folders, and again, it gets away from the book explanation.
Minimal example
This is a minimal example that tries to mimic the "sound" example of the book, there is only two files: /src/main.rs and /src/m.rs.
main.rs
mod m;
fn main() {
let st_0 = m::St::new();
}
m.rs
pub mod m {
pub struct St {
a:i32,
b:i32,
}
impl St {
pub fn new() -> St{
println!("New St!");
St {
a: 12,
b: 13,
}
}
}
}
And this is what cargo tells me:
Compiling min v0.1.0 (/home/user/min)
error[E0433]: failed to resolve: could not find `St` in `m`
--> src/main.rs:3:19
|
3 | let st_0 = m::St::new();
| ^^ could not find `St` in `m`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0433`.
error: Could not compile `min`.
To learn more, run the command again with --verbose.
When you have everything in one file, like this:
main.rs
pub mod m {
pub struct St {
a:i32,
b:i32,
}
impl St {
pub fn new() -> St{
println!("New St!");
St {
a: 12,
b: 13,
}
}
}
}
mod m;
fn main() {
let st_0 = m::St::new();
}
you wrap the module with the
pub mod mode_name {
//code...
}
Once you put the module in another file, that wrapping goes away. The Rust book, shows it, but if you don't look carefully or if you are programming drunk, you may get confused with the pub mod instrument {...} of the nested module.
So m.rs has to look like this:
pub struct St {
a:i32,
b:i32,
}
impl St {
pub fn new() -> St{
println!("New St!");
St {
a: 12,
b: 13,
}
}
}
Related
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!");
}
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?
Why isn't Result<()> allowed when compiling this bit of Rust code? Is it a breaking change between Rust editions?
fn run() -> Result<()> {
let (tx, rx) = channel();
thread::spawn(move || {
do_things_with_tx(&exit_tx);
});
match exit_rx.recv() {
Ok(result) => if let Err(reason) = result {
return Err(reason);
},
Err(e) => {
return Err(e.into());
},
}
Ok(())
}
The compiler says:
error[E0107]: wrong number of type arguments: expected 2, found 1
--> src/main.rs:1000:18
|
1000 | fn run_wifi() -> Result<()> {
| ^^^^^^^^^^ expected 2 type arguments
When I tweak the return type to Result<(), Err>, it says:
error[E0107]: wrong number of type arguments: expected 2, found 0
--> src/main.rs:1000:29
|
1000 | fn run() -> Result<(), Err> {
| ^^^ expected 2 type arguments
This is from the wifi-connect project.
The definition of Result is, and has always been, the following:
pub enum Result<T, E> {
Ok(T),
Err(E),
}
This definition is even presented in the Rust Programming language, to show how simple it is. As a generic sum type of an OK outcome and an error outcome, it always expects two type parameters, and the compiler will complain if it cannot infer them, or the list of type arguments does not have the expected length.
On the other hand, one may find many libraries and respective docs showing a Result with a single type argument, as in Result<()>. What gives?
It's still no magic. By convention, libraries create type aliases for result types at the level of a crate or module. This works pretty well because it is common for those to produce errors of the same, locally created type.
pub type Result<T> = std::result::Result<T, Error>;
Or alternatively, a definition which can still purport as the original result type.
pub type Result<T, E = Error> = std::result::Result<T, E>;
This pattern is so common that some error helper crates such as error-chain, will automatically create a result alias type for each error declared.
As such, if you are using a library that may or may not use error-chain, you are expected to assume that mentions of Result<T> are local type aliases to a domain-specific Result<T, Error>. In case of doubt, clicking on that type in the generated documentation pages will direct you to the concrete definition (in this case, the alias).
From The Rust Programming Language section The ? Operator Can Only Be Used in Functions That Return Result
use std::error::Error;
use std::fs::File;
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("hello.txt")?;
Ok(())
}
TL;DR
use std::io::Result;
Link to the type description
Long answer
I believe that the top-voted answer given by E_net4 the comment flagger is correct. But it doesn't work if applied blindly. In both cases
this
pub type Result<T> = Result<T, Error>;
and this
pub type Result<T, E = Error> = Result<T, E>;
will give the cycle dependency error
error[E0391]: cycle detected when expanding type alias `Result`
--> src\main.rs:149:33
|
149 | pub type Result<T, E = Error> = Result<T, E>;
| ^^^^^^^^^^^^
|
= note: ...which immediately requires expanding type alias `Result` again
= note: type aliases cannot be recursive
= help: consider using a struct, enum, or union instead to break the cycle
= help: see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
So as much as users of SO don't want to admit it, but Gabriel soft is very close to elegant solution, because that type alias
pub type Result<T> = result::Result<T, Error>;
is straight from the standard library.
Here it is, our desired Result with 1 generic argument is defined in std::io (docs). To fix the problem I added
use std::io::Result;
fn some_func() -> Result<()> {
...
}
or
use std::io;
fn some_func() -> io::Result<()> {
...
}
rustc 1.62.1
i solved my own error by making a generic Result type to handle the error
As its says it require a generic of T and E, so to simplify things, i had to follow this way
pub type Result = result::Result<T, Error>;
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.
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.