2

Good Day fellow earthlings.

I'm trying to do what I think is conceptually simple with Rust but i seem to be fighting the compiler and would like some assistance.

I have a really simple, small project that has effectively 3 files

├── cargo.toml
├── src
     ├── main.rs
     ├── api.rs
     └── state.rs
    

src/state.rs is basically a collection of structs that represent a system state. ie

#[derive(Debug,Serialize)]
pub struct State {
    pub field1: String,
    pub field2: String,
}

This is where things derail a bit.

src/api.rs needs to use the struct(s) defined in src/state.rs

If i try mod state.rs at the top of src/api.rs, the compiler looks for the module in /src/api/state.rs. I can make it look for the module in the correct file by doing:

#[path = "system.rs"]
mod system;

use system::*;
use rocket::State;
use rocket_contrib::json::Json;
use serde_json::Value;
use std::sync::{Arc,RwLock};

#[get("/")]
pub fn get_all(state: State<Arc<RwLock<system::State>>>) -> Json<Value> {
    return Json(json!(&*state.read().unwrap()));
}

pub fn start_api(state: Arc<RwLock<system::State>>) {
    rocket::ignite()
        .manage(state)
        .mount("/", routes![get_all]).launch();
}

And in src/main.rs, the state is built then passed into the start_api() function.

However, the compiler stops this by stating that the types do not match. It says...

mismatched types

expected struct `api::system::State`, found struct `system::State`

note: expected struct `std::sync::Arc<std::sync::RwLock<api::system::State>>`
         found struct `std::sync::Arc<std::sync::RwLock<system::State>>`rustc(E0308)

The state module is brought into main.rs the same as it was in api.rs

#![feature(decl_macro)]

...
extern crate rocket;
extern crate rocket_contrib;

mod system;
mod api;

use std::sync::{Arc,RwLock};
use std::thread;
...

fn main() {
    // Initialise state
    start_api(api_state); // << Type Error Here
}

Where have I derailed? It all works when everything is in the same file. I'm trying to split things out as main.rs was approaching a few hundred lines.

Cheers~!

John Geddes
  • 147
  • 1
  • 1
  • 12
  • 2
    so, you are declaring the same `system` mod from different places (api, and main), overriding in api to get the correct path. You shouldn't declare it several times. The usual way is to just declare `mod system` in your main, and everything else will `use crate::system::State;`. Alternatively, instead of main, create a lib.rs to host those mod declarations. But trying to declare several tinmes, even if you override the path to find the file, will lead to different logical paths, therefore will be interpreted as different types altogether. – LotB Sep 03 '20 at 07:09
  • also, duplicate of [how to include a module from another file from the same-project](https://stackoverflow.com/questions/26388861/how-to-include-a-module-from-another-file-from-the-same-project/) – LotB Sep 03 '20 at 07:20
  • @LotB If i remove the `mod state` from `api.rs`, i get: ``` failed to resolve: use of undeclared type or module `state` use of undeclared type or module `state`rustc(E0433) api.rs(10, 40): use of undeclared type or module `state` ``` Edit: The part i was missing was the `use crate::system::State;`. I wasn't aware that something like that was possible. Thanks. – John Geddes Sep 03 '20 at 07:34
  • Also, I don't think this question is a duplicate of https://stackoverflow.com/questions/26388861/how-to-include-a-module-from-another-file-from-the-same-project/ I saw this before and it didn't help me. It doesn't touch upon `use crate::system::`. – John Geddes Sep 03 '20 at 07:45

1 Answers1

2

As stated by LotB, instead of

#[path = "system.rs"]
mod system;

use rocket::State;
...
#[get("/")]
pub fn get_all(state: State<Arc<RwLock<system::State>>>) -> Json<Value> {
    return Json(json!(&*state.read().unwrap()));
}

pub fn start_api(state: Arc<RwLock<system::State>>) {
    rocket::ignite()
        .manage(state)
        .mount("/", routes![get_all]).launch();
}

I needed to replace the mod state with use crate::system::State;

Ending up with:

use crate::system::State;

use rocket::State;
use rocket_contrib::json::Json;
use serde_json::Value;
use std::sync::{Arc,RwLock};

#[get("/")]
pub fn get_all(state: State<Arc<RwLock<State>>>) -> Json<Value> {
    return Json(json!(&*state.read().unwrap()));
}

pub fn start_api(state: Arc<RwLock<State>>) {
    rocket::ignite()
        .manage(state)
        .mount("/", routes![get_all]).launch();
}

Thanks LotB.

John Geddes
  • 147
  • 1
  • 1
  • 12
  • It helps to stick to default directory layout rather than overriding your `mod` declarations with `#[path]` annotations; this way your `state.rs` would be within `system/` which helps mentally by keeping the namespace aligned with the filesystem. – eggyal Sep 03 '20 at 07:59