How to access a symbol defined in nested module? - rust

I am using rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
src
├── main.rs
└── core
├── mod.rs
└── expressionType.rs
main.rs:
mod core;
use core::expressionType;
fn main() {
let t = expressionType::ExpressionType.Integer;
println!("Hello, world!")
}
expressionType.rs:
pub enum ExpressionType {
Integer,
List(Box<ExpressionType>),
Function(Box<ExpressionType>, Box<ExpressionType>)
}
mod.rs:
pub mod expressionType;
from src, when I try to do rustc main.rs, I get
main.rs:5:13: 5:43 error: unresolved name `expressionType::ExpressionType`
main.rs:5 let t = expressionType::ExpressionType.Integer;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
I also tried core::expressionType::ExpressionType and expressionType.ExpressionType
Am I missing something? Why can't I access enum from expressionType.rs
UPD1: I also tried to add
pub use self::expressionType::ExpressionType;
to mod.rs, but after that in main.rs neither core::ExpressionType, nor expressionType::ExpressionType become available.

You need to write ExpressionType::Integer rather than ExpressionType.Integer (:: instead of .). In the latter case, the compiler is looking for a value, such as a variable or constant, named ExpressionType.

Related

Failed to resolve module with a use statement, but the module can be used when specifying scope

In Rust, I have the following folder structure:
├── Cargo.toml
└── src
├── bin
│ └── main.rs
└── lib.rs
This is as recommended in this answer.
This is the (relevant) contents of the Cargo.toml file:
[package]
name = "devinit"
...
And this is the contents of my lib.rs file:
pub mod testmod {
pub fn testfunc() {
println!("Hello world");
}
}
When trying to use the function testfunc() in main.rs, I can refer to it by specifying its scope:
fn main() {
devinit::testmod::testfunc();
}
This compiles and executes successfully. However, if I were to actually 'use' it, as seen below...
use devinit::testmod::testfunc;
fn main() {
testfunc();
}
...the compilation fails. The following code fails to compile with the error 'failed to resolve: maybe a missing crate `devinit`?'
Why is this happening? Looking at the aforementioned answer's author's project (linked in previous edits of the answer), the structure seems to be the same...
I'm pretty new to Rust, so maybe I missed something?

How to use rust module inside a different test directory?

This is my directory structure,
.
├── Cargo.lock
├── Cargo.toml
├── src
│ ├── add.rs
│ └── main.rs
└── tests
└── add_test.rs
add.rs
pub fn add(a: u8, b: u8) -> u8 {
return a + b;
}
main.rs
pub mod add;
fn main() {}
add_test.rs
#[cfg(test)]
mod tests {
#[test]
fn add_test() {
// how do I use add.rs module?
}
}
In add_test function how do I test add.rs's add function?
Notice that you are using mod add;. This is not a public module meaning it is unavailable outside of your crate.
To have it available outside the crate (and therefore available in the test) you can either make the module public, or reexport the function itself.
Additionally, to do this, you will need a lib.rs file in src where the exports are put:
// Make module public
pub mod add;
// Make the function available at the root of the crate
pub use add::add;
To then use your function in tests, you call it the same way you would call a function for a different crate. Lets assume your crate was named your-crate:
// If your module is public
your-crate::add::add(2,3);
// If you reexport the function
your-crate::add(2,3);
See more details in the chapter on test organization in the Rust book.

How do I use a custom namespaced derive-macro attribute on a type instead of inside the type?

I'd like to create a custom derive macro that uses the new namespaced attribute syntax: example::attr. I've been able to get this to work with attributes within the type (on a struct field or an enum variant, for example), but not when applied to the type itself.
src/main.rs
use repro_derive::Example;
#[derive(Example)]
#[example::attr] // Does not work
struct Demo {
#[example::attr] // Works
field: i32,
}
fn main() {}
The procedural macro itself does nothing, other than to declare that example::attr is a valid attribute.
repro-derive/src/lib.rs
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(Example, attributes(example::attr))]
pub fn example_derive(_input: TokenStream) -> TokenStream {
TokenStream::new()
}
Compiling yields:
error[E0433]: failed to resolve: use of undeclared type or module `example`
--> src/main.rs:4:3
|
4 | #[example::attr]
| ^^^^^^^ use of undeclared type or module `example`
Switching to a non-namespaced form of the attribute (example_attr) works fine.
I'm using Rust 1.32.0. The project layout is
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── repro-derive
│   ├── Cargo.toml
│   └── src
│   └── lib.rs
└── src
└── main.rs
Cargo.toml
$ cat Cargo.toml
[package]
name = "repro"
version = "0.1.0"
authors = ["Author"]
edition = "2018"
[dependencies]
repro-derive = { path = "repro-derive" }
repro-derive/Cargo.toml
[package]
name = "repro-derive"
version = "0.1.0"
authors = ["Author"]
edition = "2018"
[lib]
proc-macro = true
[dependencies]
The namespace declared in the proc_macro_derive attribute is entirely ignored, and this is a known bug. Because of this bug, the following code can be compiled, though it shouldn't be.
#[derive(Example)]
#[attr] // Works (but shouldn't)
struct Demo {
#[lolwut::attr] // Works (but shouldn't)
field: i32,
}
Until the bug is fixed, you should keep using the non-namespaced form (example_attr).
Also, according to this bug report, as of Rust 1.33.0 there is no way to achieve what OP wants via proc-macros, and how to allow #[example::attr] to work is still under design.

"unresolved import -- maybe a missing extern" When extern declaration exists

I have a small project which built with no issues when it was all in one big .rs file. I wanted to make it easier to work with, so I broke it up into modules, and the project is now structured like this:
├── GameState
│   ├── ballstate.rs
│   ├── collidable.rs
│   ├── gamestate.rs
│   ├── mod.rs
│   └── playerstate.rs
├── lib.rs
└── main.rs
In ballstate.rs, I need to use the rand crate. Here's an abbreviated version of the file:
extern crate rand;
pub struct BallState {
dir: Point,
frame: BoundingBox
}
impl BallState {
fn update_dir(&mut self) {
use rand::*;
let mut rng = rand::thread_rng();
self.dir.x = if rng.gen() { Direction::Forwards.as_float() } else { Direction::Backwards.as_float() };
self.dir.y = if rng.gen() { Direction::Forwards.as_float() } else { Direction::Backwards.as_float() };
}
}
However, when I run cargo build from the top level directory, I get the following error:
GameState/ballstate.rs:42:9: 42:13 error: unresolved import rand::*. Maybe a missing extern crate rand?
When I just had the extern crate declaration in my main.rs file, this worked. What's changed now that it's in a separate module?
To quote from the Crates and Modules chapter of the Rust book:
[...] use declarations are absolute paths, starting from your crate root. self makes that path relative to your current place in the hierarchy instead.
The compiler is correct; there is no such thing as rand, because you've put it inside a module, so the correct path to it would be GameState::ballstate::rand, or self::rand from within the GameState::ballstate module.
You need to either move extern crate rand; to the root module or use self::rand within the GameState::ballstate module.
You need to put the extern crate rand; line in you main.rs and/or lib.rs file. No need to put it in the other files.
Perhaps it is related to this bug.

How can I use shared logic from different files?

Having shared logic in:
// euler/shared/lib.rs
pub fn foo() {
println!("shared::foo()");
}
How can I use it from different files:
// euler/001/main.rs
use super::shared; // error: unresolved import `super::shared`
fn main() {
shared::foo(); // how to access it?
}
// euler/002/main.rs
use super::shared; // error: unresolved import `super::shared`
fn main() {
shared::foo(); // how to access it?
}
mdup's answer is correct, but I'd encourage you to use Cargo, Rust's package manager. It will do two very important things for you here:
Set up the correct command line arguments to rustc.
Automatically rebuild the dependent libraries when they change.
Use cargo new shared and cargo new --bin euler-001 to generate the right directory structure. Move your shared code to shared/src/lib.rs and your binaries to euler-001/src/main.rs:
.
├── euler-001
│   ├── Cargo.toml
│   └── src
│   └── main.rs
└── shared
├── Cargo.toml
└── src
└── lib.rs
Then, edit euler-001/Cargo.toml and add the dependencies section:
[dependencies.shared]
path = "../shared"
And tweak your main.rs to know about the crate:
extern crate shared;
fn main() {
shared::foo();
}
Now, you can simply type cargo run in the euler-001 directory:
$ cargo run
Compiling shared v0.1.0 (file:///private/tmp/play/euler-001)
Compiling euler-001 v0.1.0 (file:///private/tmp/play/euler-001)
Running `target/debug/euler-001`
shared::foo()
Note that you don't have to remember command line arguments and things are compiled for you! Having a built-in package manager is great!
One solution is to create a library out of the shared code. This will allow you to use an extern crate declaration.
// euler/shared/shared.rs
pub fn foo() {
println!("shared::foo()");
}
To compile the lib:
$ cd euler/shared
$ rustc --crate-type=lib shared.rs
$ ls -l libshared.rlib
-rw-r--r-- 1 mdup wheel 6758 May 17 14:38 libshared.rlib
Here is how you use it in "client" code:
// euler/001/main.rs
extern crate shared;
fn main() {
shared::foo();
}
The compile the client:
$ cd euler/001
$ rustc -L ../shared main.rs
$ ls -l main
-rwxr-xr-x 1 mdup wheel 291420 May 17 14:42 main
$ ./main
shared::foo()
More info in Rust By Example, section "Crates", pages "Library" and "extern crate".

Resources