![](/static/253f0d9b/assets/icons/icon-96x96.png)
![](https://programming.dev/pictrs/image/1f7e5534-88d3-4d6f-bc57-7cda9553890f.webp)
- Don’t use
"*"
dep version requirements. - Add
Cargo.lock
to version control. - Why read to string if you’re going to base64-encode and use
Vec<u8>
later anyway?
"*"
dep version requirements.Cargo.lock
to version control.Vec<u8>
later anyway?Here is an originally random list (using cargo tree --prefix=depth
) with some very loose logical grouping. Wide-scoped and well-known crates removed (some remaining are probably still known by most).
mime data-encoding percent-encoding textwrap unescape unicode-width scraper
arrayvec bimap bstr enum-iterator os_str_bytes pretty_assertions paste
clap_complete console indicatif shlex
lz4_flex mpeg2ts roxmltree speedy
aes base64 cbc sha1 sha2 rsa
reverse_geocoder trust-dns-resolver
signal-hook signal-hook-tokio
hex regex
blocking
fs2
semver
snmalloc-rs
My quick notes which are tailored to beginners:
Option::ok_or_else()
and Result::map_err()
instead of let .. else
.let .. else
didn’t always exist. And you might find that some old timers are slightly triggered by it.Option
s as iterators (yes Option
s are iterators).?
operator and the Try
traitlet headers: HashMap = header_pairs
.iter()
.map(|line| line.split_once(":").unwrap())
.map(|(k, v)| (k.trim().to_string(), v.trim().to_string()))
.collect();
(Borken sanitization will probably butcher this code, good thing the problem will be gone in Lemmy 0.19)
Three tips here:
headers
will be returned as a struct field, the type of which is already known.collect()
itself. That may prove useful in other scenarios.Result
/Option
if the iterator items are Result
s/Option
s. So that .unwrap()
is not an ergonomic necessity 😉.into()
or .to_owned()
for &str => String
conversions.
http
crate is the compatibility layer used HTTP rust implementations. Check it out and maybe incorporate it into your
experimental/educational code.Alright, I will stop myself here.
Broken input sanitization probably.
Issue will thankfully no longer exist in the next lemmy release.
I do, however, hold to the fact that any sudo implementation will be more complicated than doas. Sudo, as a project, has more options and usecases than doas so it also has more posibilities for bugs or misconfiguration for the user.
Fair.
I’m unable to tell what codebase your are refering to with you’re grep arguments, sorry.
sudo-rs
Opendoas has a significantly smaller codebase. It only has 4397 lines of code compared to Sudo-rs’s staggering 35990 lines.
Hmm.
% tokei src | rg ' (Language|Total)'
Language Files Lines Code Comments Blanks
Total 76 16243 13468 682 2093
% tokei src test-framework | rg ' (Language|Total)'
Language Files Lines Code Comments Blanks
Total 196 34274 27742 1072 5460
% git grep '#\[cfg(test)\]' src |wc
40 44 1387
I too love making unaware “Tests Considered Harmful” arguments based on some blind analysis.
Funnily enough, one could easily do some actually potentially useful shallow analysis, instead of a completely blind one, simply by noticing the libc
crate dependency, then running:
git grep -Enp -e libc:: --and --not -e '(libc::(c_|LOG)|\b(type|use)\b)'
Ignoring the usage in test modules, use of raw libc
appears to be more than you would think from the title. One can also argue that some of that usage would be better served by using rustix
instead of raw libc
.
Of course authors can counter with arguments why using rustix
* is not feasible or would complicate things, and would argue that the use of unsafe+libc is required for this kind of project, and it’s still reasonably limited and contained.
And a little bit more informed back-and-forth discussion can go from there.
* Searching for rustix in the sudo-rs repo returned this. So this predictably has been brought up before.
exa
(which OP’s readme says eza
is built on) supports creation times. Actual creation time (the “Birth” line in stat
output), not ctime
.
Look into Arc
, RwLock
, and Mutex
too.
Later, check out parking_lot
and co. and maybe async stuff too.
--all-features
doesn’t work with that particular crate because two of the features conflict with each other. The features list in my command is the one used for docs.rs from the crate’s Cargo.toml
.
are there any hurdles or other good reasons to not just adding this to every create?
I’m no expert. But my guess would be that many crate authors may simply not be aware of this feature. It wasn’t always there, and it’s still unstable. You would have to reach the “Unstable features” page of the rustdoc book to know about it.
Or maybe some know about it, but don’t want to use an unstable feature, or are just waiting for it to possibly automatically work without any modifications.
Of course, I would assume none of this applies to the embassy
devs. That Cargo.toml
file has a flavors
field, which is something I’ve never seen before 😉 So, I’m assuming they are way more knowledgable (and up-to-date) about the Rust ecosystem than me.
So, this is being worked on. But for now, that crate needs this line in lib.rs
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
And this line in Cargo.toml
’s [
section: ]
rustdoc-args = ["--cfg", "docsrs"]
With these changes, feature gating will be displayed in the docs.
To replicate this locally:
RUSTDOCFLAGS='--cfg docsrs' cargo doc --features=nightly,defmt,pender-callback,arch-cortex-m,executor-thread,executor-interrupt
I constantly seem to include something from the docs, only to be told by the compiler that it does not exist, and then I have to open the source for the create to figure out if it’s hidden behind a feature flag.
As others mentioned, the situation is not perfect. And you may need to check Cargo.toml
. Maybe even the source.
But as for the quoted part above, the docs should definitely indicate if a part of the API is behind a feature. Let’s take rustix
as an example.
Here is the module list:
Here is the view from inside a module:
Here is the view from a function page:
This is also true for platform support. Take this extension trait from std
:
Now, it’s true that one could be navigating to method docs in the middle of a long doc page, where those indicators at the top may be missed. But that’s a UI issue. And it could be argued that repeating those indicators over and over would introduce too much clutter.
Note: the ᐸᐳ characters used below are Canadian Aboriginal syllabics because Lemmy devs haven’t fixed broken input sanitization yet.
Well, getters are not an official concept in Rust. You can do whatever works best in your case.
Just worth pointing out that a method with a return value of OptionᐸVecᐸStringᐳᐳ
wouldn’t be really a getter, as you must be constructing values, or moving ownership, or cloning. None of these actions conceptually belong to a getter.
Also, you should be clear on the what the Option
abstraction means. Does it mean the vector is empty? Does it mean the vector does not exist or some sort of null (FFI ore serialization contexts)? And make sure the code does what you expect it to do.
Note: the ᐸᐳ
characters used below are Canadian Aboriginal syllabics because Lemmy devs haven’t fixed broken input sanitization yet.
A vec and a string are basically the same thing (a series of bytes)
Everything is a series of bytes! I thought you were going to mention that both are fat pointers. But that “series of bytes” description is quite weird.
This makes handling it much easier because you can still iterate over it
This is not a valid consideration/objection, as Option
s are iterable and you can flatten them:
fn main() {
let v = vec![1,2,3];
for n in Some(&v).into_iter().flatten() {
eprintln!("{n}");
}
for n in None::ᐸ&Vecᐸi32ᐳᐳ.into_iter().flatten() {
eprintln!("{n}");
}
}
This might involve the compiler making an allocation of an empty array but most of them (gcc, ghc) will now what you are doing and optimize the null check on the empty array to a bool check
This paragraph appears to be out of place in the context of a Rust discussion.
I will use the Rust Book first.
Good choice. Follow it with this Little Book of Rust Macros. And don’t verge into the unsafe
stuff early, and don’t verge into it later unless it’s really necessary.
Because the audiophile is broke, and will have to listen to some music on a lowly device, but the craving for some placebo is still there.
EDIT: btw, the bitrate is missing a k
in your command 😉
Regarding
Cargo.lock
, the recommendation always was to include it in version control for application/binary crates, but not library ones. But tendencies changed over time to include it even for libraries. If arust-toolchain
file is tracked by version control, and is pinned to a specific stable release, thenCargo.lock
should definitely be tracked too [1][2].It’s strictly more information tracked, so there is no logical reason not to include it. There was this concern about people not being aware of
--locked
not being the default behaviour ofcargo install
, giving a false sense of security/reliability/reproducibility. But “false sense” is never a good technical argument in my book.Anyway, your crate is an application/binary one. And if you were to not change the
"*"
dependency version requirement, then it is almost guaranteed that building your crate will break in the future without trackingCargo.lock
;)