├── .github └── FUNDING.yml └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [zkat] 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust Bumps 2 | 3 | This is a collection of notes I have on sharp edges I've encountered in my 4 | journey to learn Rust, in hopes that I can use them in the future to target 5 | contributions to Rust proper, or to share with others who might be interested. 6 | 7 | ## Contribution Process 8 | 9 | It wasn't immediately clear what the process of actually contributing to Rust 10 | proper is. 11 | 12 | ### Solutions 13 | 14 | I went to `#beginners` in the Rust discourse, and they pointed me at the 15 | forum, where I'd need to bring it up, try and get some buy-in around my change 16 | concept, then put together an RFC when enough(?) people have shown interest, 17 | and then finally that RFC would point to an implementation. 18 | 19 | ## Builders 20 | 21 | The builder pattern is super common in Rust. Almost obnoxiously so. To the 22 | point where I wonder if Rust should have some sort of first-class support or 23 | new language feature that largely obsoletes the need for the pattern. 24 | 25 | ### Solutions 26 | 27 | In general the pattern is often replaced by things like variadic functions or 28 | ad-hoc option arguments in other languages. 29 | 30 | This isn't a terrible pattern, but even going as far as introducing 31 | https://crates.io/crates/derive_builder into the language or into the Book 32 | would be nice. 33 | 34 | ## Multi-type errors 35 | 36 | The book doesn't really cover a pretty basic case in earnest: the situation 37 | where you have multiple different error returns and you want to use `?`. 38 | 39 | ### Solutions 40 | 41 | Establishing an error-definition pattern a-la https://crates.io/crates/failure 42 | in the Book would be super helpful, if not integrating `failure` itself. 43 | 44 | Update: I'm supposed to use `failure`, not `error-chain`, per @ag_dubs. SIGH 45 | 46 | Update: The plot thickens! https://twitter.com/hoodie_de/status/1135192684916879360 claims I should not be returning failure::Error from public APIs but this is not clear at all and I'm not sure what the expected alternative is. 47 | 48 | ## Returning iterators 49 | 50 | Iterators are super duper useful! Infortunately, it's super hard to figure out 51 | how to -return- them from functions. The compiler errors when you first try to 52 | do this are incredibly opaque and confusing. 53 | 54 | ### Solution 55 | 56 | It turns out these days, you have `-> impl Iterator` which makes this work, 57 | but this was not very obvious and the compiler errors were SUPER CONFUSING 58 | about how to fix this. It might go a long way to have the compiler be aware of 59 | at _least_ the Iterator case. Those compiler messages, wwhoo. 60 | 61 | ## WTF is `AsRef`? 62 | 63 | I kept seeing this `AsRef` stuff while working with `Path`-related functionality and didn't really understand why folks were doing that instead of `path: &Path` in function signatures. 64 | 65 | ### Solutions 66 | 67 | This isn't really covered in the Book, and maybe it should. A friend proceeded to explain the use and intent: It's used as a perf-cheap version of `From` to convert from one immutable ref to another immutable ref. In this **particular** case, it was being used so you could pass Paths, PathBufs, _or_ strings into the function and have it work with any of those types. 68 | 69 | It would be nice to make a note in the Book about this being a convention, or becoming one? 70 | 71 | ## Weird File API 72 | 73 | The File-related APIs are really strange and factored in such a way that I had a really hard time finding what I needed, compared to the relatively flat `fs` module in Node.js. 74 | 75 | I think the biggest pain is that some things seem to live in `fs::`, some in `io::` and others in `fs::File`, and it wasn't clear when one vs the other was used. The toplevel `fs::` utilities are actually pretty handy, though! 76 | 77 | ### Solutions 78 | 79 | idk. Changing this fundamentally would have a huge impact, unfortunately, and 80 | Rust is very stability-oriented these days. I kinda wish there were a simpler, 81 | higher-level, zero-cost crate for doing these things, optionally with 82 | `Future`s, and for the `fs` and `io` stuff to largely be considered "internal 83 | use only" building blocks, if even that. I just plain don't like it and find 84 | it hard to work with. Maybe [`Tokio`](https://crates.io/crates/tokio) is the 85 | answer, once it's updated with futures@0.3? 86 | 87 | ## Literally no chown? 88 | 89 | So the `fs` API has literally no `chown` functionality. I know it's pretty 90 | niche, but I needed it! 91 | 92 | ### Solutions 93 | 94 | This is exposed through direct bindings by 95 | [`nix`](https://crates.io/crates/nix). There's also a higher-level 96 | [`chownr`](https://crates.io/crates/chownr) crate by yours truly that does the 97 | recursive bit. 98 | 99 | ## Everyone uses `extern crate` 100 | 101 | ...but you're supposed to just use `use`. This is mostly an annoyance because everyone's docs are outdated and still refer people to importing using this. As an additional note, a lot of places combine this statement with `#![macro_use]` when importing macros. 102 | 103 | ### Solutions 104 | 105 | Highlighting that `extern crate` isn't used anymore, in the Book, might be 106 | super helpful here. The rest is just waiting out the ecosystem. I'm not really 107 | sure what the actual expected alternative to `#![macro_use]` is supposed to 108 | be, but I had some luck directly `use`-ing the macro into my scope like a 109 | function? So a macro named `foo` in crate `bar` would be imported with `use 110 | bar::foo;` and then the macro seemed to work... 111 | 112 | ## No `cargo version` built-in 113 | 114 | Coming from Node, this feels like a sharp corner: I have to manually edit 115 | Cargo.toml, change the version, run `cargo build` to update the `Cargo.lock` 116 | so I don't end up with a random diff, then I have to manually `git ci -a -m 117 | 'vX.Y.Z'`, `git tag -a vX.Y.Z`, fill in a message, `git push --follow-tags`, 118 | and **then** `cargo publish`. Just for a basic release. I'm used to at least 119 | having a baseline of `npm version patch && git push --follow-tags && npm pub`. 120 | 121 | ### Solution 122 | 123 | Having a _baseline_ `cargo version` built in would go a long way towards 124 | making publishing as a newbie a smoother process. 125 | 126 | ## No `nyc` equivalent for coverage 127 | 128 | There's no single coverage tool you can just install that integrates with 129 | `cargo test` and gives useful coverage feedback in the command line, works 130 | with coveralls/codecov, etc. The best you get is something [as described in 131 | this 3-year-old forum 132 | thread](https://users.rust-lang.org/t/howto-generating-a-branch-coverage-report/8524) 133 | which... honestly I'm not going to bother because this is an immense amount of 134 | fucking around with stuff just to get my percentages? 135 | 136 | I'm so used to having [`nyc`](https://npm.im/nyc) available :() 137 | 138 | ### Solution 139 | 140 | Rust -really- needs an `nyc` port. 141 | --------------------------------------------------------------------------------