Can I use a module that is located inside the directory that is located next to the executable file?
--src
|
|--main.rs
|
|--dir
| |--my_file.rs
I don't really want to start a new crate, but I can't write something like:
mod my_file;
or
mod dir::my_file;
If you know Python, Rust's modules are somewhat similar to Python's packages in that the directories are not intrinsically meaningful, a "signal" file is necessary to make them so.
For historical reaons, in rust there are two options for that signal files:
a mod.rs file nested inside the directory
or a dir.rs file next to the directory
Both work and their behaviour is equivalent, so it mostly comes down to how you come at it. mod.rs has the advantage that it makes the entire module into a unit you can move around, while dir.rs provides a clearer descriptor and makes it easier to start with a single file then split things out later on.
So in the above what you need is to add a dir.rs or dir/mod.rs which contains:
mod my_file;
and main.rs should contain the stanza
mod dir;
and things should work out, dir and dir::my_file now become available (in sibling modules you may need to use them).
In addition, it is not clear to me if I create a crate, I should always take out all open methods in lib.rs ?
I don't understand what you're talking about, what is an "open method"?
[...] what is the advantage of crates in general
In Rust a crate is a unit of:
visibility, a crate is a single thing which impacts visibility (pub(crate) and a few other things) and orphan rules (you can only implement a trait on a type if either was defined in the current crate), a crate can also have circular dependencies internally (not that it's necessarily a good thing though it's often convenient) while intra-crate dependencies must be a DAG
code distribution, a crate is a unit you can upload to cargo (or an equivalent private repository) and depend on
code generation, different crates can always be built concurrently (as long as they don't depend on one another, obviously), intra-crate concurrency is a lot less reliable
Related
I like naming my folders and files by the kebab-case convention.
Recently, I've been learning rust and learned a bit about modules. In one of the examples, I have a file named: distinct-powers.rs. Whenever I do mod distinct-powers to put the code in scope, I obviously get a syntax error since Rust cannot handle kebab-case. The error is: Syntax Error: expected BANGrust-analyzer which I don't think is informing us of anything since it thinks the error is completely different.
Is there any way to circumvent this limitation of Rust?
If you really want to, you can place modules’ code at arbitrary filenames:
#[path = "distinct-powers.rs"]
mod distinct_powers;
But please don’t — one of the great things about Rust is that there is a single standard for project layout, which makes it easy to dive into other people’s code. Every customization is a disruption to someone finding the code they’re looking for.
There are a couple of locations where hyphens are allowed, that is, a kebab-case name can be used in a Rust package. They all have to do with Cargo, the build system, rather than the Rust language itself.
The name of the package itself (as specified in Cargo.toml) can be kebab-case. If the package is a library, Cargo will automatically translate this to snake_case for the library's crate name (which is how you refer to it within Rust code in dependents). This is quite commonly done.
For example, in this docs URL, https://docs.rs/ordered-float/latest/ordered_float/, you can see that the package name is ordered-float and the crate name (which could be overridden but was not) is derived from that as ordered_float.
The name of a binary, example, or test target can contain hyphens. This means that the binaries built in target/ can have kebab-case names — cargo run --bin distinct-powers is valid.
These names can all be used by Cargo target auto-discovery and thus are not considered non-standard layout.
kebab-enthusiast/
Cargo.toml
src/
lib.rs
snake_module.rs
bin/
kebab-binary.rs
examples/
kebab-example.rs
tests/
kebab-test.rs
I have a rust project with main.rs, some other modules in the main.rs level and several submodules underneath. I use the anyhow crate in almost all of them.
Is there a clean way to declare use anyhow; only once (probably in main.rs?) without the need to redclare its usage in every single mod/file?
Note that anyhow itself should be accessible without use (as of Edition 2018), because this is a crate name. If you mean to import something within that crate for your entire project (use anyhow::Context;), then no, there is no standard¹ way to have that.
Each module has its own scope for such symbols, which are imported via use. The one exception is in the standard preludes, defined by the compiler itself. These are what enable you to use Copy, Result, and others without having to import them explicitly. However, this is naturally out of your control.
There is also a common pattern for some libraries to provide their own prelude: a module that re-exports symbols that are likely to be useful. anyhow does not provide one at the time of writing.
See also:
What is the prelude?
¹Almost anything becomes possible with macros or another preprocessor, but it is hardly a good tradeoff for this case.
Rust doesn't support global imports.
However, for global macro imports, there is a way, as explained here. That won't solve your problem completely, but it will at least allow you to avoid importing the macros.
In your main.rs you can add this:
#[macro_use]
extern crate anyhow;
And then you can use macros like bail! and ensure! all around your project, without the need to explicitly import them.
These two traits (std::ops::Add, core::ops::Add) provide the same functionality, and they both use the same example (both utilize std::ops::Add). Their set of implementors differ somewhat.
Should one default to using std::ops::Add? Why do both, as opposed to one, of them exist?
There aren't two traits. There is one trait which is exported under several interchangeable names. This is far from unique. Virtually everything in core is also exported from std, and virtually always under exactly the same path (i.e., you can just replace the "core" prefix with "std").
As for which one you should use: If you have a reason to not link to the standard library (#![no_std]), then the std::* one isn't available so obviously you use core::*. If on the other hand you do use the standard library, you should use the std::* re-export. It is more customary and requires less typing.
They're in fact exactly the same, despite the set of implementors being listed as slightly different.
The core library is designed for bare-metal/low-level tasks, and is thus more barebones than what std can provide by assuming an operating system exists. However, people using std will want the stuff that's in core too (e.g. Add or Option or whatever), and so to avoid having to load both std and core, std reexports everything from core, via pub use. That is, std provides aliases/import paths for the things in core.
There are some unfortunate error messages where the compiler points to the original source of an item, not the reexport, which might not be in a crate you're extern crateing.
I have a function file_to_bytes() in lib.rs which I need to call from both lib.rs and runtime.rs (and tests.rs, but it's OK from there).
I also have a file klass_parser.rs that contains a struct OtKlassParser that needs to be used in both lib.rs and runtime.rs.
I can't seem to arrange the mod and use declarations correctly - what's the canonical way to do this, and what section of the documentation covers this case?
Answering my own question as this is not covered in the docs.
There appears to be no easy way to do this directly. Instead, the dependency graph that is described in the question is an indication that actually the project needs more structure and to be composed of multiple crates.
In this case, a workable structure looks something like the following:
klass_parser.rs should be its own crate
Majority of lib.rs should move into a new crate (called something like vm)
runtime.rs should become a third separate crate
Remainder of lib.rs should move into main.rs
lib.rs should disappear completely
I am trying to create a library and I want to include some binary (or text) files in it that will have data which will be parsed at runtime.
My intention is to have control over these files, update them constantly and change the version of the library in each update.
Is this possible via cargo? If so, how can I access these files from my library?
A workaround I thought of is to include some .rs files with structs and/or constants like &str which will store the data but I find it kind of ugly.
EDIT:
I have changed the accepted answer to the one that fits more my case, however take a look at Shepmaster's answer as this can be more suitable in your case.
Disclaimer: I mentioned it in a comment, but let me re-iterate here, as it gives me more space to elaborate.
As Shepmaster said, it is possible to include text or binary verbatim in a Rust library/executable using the include_bytes! and include_str! macros.
In your case, however, I would avoid it. By deferring the parsing of the content to run-time:
you allow building a flawed artifact.
you incur (more) run-time overhead (parsing time).
you incur (more) space overhead (parsing code).
Rust acknowledges this issue, and offers multiple mechanisms for code generation destined to overcome those limitations:
macros: if the logic can be encoded into a macro, then it can be included in a source file directly
plugins: powered up macros, which can encode any arbitrary logic and generate elaborate code (see regex!)
build.rs: an independent "Rust script" running ahead of the compilation proper whose role is to generate .rs files
In your case, the build.rs script sounds like a good fit:
by moving the parsing code there, you deliver a lighter artifact
by parsing ahead of time, you deliver a faster artifact
by parsing ahead of time, you deliver a correct artifact
The result of your parsing can be encoded in different ways, from functions to statics (possibly lazy_static!), as build.rs can generate any valid Rust code.
You can see how to use build.rs in the Cargo Documentation; you'll find there how to integrate it with Cargo and how to create files (and more).
The include_bytes! macro seems close to what you want. It only gives you a reference to a byte array though, so you'd have to do any parsing starting from that:
static HOST_FILE: &'static [u8] = include_bytes!("/etc/hosts");
fn main() {
let host_str = std::str::from_utf8(HOST_FILE).unwrap();
println!("Hosts are:\n{}", &host_str[..42]);
}
If you have UTF-8 content, you can use include_str!, as pointed out by Benjamin Lindley:
static HOST_FILE: &'static str = include_str!("/etc/hosts");
fn main() {
println!("Hosts are:\n{}", &HOST_FILE[..42]);
}