I'm starting a project to learn Rust and I fail at the most basic things, like setting up a proper module structure. My code looks like this:
// src/theorem/math.rs
pub mod theorem {
pub mod math {
use std::ops::{Add, Sub};
pub struct Point {
x: i32,
y: i32,
}
impl Add for Point {
// Omitted...
}
}
pub use math::{Point};
}
#[cfg(test)]
mod tests {
use theorem::math::{Point};
#[test]
fn add_point() {
let v1 = Point { x: 1, y: 1 };
let v2 = Point { x: 2, y: 2 };
assert_eq!(v1 + v1, v2);
}
}
I tried pub use, and I tried to write pub in front of everything, everywhere, but all I get is the message
error[E0432]: unresolved import `math::Point`
--> src/theorem/math.rs:28:20
|
28 | pub use math::{Point};
| ^^^^^ no `Point` in `math`
Which is a nice insight but does not help me. I read through the docs but there are no real examples for this case, but... it must be possible, right?
I have also tried to have a proper directory structure like src/theorem/math/point.rs but that did not work either.
What compiler version do you use? Since version 1.13, the error message looks like this:
error[E0432]: unresolved import `math::Point`
--> <anon>:16:20
|
16 | pub use math::{Point};
| ^^^^^ Did you mean `self::math`?
And pub use self::math::{Point}; is in fact the solution to your question! When you use a path, this path is always an absolute path. This means it is interpreted from the root of your crate. But there is no math module as direct child of the root module, hence the error.
Related
Summary
I'm writing a program in rust and I would prefer use a TOML file to store a vector of struct's. However I can't figure out how to store a vector of struct's in a TOML file. I am able to do this using JSON but was hoping for TOML so just confirming that I'm not overlooking something (not even sure if the TOML format would be able to support what I want). Therefore, I'm trying to find out if anyone knows of a way use rust to serialize a vector of struct's to TOML and more importantly to deserialize it back into a vector.
Error message (on attempt to deserialize)
thread 'main' panicked at 'called Result::unwrap() on an Err value: Error { inner: ErrorInner { kind: Wanted { expected: "a table key", found: "a right bracket" }, line: Some(0), col: 2, at: Some(2), message: "", key: [] } }', src/main.rs:22:55
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
Excerpt from Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.86"
toml = "0.5.9"
Example code
Link to code on Playground
use serde::{Deserialize, Serialize};
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Point {
x: i32,
}
/// An ordered list of points (This is what I want to store in the TOML file)
type Points = Vec<Point>;
fn main(){
// Create sample data to test on
let original: Points = vec![Point { x: 1 }];
// Working code that converts it to json and back
let json = serde_json::to_string(&original).unwrap();
let reconstructed: Points = serde_json::from_str(&json).unwrap();
assert_eq!(original, reconstructed); // No panic
// "Desired" code that converts it to toml but unable to deserialize
let toml = toml::to_string(&original).unwrap();
let reconstructed: Points = toml::from_str(&toml).unwrap(); // Panics!
assert_eq!(original, reconstructed);
}
Output of toml::to_string(&original).unwrap()
[[]]
x = 1
Explanation of example code
In the example code I create some sample data then convert it to JSON and back with no issue. I then try to convert it to TOML, which doesn't give an error but the output doesn't make sense to me. Then I try to convert it back into a rust vector and that triggers the error. My biggest problem is I'm not even sure how I would expect the TOML file to look for a valid representation of a vector with multiple struct's.
Related Questions / Research
I wasn't able to find any information for creating a vector with multiple struct's the closest I could find is this question, and while the question looks like it should solve my problem the actual problem was serializing enums and the solution hence refers to that and doesn't solve my problem.
It seems that to represent an array of tables in Toml the syntax is
[[points]]
x = 1
[[points]]
x = 2
So backtracking from Toml syntax and original panic error Error { inner: ErrorInner { kind: Wanted { expected: "a table key", found: "a right bracket" }: Introducing a wrapper struct to represent table key fixes the issue.
use serde::{Deserialize, Serialize};
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Point {
x: i32,
}
#[derive(PartialEq, Debug,Serialize, Deserialize)]
struct Points {
points: Vec<Point>
}
impl From<Vec<Point>> for Points {
fn from(points: Vec<Point>) -> Self {
Points {
points
}
}
}
fn main(){
let original: Points = vec![Point { x: 1 }, Point {x : 2}].into();
let json = serde_json::to_string(&original).unwrap();
let reconstructed: Points = serde_json::from_str(&json).unwrap();
assert_eq!(original, reconstructed);
let toml = toml::to_string(&original).unwrap();
let reconstructed: Points = toml::from_str(&toml).unwrap();
assert_eq!(original, reconstructed);
}
I'm trying to use the Snafu crate for some basic error handling. In this case, I'm trying to return an Error when check_value() is given anything but a CustomInputValue::CiFloat. Based on what I was seeing in examples on this page from the docs, I thought this would work:
use snafu::{Backtrace, ResultExt, Snafu, ensure};
#[derive(Debug, Snafu)]
pub enum Error{
#[snafu(display("Incorrect Type: {:?}"), kind)]
IncorrectInputType{kind: CustomInputValue},
}
#[derive(Debug, Clone, PartialEq)]
pub enum CustomInputValue{
CiBool(bool),
CiInt(i32),
CiFloat(f64),
}
type Result<T, E = Error> = std::result::Result<T, E>;
fn main(){
check_value(CustomInputValue::CiFloat(10.0));
}
fn check_value(val: CustomInputValue )->Result<()>{
match val {
CustomInputValue::CiFloat(inp)=>inp,
_=>Error::IncorrectInputType{kind: val}.fail()?
};
Ok(())
}
However, this produces the error:
error[E0599]: no method named `fail` found for enum `Error` in the current scope
--> src/main.rs:24:57
|
4 | pub enum Error{
| -------------- method `fail` not found for this
...
24 | _=>Error::IncorrectInputType{kind: val}.fail()?
| ^^^^ method not found in `Error`
What's causing this error? Do I need to implement a fail function? I don't see anywhere in the docs such a custom fail() function being written for Error, and can't find anything bout requiring a fail() function for Error in the docs.
The #[derive(Snafu)] attribute creates "context selectors" for each enum variant. That means that Error::IncorrectInputType refers to the variant, while IncorrectInputType is a generated struct which has the fail() method.
The fix is to use this selector instead of the enum:
match val {
CustomInputValue::CiFloat(inp) => inp,
_ => IncorrectInputType { kind: val }.fail()?
// ^^^^^^^^^^^^^^^^^^ no Error::
};
You can browse the rest of the SNAFU user's guide to know more about the macro.
Also, the kind in the #[snafu(display(...))] attribute is misplaced. It should be a parameter within the display portion:
#[snafu(display("Incorrect Type: {:?}", kind))]
IncorrectInputType { kind: CustomInputValue },
I'm trying to understand how to use the failure crate. It works splendidly as a unification of different types of standard errors, but when creating custom errors (Fails), I do not understand how to match for custom errors. For example:
use failure::{Fail, Error};
#[derive(Debug, Fail)]
pub enum Badness {
#[fail(display = "Ze badness")]
Level(String)
}
pub fn do_badly() -> Result<(), Error> {
Err(Badness::Level("much".to_owned()).into())
}
#[test]
pub fn get_badness() {
match do_badly() {
Err(Badness::Level(level)) => panic!("{:?} badness!", level),
_ => (),
};
}
fails with
error[E0308]: mismatched types
--> barsa-nagios-forwarder/src/main.rs:74:9
|
73 | match do_badly() {
| ---------- this match expression has type `failure::Error`
74 | Err(Badness::Level(level)) => panic!("{:?} badness!", level),
| ^^^^^^^^^^^^^^^^^^^^^ expected struct `failure::Error`, found enum `Badness`
|
= note: expected type `failure::Error`
found type `Badness`
How can I formulate a pattern which matches a specific custom error?
You need to downcast the Error
When you create a failure::Error from some type that implements the Fail trait (via from or into, as you do), you temporarily hide the information about the type you're wrapping from the compiler. It doesn't know that Error is a Badness - because it can also be any other Fail type, that's the point. You need to remind the compiler of this, the action is called downcasting. The failure::Error has three methods for this: downcast, downcast_ref and downcast_mut. After you've downcast it, you can pattern match on the result as normal - but you need to take into account the possibility that downcasting itself may fail (if you try to downcast to a wrong type).
Here's how it'd look with downcast:
pub fn get_badness() {
if let Err(wrapped_error) = do_badly() {
if let Ok(bad) = wrapped_error.downcast::<Badness>() {
panic!("{:?} badness!", bad);
}
}
}
(two if lets can be combined in this case).
This quickly gets very unpleasant if more than one error type needs to be tested, since downcast consumes the failure::Error it was called on (so you can't try another downcast on the same variable if the first one fails). I sadly couldn't figure out an elegant way to do this. Here's a variant one shouldn't really use (panic! in map is questionable, and doing anything else there would be plenty awkward, and I don't even want to think about more cases than two):
#[derive(Debug, Fail)]
pub enum JustSoSo {
#[fail(display = "meh")]
Average,
}
pub fn get_badness() {
if let Err(wrapped_error) = do_badly() {
let e = wrapped_error.downcast::<Badness>()
.map(|bad| panic!("{:?} badness!", bad))
.or_else(|original| original.downcast::<JustSoSo>());
if let Ok(so) = e {
println!("{}", so);
}
}
}
or_else chain should work OK if you actually want to produce some value of the same type from all of the possible\relevant errors. Consider also using non-consuming methods if a reference to the original error is fine for you, as this would allow you to just make a series of if let blocks , one for each downcast attempt.
An alternative
Don't put your errors into failure::Error, put them in a custom enum as variants. It's more boilerplate, but you get painless pattern matching, which the compiler also will be able to check for sanity. If you choose to do this, I'd recommend derive_more crate which is capable of deriving From for such enums; snafu looks very interesting as well, but I have yet to try it. In its most basic form this approach looks like this:
pub enum SomeError {
Bad(Badness),
NotTooBad(JustSoSo),
}
pub fn do_badly_alt() -> Result<(), SomeError> {
Err(SomeError::Bad(Badness::Level("much".to_owned())))
}
pub fn get_badness_alt() {
if let Err(wrapper) = do_badly_alt() {
match wrapper {
SomeError::Bad(bad) => panic!("{:?} badness!", bad),
SomeError::NotTooBad(so) => println!("{}", so),
}
}
}
I have a small program that I've been trying to get working, but I keep getting unresolved import messages.
main.rs:
mod sub_module;
use sub_module::a_structure;
fn main() {
let x: a_structure = /* init code */;
}
sub_module.rs:
pub mod sub_sub_module;
pub use sub_sub_module::a_structure;
sub_sub_module.rs:
pub struct a_structure<T> {
some_field: i32,
}
However, on executing cargo build I get an "unresolved import sub_sub_module::a_structure". Everything I've found regarding visibility says that this should work however it doesn't. What am I missing here?
Think of Rust modules as being like a directory tree. Modules are directories, everything else is a file [1]. :: is basically /.
So, you have this structure:
/ (crate root)
└┬─ sub_module
│ └┬─ sub_sub_module
│ │ └── a_structure
│ └─ a_structure [x]
├─ a_structure
└─ main
The problem is in how you define the a_structure [x] "symlink". As explained in the book, use paths in Rust are absolute, meaning in this analogy that they all implicitly start with /. Meaning that use sub_sub_module::a_structure is referring to /sub_sub_module/a_structure, which doesn't exist.
The solution is to use a relative path by explicitly starting the path with self (effectively .) or super (effectively ..). You want ./sub_sub_module/a_structure, so the path in Rust should be self::sub_sub_module::a_structure. A full, compiling (with warnings) example looks like:
mod sub_module {
pub mod sub_sub_module {
pub struct a_structure {
some_field: i32,
}
}
pub use self::sub_sub_module::a_structure;
}
use sub_module::a_structure;
fn main() {
let x: a_structure = panic!("TODO");
}
You should also note that paths used anywhere outside of a use have the exact opposite default: they are relative to the containing module by default. If you want an absolute path in that case, you need to explicitly ask for one by starting the path with :: (just like a filesystem path that is, by default, interpreted as relative).
Aside: The conventional style is to use PascalCase for type names. Also, I had to remove the type parameter because it wasn't being used.
[1]: This is, in fact, a lie, as you can have items associated with other items. For example, associated consts, while unstable, are a thing. I suppose you could think of them in terms of resource forks or something, I don't know; it's just a metaphor!
I'm trying to involve std::error::FromError trait as widely as possible in my projects to take advantage of try! macro. However, I'm a little lost with these errors conversions between different mods.
For example, I have mod (or crate) a, which has some error handling using it's own Error type, and implements errors conversion for io::Error:
mod a {
use std::io;
use std::io::Write;
use std::error::FromError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<io::Error> for Error {
fn from_error(err: io::Error) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<(), Error> {
try!(writeln!(&mut io::stdout(), "Hello, world!"));
Ok(())
}
}
I also have mod b in the same situation, but it implements error conversion for num::ParseIntError:
mod b {
use std::str::FromStr;
use std::error::FromError;
use std::num::ParseIntError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<ParseIntError> for Error {
fn from_error(err: ParseIntError) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<usize, Error> {
Ok(try!(FromStr::from_str("14")))
}
}
Now I'm in my current mod super, which has it's own Error type, and my goal is to write a procedure like this:
#[derive(Debug)]
struct Error(String);
fn func() -> Result<(), Error> {
println!("a::func() -> {:?}", try!(a::func()));
println!("b::func() -> {:?}", try!(b::func()));
Ok(())
}
So I definitely need to implement conversions from a::Error and b::Error for my Error type:
impl FromError<a::Error> for Error {
fn from_error(a::Error(contents): a::Error) -> Error {
Error(contents)
}
}
impl FromError<b::Error> for Error {
fn from_error(b::Error(contents): b::Error) -> Error {
Error(contents)
}
}
Ok, it works up until that time. And now I need to write something like this:
fn another_func() -> Result<(), Error> {
let _ = try!(<usize as std::str::FromStr>::from_str("14"));
Ok(())
}
And here a problem raises, because there is no conversion from num::ParseIntError to Error. So it seems that I have to implement it again. But why should I? There is a conversion implemented already from num::ParseIntError to b::Error, and there is also a conversion from b::Error to Error. So definitely there is a clean way for rust to convert one type to another without my explicit help.
So, I removed my impl FromError<b::Error> block and tried this blanket impl instead:
impl<E> FromError<E> for Error where b::Error: FromError<E> {
fn from_error(err: E) -> Error {
let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
Error(contents)
}
}
And it's even worked! However, I didn't succeed to repeat this trick with a::Error, because rustc started to complain about conflicting implementations:
experiment.rs:57:1: 62:2 error: conflicting implementations for trait `core::error::FromError` [E0119]
experiment.rs:57 impl<E> FromError<E> for Error where a::Error: FromError<E> {
experiment.rs:58 fn from_error(err: E) -> Error {
experiment.rs:59 let a::Error(contents) = <a::Error as FromError<E>>::from_error(err);
experiment.rs:60 Error(contents)
experiment.rs:61 }
experiment.rs:62 }
experiment.rs:64:1: 69:2 note: note conflicting implementation here
experiment.rs:64 impl<E> FromError<E> for Error where b::Error: FromError<E> {
experiment.rs:65 fn from_error(err: E) -> Error {
experiment.rs:66 let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
experiment.rs:67 Error(contents)
experiment.rs:68 }
experiment.rs:69 }
I can even understand the origin of problem (one type FromError<E> can be implemented both for a::Error and b::Error), but I can't get how to fix it.
Theoretically, maybe this is a wrong way and there is another solution for my problem? Or I still have to repeat manually all errors conversions in every new module?
there is no conversion from num::ParseIntError to Error
It does seem like you doing the wrong thing, conceptually. When a library generates an io::Error, like your first example, then it should be up to that library to decide how to handle that error. However, from your question, it sounds like you are generating io::Errors somewhere else and then wanting to treat them as the first library would.
This seems very strange. I wouldn't expect to hand an error generated by library B to library A and say "wrap this error as if you made it". Maybe the thing you are doing should be a part of the appropriate library? Then it can handle the errors as it normally would. Perhaps you could just accept a closure and call the error-conversion as appropriate.
So definitely there is a clean way for Rust to convert one type to another without my explicit help.
(Emphasis mine). That seems really scary to me. How many steps should be allowed in an implicit conversion? What if there are multiple paths, or even if there are cycles? Having those as explicit steps seems reasonable to me.
I can even understand the origin of problem [...], but I can't get how to fix it.
I don't think it is possible to fix this. If you could implement a trait for the same type in multiple different ways, there's simply no way to pick between them, and so the code is ambiguous and rejected by the compiler.