Module resolution - rust

I have the following code in src/
main.rs
a.rs
b.rs
Here's the code:
main.rs
mod a;
mod b;
use crate::a::Summary;
use crate::b::Person;
fn main() {
let p = Person{ first: "John".to_string(), last: "Doe".to_string() } ;
sum(p) ;
}
fn sum(summary: impl Summary) {
println!("{}", summary.summarize()) ;
}
a.rs
pub trait Summary {
fn summarize(&self) -> String ;
}
b.rs
use crate::Summary;
pub struct Person {
pub first: String,
pub last: String,
}
impl Summary for Person {
fn summarize(&self) -> String {
format!("{}, {}.", self.last, self.first)
}
}
What I don't understand is how does "use crate::Summary;" not cause a problem in b.rs? It should be "use crate::a::Summary;" or even "use super::a::Summary;", but for some reason use crate::Summary works. Is there some kind of funky search logic being applied here under the hood?

Items defined without a visibility specifier are available to the module that they're defined in and all of its sub-modules.
Since a and b are submodules of the crate root module, they can access the Summary object that was imported via a use declaration in main into the crate root module.

Related

Rust tells me that an import is unused, and then in the very same breath tells me that I should make that import

Here's the code:
use crate::rooms::room::RoomInterface;
pub mod dogroom {
pub struct R;
impl RoomInterface for R {
}
}
Here's /rooms/mod.rs:
pub mod room {
// Irrelevant stuff
pub trait RoomInterface {
// stuff
}
// stuff
}
Here's what it tells me:
I find it quite arcane that I import the very same thing it wants me to import, and yet it doesn't work.
I've tried pretty much all the permutations of the use keyword, and I can't make it work. What's going on?
uses are scoped to the module that imports them, not the file they are in.
Move the import into the dogroom module:
pub mod dogroom {
use crate::rooms::room::RoomInterface;
pub struct R;
impl RoomInterface for R {
}
}
Alternatively, you might want the dogroom module to reuse everything from the parent module:
use crate::rooms::room::RoomInterface;
pub mod dogroom {
use super::*;
pub struct R;
impl RoomInterface for R {
}
}

How do I access "private" struct's field from other files in Rust?

As advised by my lead programmer, who's not knowledgeable in Rust but knows a lot about OO languages like Java, C#, and such, I should separate the functions and associated methods of a particular "class," in Rust it's more or less a struct, from its model or definition to another file. But I had trouble accessing a struct's field/data member from another file. It feels icky to just attach pub before every struct field's name.
// some_model.rs
// This feels icky
pub struct SomeStruct {
pub name: String,
pub id: u32,
}
Just so other files could access the aforementioned struct above
// some_adapter.rs
impl SomeStruct {
pub fn get_id(&self) -> u32 {
self.id
}
pub fn get_name(&self) -> &'static str {
self.name
}
pub fn new(name: &'static str, id: u32) -> Self {
SomeModel {
name,
id
}
}
}
So how does one access such fields from a different file?
Warning
Based from the comments I've received, I'll put this at the top
THIS IS AN UN-RUSTY SOLUTION
If your lead programmer says you should do the following, or do what's indicate in the question, protest and show them this post.
Proposed Answer
I've scoured the net for some answers, every link is a piece of the whole puzzle. See the references below the post. And eventually, I think I found an apt solution, without using the much warned include! macro.
I used the following syntax profusely:
Syntax
Visibility :
pub
| pub ( crate )
| pub ( self )
| pub ( super )
| pub ( in SimplePath )
At first glance it was confusing for me, and for the others like me who might be perplexed as well, I had posted my findings with a sample code.
The directory, using broot
src
├──dal
│ ├──adapter
│ │ └──some_adapter.rs
│ ├──adapter.rs
│ ├──model
│ │ └──some_model.rs
│ └──model.rs
├──dal.rs
├──lib.rs
└──main.rs
I intended to include numerous sub-directories as well, as I reckoned it might add incidental information to those likely having the same knowledge as I in Rust.
I executed cargo new visibility_sample
dal/model/some_model.rs
// dal/model/some_model.rs
pub struct SomeModel {
// take note of the following syntax
pub(in super::super) name: &'static str,
pub(in super::super) id: u32,
}
dal/adapter/some_adapter.rs
// dal/adapter/some_adapter.rs
use super::super::model::some_model::SomeModel;
impl SomeModel {
pub fn get_id(&self) -> u32 {
self.id
}
pub fn get_name(&self) -> &'static str {
self.name
}
pub fn new(name: &'static str, id: u32) -> Self {
SomeModel {
name,
id
}
}
}
dal/model.rs
// dal/model.rs
pub mod some_model;
dal/adapter.rs
// dal/adapter.rs
pub mod some_adapter;
dal.rs
// dal.rs
pub mod model;
pub mod adapter;
lib.rs
// lib.rs
pub mod dal;
And finally main.rs
// main.rs
use visibility_sample::dal::model::some_model::SomeModel;
fn main() {
let object = SomeModel::new("Mike", 3);
println!("name: {}, id: {}", object.get_name(), object.get_id());
}
running cargo run
Compiling visibility_sample v0.1.0 (C:\Users\miked\git\visibility_sample)
Finished dev [unoptimized + debuginfo] target(s) in 1.40s
Running `target\debug\visibility_sample.exe`
name: Mike, id: 3
but if main.rs has the following code:
// main.rs
use visibility_sample::dal::model::some_model::SomeModel;
fn main() {
let object = SomeModel::new("Mike", 3);
println!("name: {}, id: {}", object.name, object.id);
}
Powershell prints out Rust compiler's beautiful and informative error printing:
error[E0616]: field `name` of struct `SomeModel` is private
--> src\main.rs:5:41
|
5 | println!("name: {}, id: {}", object.name, object.id);
| ^^^^ private field
error[E0616]: field `id` of struct `SomeModel` is private
--> src\main.rs:5:54
|
5 | println!("name: {}, id: {}", object.name, object.id);
| ^^ private field
error: aborting due to 2 previous errors
I placed "" quotation marks in the title for "private" because I'm not certain whether that word is still applicable with the term I'm trying to convey with my posted solution.
References
https://doc.rust-lang.org/reference/visibility-and-privacy.html
https://users.rust-lang.org/t/implement-private-struct-in-different-files/29407
Move struct into a separate file without splitting into a separate module?
Proper way to use rust structs from other mods
P.S.
Perhaps to those gifted and keen, they can easily understand the solution with a few or even a single link in my references on their own, but to someone like me, I have to read these links a whole lot and repeatedly get back to it for tinkering on my own.

Rust Submodule Behavior with Wildcard Use Declarations

I was trying to understand how (sub)module imports work when using wildcard paths. The simplest demonstration I could come up with is as follows, where two modules, or perhaps two crates, share the same module structure.
pub mod primary {
pub mod a {
pub mod b {
pub struct A(pub i32);
}
}
}
pub mod import {
pub use crate::primary::*;
// Compiles and executes fine with this commented out, but fails with
// "error[E0433]: failed to resolve: could not find `b` in `a`"
// otherwise. The error refers to the usage in the assert_eq macro
// pub mod a {}
}
fn main() {
assert_eq!(import::a::b::A(42).0, 42);
}
My general thought, was, since the first case, where the pub mod a {} is commented out works, the wildcard should expand all submodules the wildcard picks up into submodules in the path in which it is expanding. Is this not the case? If so, what's the appropriate way to think about?
The Use declarations doesn't have a lot of detail on this.
use with a * imports all the names, except for those that would conflict with names that already exist in the current module.
Compare:
pub mod primary {
pub fn f() {
println!("p::f");
}
}
pub mod import {
pub use crate::primary::*;
}
fn main() {
import::f();
}
which prints p::f to
pub mod primary {
pub fn f() {
println!("p::f");
}
}
pub mod import {
pub use crate::primary::*;
pub fn f() {
println!("import::f");
}
}
fn main() {
import::f();
}
which prints import::f.
This might seem obvious for functions and constants (it would otherwise make * very limited, making it impossible for upstream libraries to add any item without risking to break downstream users), but it might seem more confusing for modules.
You have to remember though that you can't define a module multiple times (ie. "reopen" a module). The following is illegal:
pub mod primary {
pub mod a {}
pub mod a {}
}
and fails with
error[E0428]: the name `a` is defined multiple times
--> src/lib.rs:3:5
|
2 | pub mod a {}
| --------- previous definition of the module `a` here
3 | pub mod a {}
| ^^^^^^^^^ `a` redefined here
|
= note: `a` must be defined only once in the type namespace of this module
You can solve this particular case by adding one more level:
pub mod primary {
pub mod a {
pub mod b {
pub struct A(pub i32);
}
}
}
pub mod import {
pub mod a {
pub use crate::primary::a::*;
}
}
fn main() {
assert_eq!(import::a::b::A(42).0, 42);
}
A wildcard import creates aliases to all items on the top level of the module.
In your example, since primary contains only one item, a, the wildcard import creates an alias import::a, which refers to the module primary::a.
Whenever conflicts arise, explicitly named items are given higher precedence than items that were imported via a wildcard. Effectively, you can shadow a wildcard import by declaring a new item or by importing it by name from another module.
Each mod declaration declares a different module. There is no implicit merging of items in modules that happen to have the same name or alias.

When if ever do pub and pub(super) have different semantics?

Rust has support for both pub and pub(super). pub makes it so the parent module can access an item... and pub(super) seems to also do exactly the same thing. I've tried playing with the example below, and swapping pub and pub(super) seems to have no effect:
#![allow(dead_code)]
mod outer {
pub(super) fn outer_foo() { inner::inner_foo(); }
mod inner {
pub(super) fn inner_foo() { println!("hello world!"); }
}
}
fn top_level_foo() { outer::outer_foo(); }
Why would you ever use one over the other?
Playground link.
In your example, if you change your inner module to be public, then the difference would become clear.
For example, this works because outer::inner::inner_foo is visible from the main module:
#![allow(dead_code)]
mod outer {
pub(super) fn outer_foo() { inner::inner_foo(); }
pub mod inner {
pub fn inner_foo() { println!("hello world!"); }
}
}
fn top_level_foo() { outer::outer_foo(); }
fn main() {
outer::inner::inner_foo();
}
If you kept inner_foo as pub(super) it would've been only visible from the outer module (because super refers to the super-module, outer in the case of something inside inner), hence the above code wouldn't compile and you would see this error:
|
13 | outer::inner::inner_foo();
| ^^^^^^^^^ private function
|
note: the function `inner_foo` is defined here
Notice that pub can also take crate as an argument, making the function public within the crate itself, but not to other crates.

Include main.rs in other module

I'm new to rust. I know, for calling a module in same folder I need to write mod <module name> for other folder mod <module name>{ include!("path to module") }. I want to include main.rs in extra.rs, present in same folder, so that I can use Summary trait for structure feed in extra.rs. I get error recursion limit reached while expanding the macro 'include'.
How I can include main.rs in extra.rs? Is there a better way to write the same code?
error
error: recursion limit reached while expanding the macro `include`
--> src/extra.rs:3:5
|
3 | include!("main.rs");
| ^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate
error: aborting due to previous error
error: could not compile `office_manager`.
main.rs
mod extra;
pub trait Summary {
fn print_summry(&self) -> String;
}
pub struct Tweet {
name: String,
message: String
}
impl Summary for Tweet {
fn print_summry(&self) -> String {
format!("{}: {}",self.name,self.message)
}
}
fn main() {
let t = extra::Feed {
name: String::from("Hanuman"),
message: String::from("Jai sri Ram")
};
println!("{}",t.print_summry());
}
extra.rs
mod main {
include!("main.rs");
}
pub struct Feed {
pub name: String,
pub message: String
}
impl Summary for Feed {
fn print_summry(&self) -> String {
format!("{}: {}",self.name,self.message)
}
}
Elements of parent module can be accessed with help of super. Therefore adding use super::*; on top or using super::Summary both works. But it is better to use super::Summary as it don't include everything of main.rs.

Resources