# Calculating which 3rd party crates are good candidates for "std" inclusion via "left-pad index"

**URL:** https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129
**Category:** libs
**Created:** [October 16, 2019, 6:08pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129 "2019-10-16T18:08:57Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)
#### Post date: [October 16, 2019, 6:08pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/1 "2019-10-16T18:08:57Z")

</div>

Patrick Walton proposed the idea of a "left-pad index":

> <https://twitter.com/pcwalton/status/1181394377081442304>

I went ahead and crunched the numbers for [crates.io](http://crates.io), surveying the top 500 crates by recent downloads, dividing that number by the crate size, and coming up with the following results:

> **[Top 500 Crates](https://docs.google.com/spreadsheets/d/1wwahRMHG3buvnfHjmPQFU4Kyfq15oTwbfsuZpwHUKc4/edit#gid%3D1253069234)**
>
> Sheet 1 -...

 ![13%20AM](https://us1.discourse-cdn.com/flex002/uploads/rustlang/original/2X/6/678b3a1282329c256911b81a9f5676226bb8bbdb.png)

Per Patrick, here are some good candidates for potential inclusion in `std`:

> <https://twitter.com/pcwalton/status/1184524317079543808>

...the idea being that it would be safer to rely on the Rust distribution itself, rather than individual maintainers of third-party crates, for this functionality.

---

<div class="post-metadata">

### Author: ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)
#### Post date: [October 16, 2019, 6:29pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/2 "2019-10-16T18:29:31Z")

</div>

The world will hopefully soon be `nodrop` crate free, now that we have `MaybeUninit` which fully replaced it in arrayvec 0.5 (Rust 1.36+), and some crates have also dropped arrayvec 0.4 altogether, losing nodrop that way (which is also cool in my book.) We only need to wait for the version upgrades to trickle in. (Would it be possible to have the maintenance status in a column? 🙂 )

My personal favourite microcrate is `matches`.

---

<div class="post-metadata">

### Author: ![kjeremy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kjeremy/32/5492_2.png) [@kjeremy](https://internals.rust-lang.org/u/kjeremy)
#### Post date: [October 16, 2019, 6:52pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/3 "2019-10-16T18:52:51Z")

</div>

> [@bluss](#):
>
> The world will hopefully soon be `nodrop` crate free, now that we have `MaybeUninit` which fully replaced it in arrayvec 0.5

I believe crossbeam-epoch has a dependency on arrayvec 0.4 and that's used in quite a few places.

---

<div class="post-metadata">

### Author: ![vorner](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/vorner/32/3310_2.png) [@vorner](https://internals.rust-lang.org/u/vorner)
#### Post date: [October 16, 2019, 6:53pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/4 "2019-10-16T18:53:49Z")

</div>

Is being downloaded a lot a good indicator for inclusion into std?

For example, the table above contains lazy\_static. It has a lot of dependencies, because it solves a specific and quite a common problem. However, I find the once-cell more elegant and ergonomic. It has less reverse dependencies mostly because it is younger (I think).

Though I guess having this list is nice as a first filter into which to look.

---

<div class="post-metadata">

### Author: ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)
#### Post date: [October 16, 2019, 6:54pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/5 "2019-10-16T18:54:03Z")

</div>

It's gone in git, I think.

If I look close, rdep count seems like a much better indicator. Some of these have ridiculous download numbers for very few deps?

---

<div class="post-metadata">

### Author: ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)
#### Post date: [October 16, 2019, 6:55pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/6 "2019-10-16T18:55:56Z")

</div>

This scoring seems like a very incomplete story of importance in the ecosystem, and is misleading with regards to reusability which should be considered for inclusion in the standard library. Afterall, adding more baggage to everyone's download should at least come with overall useful payload.

Take `memoffset` for example whose download number comes overwhelmingly from a single crate, `crossbeam`. Or `nodrop` whose last release has marked it as deprecated after having been dropped from its main using crate `arrayvec`, by the same author (see above, @bluss beat me to the punch). Can a single major use be taken as an incentives to inclusion in `std`?

On the case of `phf_shared`/`phf_generator` they are very minimal indeed. However, how useful are they on their own? The extremely _costly_ dependency `phf_macros`, pretty much required to actually make use of its powers compared to standard hash functions, is not capture by the metrics.

And `fuchsia-cprng` is also curious since the description already disputes any cross-platform usability: `Type-safe bindings for the Zircon kernel's CPRNG.`. While that confirms that at least some party connected to Google Fuchsia is a prominent user of Rust & [crates.io](http://crates.io) (Are other crates internally cached, or why don't all fuchsia crates show up that high?) it does not qualify the crate for inclusion in `std` in any way. And since the metrics rank it that high, that makes me question the metrics.

That's not to say the list doesn't have any useful entries, both `matches` and `scopeguard` _complement_ existing features quite well imho (though the interfaces deserve RFCs anways if someone were to propose them).

---

<div class="post-metadata">

### Author: ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)
#### Post date: [October 16, 2019, 7:15pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/7 "2019-10-16T19:15:40Z")

</div>

> [@bluss](#):
>
> My personal favourite microcrate is `matches` .

...which I don't think should be added to the standard library, at least not in its current form, due to improvements to the language itself (see let chains, the possibility of making `let $pat = $expr` itself a bool-typed expression, ...).

> [@197g](#):
>
> Take `memoffset` for example whose download number comes overwhelmingly from a single crate, `crossbeam`

And moreover, `memoffset` is unsound.

---

<div class="post-metadata">

### Author: ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)
#### Post date: [October 16, 2019, 7:25pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/8 "2019-10-16T19:25:10Z")

</div>

I agree that any metric which includes transitive clients is going to have its usefulness quickly demolished by the "oh, crossbeam used it" problem.

The reverse\_deps field is just _direct_ reverse dependencies, right? Because using that metric instead of recent downloads produces the following top 30 list:

- lazy\_static
- log
- serde
- serde\_derive
- byteorder
- futures
- failure\_derive
- serde\_json
- matches
- quote
- failure
- env\_logger
- mime
- hex
- bitflags
- num\_cpus
- atty
- dirs
- cfg-if
- time
- bincode
- rand
- strsim
- error-chain
- pkg-config
- proc-macro2
- tempfile
- sha2
- dotenv
- pretty\_env\_logger

Which seems much more plausible to me. Although... serde is clearly not a "microcrate". Let's try reverse\_deps / crate\_size ^ 2:

- matches
- lazy\_static
- failure\_derive
- atty
- phf\_codegen
- hex
- phf
- strum
- cfg-if
- log
- doc-comment
- byteorder
- num\_cpus
- mime
- dotenv
- strsim
- futures
- crunchy
- bitflags
- dirs
- quote
- pretty\_env\_logger
- hex-literal
- try\_from
- maplit
- crossbeam
- md5
- bincode
- phf\_shared
- digest

Yeah, I think that's a slight improvement. That's probably as good a list of "Rust leftpads" as we're gonna get from number crunching alone.

(I am bad at google docs, but on the off chance it helps somehow, here's the link to my copy of the top 500 table changed to do rdeps/size^2 sorting: [https://docs.google.com/spreadsheets/d/1TIU7IQKhwfIWPAWhfX0f-PHfcwsVXsg43MxDUg2AO4I/edit?usp=sharing](https://docs.google.com/spreadsheets/d/1TIU7IQKhwfIWPAWhfX0f-PHfcwsVXsg43MxDUg2AO4I/edit?usp=sharing) )

---

<div class="post-metadata">

### Author: ![RazrFalcon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/razrfalcon/32/2464_2.png) [@RazrFalcon](https://internals.rust-lang.org/u/RazrFalcon)
#### Post date: [October 16, 2019, 7:35pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/9 "2019-10-16T19:35:08Z")

</div>

It doesn't seem like a good metric. From crates on the screenshot, only `matches` and `cfg-if` are std worthy, imho. And both of them should be implemented as a language feature anyway.

Personally, `log` is my main request. Also `arrayvec`/`smallvec`. `byteorder` is also a very popular.

UPD: I almost forgot about language-level `bitflags`. The current implementation isn't user-friendly (IDE's cannot expand macros yet, so it breaks autocomplition).

---

<div class="post-metadata">

### Author: ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)
#### Post date: [October 16, 2019, 7:54pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/10 "2019-10-16T19:54:50Z")

</div>

> [@bluss](#):
>
> My personal favourite microcrate is `matches` .

Agreed, to the point that we keep having conversations about it being a feature with real syntax (one proposal was `x is Some(_)`, for example.)

Would still be worth contemplating putting `assert_matches!` in `std`, though, the same way we have `assert_eq!` even with `==` syntax...

> [@Ixrec](#):
>
> - try\_from

Good to see we've at least made progress one some of them 🙂

---

<div class="post-metadata">

### Author: ![synek317](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/synek317/32/3371_2.png) [@synek317](https://internals.rust-lang.org/u/synek317)
#### Post date: [October 16, 2019, 8:11pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/11 "2019-10-16T20:11:45Z")

</div>

Having some experience with multiple 'mainstream' languages, I was pretty surprised that following crates are not in the std:

- log
- rand
- lazy\_static or something similar

Other good candidates:

- syn, quote, proc\_macro2 - must haves to create any proc macro,
- regex,
- itertools - it provides a lot of goodies but sometimes I decide to write code in more ugly way just because I'm too lazy to add the dependency or I want to reduce build time,
- derive more

Also, I don't understand why there is `std::time` and crate `time`. And chrono, or at least parts of chrono, seems to be good candidate.

---

<div class="post-metadata">

### Author: ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)
#### Post date: [October 16, 2019, 8:28pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/12 "2019-10-16T20:28:17Z")

</div>

> [@vorner](#):
>
> For example, the table above contains lazy\_static. It has a lot of dependencies, because it solves a specific and quite a common problem. However, I find the once-cell more elegant and ergonomic. It has less reverse dependencies mostly because it is younger (I think).

I would agree just copying and pasting `lazy_static` into `std` as-is would be a bad idea. That said, you're missing the forest for the trees: it isn't so much that we should just outright copy and paste these crates into `std`, but rather these crates provide features which might be good candidates for first-class `std` features.

In the case of `lazy_static`, improving Rust's core support for static data, e.g. static initializers, first-class heap-allocated statics, and associated statics, are common topics on these forums. The problem of static data, in particular, is a problem that can be solved much more elegantly and powerfully at the language level rather than at the library level, and could potentially interact with things like the trait system or program startup.

---

<div class="post-metadata">

### Author: ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)
#### Post date: [October 16, 2019, 9:19pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/13 "2019-10-16T21:19:05Z")

</div>

> [@synek317](#):
>
> syn, quote, proc\_macro2 - must haves to create any proc macro,

This would amount to freezing the syntax of the language itself.

> [@RazrFalcon](#):
>
> Also `arrayvec` / `smallvec` .

I'm personally in favor of `ArrayVec<...>` using const generics on nightly because they are sort-of a vocabulary type at least for a language like Rust.

> [@scottmcm](#):
>
> Would still be worth contemplating putting `assert_matches!` in `std` , though, the same way we have `assert_eq!` even with `==` syntax...

Imo `assert!(let A = expr && ...);` seems strictly more flexible.

> [@synek317](#):
>
> itertools - it provides a lot of goodies but sometimes I decide to write code in more ugly way just because I'm too lazy to add the dependency or I want to reduce build time,

We have imported some stuff from itertools over time. Would be worth going over again to see if there are some more things we could add.

> [@synek317](#):
>
> derive more

Could definitely see this; adding more built-in derives for standard library traits seems sensible if obvious structural implementations can be given.

> [@bascule](#):
>
> In the case of `lazy_static` , improving Rust's core support for static data, e.g. static initializers, first-class heap-allocated statics, and associated statics, are common topics on these forums. The problem of static data, in particular, is a problem that can be solved much more elegantly and powerfully at the language level rather than at the library level, and could potentially interact with things like the trait system or program startup.

I think it would take some convincing for me to be comfortable with baking in support for (and thereby encouraging) what are essentially global singletons into the language itself since that is often a code-smell and hacks around better architectures. Most of the times I've used `lazy_static!` I've come to regret it later.

> [@bascule](#):
>
> first-class heap-allocated statics

There are plans 🙂(Me and Oliver should probably write an RFC at some point...)

[![](https://img.youtube.com/vi/wkXNm_qo8aY/maxresdefault.jpg "RustConf 2019 - Taking Constant Evaluation to the Limit by Oliver Schneider") ](https://www.youtube.com/watch?v=wkXNm_qo8aY)

> [@bascule](#):
>
> and associated statics

...are generally wanted but these would allow generic statics and those do generally not mix with dylibs (which many want to ditch eventually...).

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [October 16, 2019, 9:33pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/14 "2019-10-16T21:33:28Z")

</div>

> [@Centril](#):
>
> > [@scottmcm](#):
> >
> > Would still be worth contemplating putting `assert_matches!` in `std` , though, the same way we have `assert_eq!` even with `==` syntax...
> 
> Imo `assert!(let A = expr && ...);` seems strictly more flexible.

`assert!(expr == expected)` is strictly more flexible than `assert_eq!(expr, expected)` as well, yet we still have `assert_eq!` because it can give more useful errors than `assert!(==)`. I think the same applies to `assert_matches!` and `assert!(let =)`.

---

<div class="post-metadata">

### Author: ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)
#### Post date: [October 16, 2019, 9:41pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/15 "2019-10-16T21:41:49Z")

</div>

> [@Centril](#):
>
> There are plans 🙂 (Me and Oliver should probably write an RFC at some point...)

Neat! Looking forward to seeing it.

---

<div class="post-metadata">

### Author: ![kentnl](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kentnl/32/6165_2.png) [@kentnl](https://internals.rust-lang.org/u/kentnl)
#### Post date: [October 16, 2019, 11:19pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/16 "2019-10-16T23:19:06Z")

</div>

fuschia-cprng is a target-conditional dependency of rand ( or something in rand's dep stack, I forget ).

That might have something to do with its prevalence in this graph, despite the apparent lack of reverse-deps ( in that, cargo users using the rand crate may have it downloaded for them at some point, even though it gets elided from compilation )

---

<div class="post-metadata">

### Author: ![endsofthreads](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/endsofthreads/32/1769_2.png) [@endsofthreads](https://internals.rust-lang.org/u/endsofthreads)
#### Post date: [October 17, 2019, 1:35am UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/17 "2019-10-17T01:35:04Z")

</div>

Quickly about `log`: I don't believe that that the style of logging we see now, as exemplified by `log`, will be the dominant form of how we emit instrumentation from applications and libraries in the decently-near future. I think it'll probably be far closer to [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-specification) or [`tracing`](https://github.com/tokio-rs/tracing).

Introducing a library into `std` means that a breaking change _cannot ever_ be introduced into that API, not even through editions. As much as I rely on those libraries on a day-to-day, the thought of _never_ introducing a breaking change gives me pause.

---

<div class="post-metadata">

### Author: ![pcwalton](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pcwalton/32/207_2.png) [@pcwalton](https://internals.rust-lang.org/u/pcwalton)
#### Post date: [October 17, 2019, 2:59pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/18 "2019-10-17T14:59:26Z")

</div>

I think it's a shame if we can't include basic things in the standard library because of lack of consensus, even when we have empirical evidence that they're widely used.

> [@Centril](#):
>
> I think it would take some convincing for me to be comfortable with baking in support for (and thereby encouraging) what are essentially global singletons into the language itself since that is often a code-smell and hacks around better architectures. Most of the times I've used `lazy_static!` I've come to regret it later.

I strongly disagree with this. `lazy_static!` is extremely important for all sorts of use cases. It's not Rust's place to be overly opinionated like that.

For example, I recently used `lazy_static!` several times in a GPU plumbing crate I'm working on to load OpenGL extension functions. Essentially, I was replicating `dlopen` and `dlsym` (you can't use `dlopen` and `dlsym` directly for various platform-specific reasons not worth getting into here). They're global functions: there would be zero benefit to storing them in a struct and forcing callers to pass them around everywhere. We don't force callers of basic dynamically-linked functions like `OpenFile()` on Windows to manually load them into a struct and thread that struct through all their code.

Similar reasons crop up in most of the crates I write to implement `lazy_static`, since I frequently write low-level plumbing crates. Rust is a systems language, and as such must be flexible. Just because you don't use `lazy_static` doesn't mean a lot of others don't have legitimate reasons to use it.

---

<div class="post-metadata">

### Author: ![pcwalton](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pcwalton/32/207_2.png) [@pcwalton](https://internals.rust-lang.org/u/pcwalton)
#### Post date: [October 17, 2019, 3:01pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/19 "2019-10-17T15:01:28Z")

</div>

> [@endsofthreads](#):
>
> Quickly about `log` : I don't believe that that the style of logging we see now, as exemplified by `log` , will be the dominant form of how we emit instrumentation from applications and libraries in the decently-near future. I think it'll probably be far closer to [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-specification) or [`tracing`](https://github.com/tokio-rs/tracing).

For servers, maybe. But for those of us who are, say, writing low-level graphics code, those crates are total overkill. I don't want to learn a fancy logging system which has no benefit to the code that I'm actually writing right now; I just want to use `log` so that I can get printfs that actually work on Android. If `log` were to go away, then I'd probably migrate to just open-coding calls to `__android_log_print` instead of using a heavyweight logging framework, which would obviously be of no benefit.

---

<div class="post-metadata">

### Author: ![pcwalton](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pcwalton/32/207_2.png) [@pcwalton](https://internals.rust-lang.org/u/pcwalton)
#### Post date: [October 17, 2019, 3:08pm UTC](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129/20 "2019-10-17T15:08:47Z")

</div>

I agree with @bascule that nitpicking the details of individual crates misses the point. The purpose of the "left-pad index" is that small crates that are widely used are one of the sincerest forms of feature requests. If the functionality provided by the crates can be provided by a language feature, or by the standard library in a different way from the popular [crates.io](http://crates.io) crates, then great! What I don't think we should do is ignore the signal entirely. People are using the functionality provided by these crates, period—our choice is whether we want to make Rust users' lives easier or not.

[Next page](https://internals.rust-lang.org/t/calculating-which-3rd-party-crates-are-good-candidates-for-std-inclusion-via-left-pad-index/11129.md?page=2)
