Issue when replacing a crates dependency with a local version - rust

So I am trying to serialize a struct using bincode following these instructions, and I was able to get that to work.
But then I wanted to serialize a struct with an IpAddr enum. Since IpAddr doesn't implement the Encodable trait needed, I downloaded the rustc_serialize crate from git and implemented encodable for IpAddr myself. I then changed my Cargo.toml file to:
[dependencies]
# rustc-serialize = "0.3"
byteorder = "0.3"
bincode = "0.4"
[dependencies.rustc-serialize]
path = "src/rustc-serialize-master"
But now, the same code from the struct I was using doesn't compile saying that
rustc_serialize::serialize::Encodable is not implemented for my struct even though i have #[derive(RustcEncodable)] above the struct.
Even when I get rid of the code I added to the local version of rustc_serialize, I still get that error.
I think it might be due to something being screwed up with the way bincode and a local rustc_serialize interact, but I'm not sure.

Please review the Cargo documentation on overriding dependencies:
To specify overrides, create a .cargo/config file in some ancestor of your project's directory (common places to put it is in the root of your code directory or in your home directory).
Inside that file, put this:
paths = ["/path/to/project/rand"]
Going deeper, you are likely running into issue 22750 - two different versions of a crate interacting leads to unhelpful error messages. When you add rustc-serialize to your dependencies, you aren't replacing the old version, you are adding a new one.
In general, this is a good feature. If my project relies on crates A and B and they both rely on crate Z but with different versions, Rust can handle that just fine. The problem arises when they re-export items from those crates.

Related

Can I apply a crate attribute only to the crate itself?

I have a Rust project that needs a few binaries with TitleCaseNames. So I created source files like src/bin/MyFooBinary.rs and src/bin/MyBarBinary.rs. The compiler warns that these binary crates should have snake case names, and I want to suppress that warning.
I can add #![allow(non_snake_case)] to the crate, but that then applies to the crate's entire contents as well. Not ideal. I really only want to suppress the warning for the crate name. Is that possible?
I'd suggest to follow the usual snake_name convention for the source file and crate names. Since you need to move the binaries elsewhere during deployment or packaging anyway, you can rename them at that point.
In the nightly compiler build, you can also specify a filename that is different from the crate name in Cargo.toml:
cargo-features = ["different-binary-name"]
[package]
# ...
[[bin]]
name = "foo_bar"
filename = "FooBar"
path = "src/bin/foo_bar.rs"

Is there a problem with naming a crate containing the string ".rs"?

Could there be any future problem in naming a dependency .rs for example,
[dependencies]
gccjit.rs = { git = "https://github.com/swgillespie/gccjit.rs.git" }
In the above code, I use .rs for something which is not a Rust source code file. Is that not ideal or is it okay because it would be easier to default to the same name as the repository?
If an object is named .rs it could maybe be automatically recognized as Rust source code but in this case it is not.
Yes, there is a problem. Do not do this.
How you could have determined this for yourself
Try to use the code that you've proposed, you'll see:
$ cargo build
error: failed to parse manifest at `.../Cargo.toml`
Caused by:
could not parse input as TOML
Caused by:
expected an equals, found a period at line 9
You could have also attempted to create a package with the same name. You would have then seen:
$ cargo new 'gccjit.rs.git'
error: Invalid character `.` in crate name: `gccjit.rs.git`
use --name to override crate name
Who controls crate names
You don't get to control the name of an imported crate that way; the crate determines it and it's already picked one:
[package]
name = "gccjit"
If you want to rename an existing package on import, you have to use the package key to match the real name:
some_name = { package = "gccjit", git = "https://github.com/swgillespie/gccjit.rs.git" }
See How to idiomatically alias a crate in Rust 2018? for more.
To use a period in the name, you can seemingly use a string key (although I think this is a bug):
"gcc.jit" = { package = "gccjit", git = "https://github.com/swgillespie/gccjit.rs.git" }
However, a package name has to be a valid Rust identifier, which periods are not. If you do this, there's no way to use the package.
It's redundant anyway
More opinion based, such a name is completely pointless. You don't need to say "rs" or "rust" in the name because of course it's Rust code. If it wasn't, you couldn't use it as a dependency in the first place.
We don't call our packages "computer-source-code-awesome-tool" for the same reason — that much is implied.
Package names are different from source control
Cargo and Rust don't care what the name of your source control repository is. It's separate from the package name. While it's better to have them be somewhat similar, there's no real reason they have to be whatsoever related.
Package names are different from library names
This is a feature with a very small number of uses, but the name of your package (a.k.a. name of the crate on Crates.io) can be different from the name of your library (what is imported into the code).
Piston is the biggest "offender" of this that I know of:
[package]
name = "piston2d-graphics"
version = "0.30.0"
[lib]
name = "graphics"
Please do not use this as it's simply maddening to attempt to debug.

How to skip a library crate's examples depending on the target platform?

I have a Rust library crate which I only use on Linux, but I don't know of any reason it shouldn't work on Windows; however one of the examples is Unix-specific, so it the crate fails the build on AppVeyor.
The reason is that there's a Unix-only dependency (Termion) used by one of the examples, so when I used an AppVeyor template, it fails to build that dev-dependency.
So I made the dependency conditional:
[target.'cfg(unix)'.dev-dependencies]
termion = "1.0"
So far so good, but of course now that example fails on extern crate termion.
What I need is to just not build that example on non-Unix-like targets. I was hoping something like:
[[target.'cfg(unix)'.example]]
name = "foo"
would work, but I get:
warning: unused manifest key: target.cfg(unix).example
error: no example target named `foo`
Another promising way forward was Cargo's required-features, but as of writing it's apparently not in stable Cargo, which means that doesn't help me checking that it works on stable Rust on Windows.
The last option I can think of is to #[cfg(unix)] away most of the example's source, turning it into a stub on Windows, but I'd really like a cleaner way of doing it.
Is there some existing way of skipping an example on some unsupported targets that works with current stable Rust/Cargo?

Testing a Rust crate outside of the source package

I have created my Rust crate. It's a very trivial affair. It built fine and when tested within it's own source directory works just fine (I just included extern crate my_first_crate; in my test file).
I want to now test the crate in a totally different application.
If I add the same extern crate line to my new application, the compiler tells me that it can't find the crate. I expected this (I'd get the same in C if I told the compiler to link to a library it has no clue about!)
Do I need to copy the my_first_crate.rlib file from the source to the application target/debug folder or is there a way to tell cargo that it needs to link to the rlib file?
You need to add your crate as a dependency for your application. Add this to your application's Cargo.toml:
[dependencies]
my_first_crate = { path = "/path/to/crate" }
"/path/to/crate" is the path to the root of the crate's source (i.e. the directory that contains its Cargo.toml). You can use either a relative or an absolute path (but avoid absolute paths if you intend on publishing your code!).

Figure out code from what module is "use"d in a large rust project (servo)

I'm trying to read the code of servo. As an example, I'm looking at this code in layout_task.rs:
use url::Url;
..and I want to know which code this refers to (the answer is rust-url).
Per the Rust reference §6.1.2.2 Use declarations,
the paths contained in use items are relative to the crate root [...]
It is also possible to use self and super at the beginning of a use item to refer to the current and direct parent modules respectively.
All rules regarding accessing declared modules in use declarations apply to both module declarations and extern crate declarations.
The reference (§5 Crates and source files) does not explicitly say what a "crate root" is, but it does share that:
A crate contains a tree of nested module scopes. The top level of this tree is a module that is anonymous [...] The Rust compiler is always invoked with a single source file as input, and always produces a single output crate. The processing of that source file may result in other source files being loaded as modules.
So it seems that to find the crate root that the current file (layout_task.rs) belongs to, we need to figure out what source file rustc is invoked with when building the crate. With Cargo this is specified in Cargo.toml and defaults to src/lib.rs:
[lib]
path = "src/lib.rs"
In my case, here's Cargo.toml and the lib.rs has:
extern crate url;
pub mod layout_task;
So far so good. To find out what the extern crate refers to, we need to look at Cargo.toml again:
[dependencies.url]
version = "0.2"
The cargo docs claim that "Dependencies from crates.io are not declared with separate sections", but apparently they can be... So we look the package up on crates.io: https://crates.io/crates/url

Resources