TIL features can't be used like this and I think it's nuking my incremental build times

50 points Tiflotin 28 comments

I'm making a mmorpg that has several shared types between client and server. I have 3 crates, client, server, shared.

Item, is one of those types for example. Item has 2 fields `id` and `amount`. I want to change the type of the field based off what crate is using the shared crate. Eg the client, the `id` field should be of type u16. But in the server, I want the `id` type to be a `ItemId` (enum repr u16 type for item constants). The client can't use the same type since `ItemId` wont always be up to date with the latest items in game (we can add items without releasing new client updates).

This is what I've got so far, and its fine when building the specific crate (eg client or server) but if u try to build the workspace itself, it fails.

Item.rs inside shared:

pub struct Item {
    pub id: ItemIdType,
}

#[cfg(not(feature = "server"))]
pub type ItemIdType = u16;
#[cfg(feature = "server")]
pub type ItemIdType = String;

Example use of client with u16 type:

use shared::Item;

fn main() {
    // Client project, NO server feature
    let test = Item { id: 123 };
    println!(
        "We are a u16 since we're NOT using the server feature! {:?}",
        test.id
    );
}

Example use of server with String type:

use shared::Item;

fn main() {
    // Server project, YES server feature
    let test = Item {
        id: String::from("Hello"),
    };
    println!(
        "We are a String since we ARE using the server feature! {:?}",
        test.id
    );
}

My issue is when running cargo build in the workspace, it gives an error saying client was failed to build due to incorrect item id type. But if I run cargo build inside the client directory it works fine.

error[E0308]: mismatched types
 --> client/src/main.rs:5:27
  |
5 |     let test = Item { id: 123 };
  |                           ^^^- help: try using a conversion method: `.to_string()`
  |                           |
  |                           expected `String`, found integer

I don't really understand why this isnt valid, and not quite sure how to achieve what I want without duplicating the struct inside server and client. It's got me stumped!

Small example project: https://github.com/user-attachments/files/20989722/rustanalyzer-false-positive.zip