• 0 Posts
  • 39 Comments
Joined 1 year ago
cake
Cake day: July 9th, 2023

help-circle
  • 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 a rust-toolchain file is tracked by version control, and is pinned to a specific stable release, then Cargo.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 of cargo 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 tracking Cargo.lock ;)



  • 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 hex cbc sha1 sha2 rsa
    reverse_geocoder trust-dns-resolver
    signal-hook signal-hook-tokio
    blocking
    fs2
    semver
    snmalloc-rs
    

  • My quick notes which are tailored to beginners:

    Use 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.
    • Functional style is generally preferred, as long as it doesn’t effectively become a code obfuscater, like over-using Options as iterators (yes Options are iterators).
    • Familiarize yourself with the ? operator and the Try trait

    Type inference and generic params

    let 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:

    1. You don’t need to annotate the type here because it can be inferred since headers will be returned as a struct field, the type of which is already known.
    2. In this pattern, you should know that you can provide the collected type as a generic param to collect() itself. That may prove useful in other scenarios.
    3. You should know that you can collect to a Result/Option if the iterator items are Results/Options. So that .unwrap() is not an ergonomic necessity 😉

    Minor point

    • Use .into() or .to_owned() for &str => String conversions.
      • Again, some pre-specialization old timers may get slightly triggered by it.

    make good use of the crate echo system

    • It’s important to make good use of the crate echo system, and talking to people is important in doing that correctly and efficiently.
      • This post is a good start.
      • More specifically, the 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.






  • Next Day Edit: Sorry. Forgot to use my Canadian Aboriginal syllabics again. Because apparently it’s too hard to admit HTML-sanitizing source markdown was wrong!

    One thing that irks me in these articles is gauging the opinion of the “Rust community” through Reddit/HN/Lemmy😉/blogs… etc. I don’t think I’d be way off the mark when I say that these platforms mostly collectively reflect the thoughts of junior Rustaceans, or non-Rustaceans experimenting with Rust, with the latter being the loudest, especially if they are struggling with it!

    And I disagree with the argument that poor standard library support is the major issue, although I myself had that thought before. It’s definitely current lack of language features that do introduce some annoyances. I do agree however that implicit coloring is not the answer (or an answer I want to ever see).

    Take this simple code I was writing today. Ideally, I would have liked to write it in functional style:

        async fn some_fn(&self) -> OptionᐸMyResᐸVecu8ᐳᐳᐳ {
            (bool_cond).then(|| async {
                // ...
                // res_op1().await?;
                // res_op2().await?;
                // ...
                Ok(bytes)
            })
        }
    

    But this of course doesn’t work because of the opaque type of the async block. Is that a serious hurdle? Obviously, it’s not:

        async fn some_fn(&self) -> OptionᐸMyResᐸVecu8ᐳᐳᐳ {
            if !bool_cond {
                return None;
            }
    
            let res = || async {
                // ...
                // res_op1()?;
                // res_op2()?;
                // ...
                Ok(bytes)
            };
    
            Some(res().await)
        }
    

    And done. A productive Rustacean is hardly wasting time on this.

    Okay, bool::then() is not the best example. I’m just show-casing that it’s current language limitations, not stdlib ones, that are behind the odd async annoyance encountered. And the solution, I would argue, does not have to come in the form of implicit coloring.




  • 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.



  • I would bad mouth Axum and Actix just because of the overhype. But then, the latter is powering this very platform, and the former is used in the federation crate examples 😉

    So let me just say that I tried poem and it got the job done for me. Rusty API. Decent documentation. And everything is in one crate. No books, extension crates, and towers of abstractions needed.

    I try to avoid tokio stuff in general for the same reason, although a compatible executor is unfortunately often required.


  • From your list, I use bat, exa and rg.

    delta (sometimes packaged as git-delta) deserves a mention. I use it with this git configuration:

    [core]
      # --inspect-raw-lines=false fixes issue where some added lines appear in bold blue without green background
      # default minus-style is 'normal auto'
      pager = "delta --inspect-raw-lines=false --minus-style='syntax #400000' --plus-style='syntax #004000' --minus-emph-style='normal #a00000' --plus-emph-style='normal #00a000' --line-buffer-size=48 --max-line-distance=0.8"
    
    [interactive]
      diffFilter = "delta --inspect-raw-lines=false --color-only --minus-style='syntax #400000' --plus-style='syntax #004000' --minus-emph-style='normal #a00000' --plus-emph-style='normal #00a000' --line-buffer-size=48 --max-line-distance=0.8"
    
    [delta]
      navigate = true  # use n and N to move between diff sections
      light = false    # set to true if you're in a terminal w/ a light background color (e.g. the default macOS terminal)
    
    [merge]
      conflictstyle = diff3
    



  • 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 [package.metadata.docs.rs] 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.