Starting Rust notes
I started learning Rust (again). Right now, I'm translating a bunch of my astronomy and astrodynamics code (in a mix of C++, Go, and Forth). I do want to start working on a delay-tolerant networking package too, it's been a long-standing interest.
Library organization
First, the tree will look something like this:
astro-rs/
├── Cargo.toml
├── LICENSE
├── README.md
├── src/
│ ├── lib.rs
│ ├── dms.rs
│ ├── dts.rs
│ └── fpm.rs
Then, lib.rs will look something like
//! astro is a collection of software for doing astronomy
//! and astrodynamics.
pub mod dts;
pub mod dms;
pub mod fpm;
- The pub mod lines tell Rust to include these modules and make them accessible to users of your library.
- Library-level code can be added here if needed (e.g., common traits or enums).
Then, dms.rs might look like
//! date-time systems.
use std::fmt;
#[derive (Debug, Clone, Copy)]
pub struct Time {
pub hour: i32,
pub minute: i32,
pub second: f64,
}
pub const MIDNIGHT: Time = Time{hour: 0, minute: 0, second: 0.0};
pub const NOON: Time = Time{hour: 12, minute: 0, second: 0.0};
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:02}:{:02}:{:06.3}",
self.hour, self.minute, self.second)
}
}
impl Time {
pub fn new(h: i32, m: i32, s: f64) -> Time {
Time{
hour: h,
minute: m,
second: s,
}
}
pub fn frac(&self) -> f64 {
(self.hour as f64 +
self.minute as f64 / 60.0 +
self.second / 3600.0) / 24.0
}
pub fn julian(&self) -> f64 {
(self.frac() + 0.5) % 1.0
}
// more code follows
}
Other code can use this with
use astro::dts;
println!("{}", dts::Noon);
Testing this is done by putting tests at the end of the file:
// at EOF in dts.rs
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_time_frac() {
assert!(NOON.frac() == 0.5,
"noon should be halfway through the day");
assert!(MIDNIGHT.frac() == 0.0,
"midnight should be the start of the day");
}
#[test]
fn test_time_julian() {
assert!(MIDNIGHT.julian() == 0.5,
"midnight should be halfway through the Julian day");
assert!(NOON.julian() == 0.0,
"noon should be the start of the Julian day");
}
}
To expand this out, for example if dts expands, you can break it
out into a subdirectory. Now you have src/dts/mod.rs, keeping
pub mod dts in the top lib.rs.
Various floating point options
A bunch of small builtins:
absfloor→FIXEDfractmin
etc.
Cargo registry
gitea supports a private Cargo
registry. In an effort to avoid interacting with the Rust community as
much as possible, I've decided to implement as much of what I need as
I can. All it took for me was enabling the registry in gitea, and
creating ~/.cargo/config.toml with
[registry]
default = "gitea"
[registries.gitea]
index = "sparse+https://git.example.com/api/packages/owner/cargo/" # Sparse index
token = "Bearer REDACTED"
The process of learning
I've picked up a couple of Rust books (and a course):
% tree -d Rust
Rust
├── Code Like a Pro in Rust
├── Idiomatic Rust
├── Refactoring to Rust
├── Rust in Action
└── Rust in Motion
What actually got me started was porting some of my existing code, and having a project I want to work on, then sitting down and just working on it.
Going forward
I have to start building some real things, not just math toys next. Maybe I'll build a CAS or KV store, or just dive right into RFC 5050.
Addendum
In addition to a Cargo registry, I also wanted Rust docs available too. While looking around for how to do this, I found kellnr. It took me a some effort to get it working; I found it easiest to install the Debian server version rather than Docker. I ran into a couple issues that were interesting to debug.
config.json not found
In one place, I had the registry path as /api/v1/cratesio/ instead
of /api/v1/crates/ (I think I found some stale documentation
somewhere). Well, turns out you can't find config.json if you're
pointed at the wrong place. What threw me off at first was that the
Gitea registry has an admin option to initialize the cargo.json, and I
did that before publishing. Not sure if causation or correlation, but
I couldn't find anything like that in Kellnr. Anyways, my cargo config
looks something like this now:
[registry]
default = "kellnr"
[registries.kellnr]
index = "sparse+https://cargo.wntrmute.dev/api/v1/crates/"
credential-provider = ["cargo:token"]
token = "REDACTED"
[registries.gitea]
index = "sparse+https://git.wntrmute.dev/api/packages/wntrmute/cargo/" # Sparse index
# index = "https://git.wntrmute.dev/wntrmute/_cargo-index.git" # Git
token = "Bearer REDACTED"
docs not building
The doc problem was trickier, and essentially came down to the server user not having cargo in the path. Docs would be queued for building, they would show up in the data directory's queued directory, but never actually make it. I had the logging turned all the way up, including the web framework—which drowned out the log messages I needed to see.
Finally, it works
Now I have a cargo registry and rustdocs site that requires authentication to view and download packages.