Skip to content

a different internal crate organization to help with build times #373

@BurntSushi

Description

@BurntSushi

While #372 tries to attack the problem of build times with the obvious "make it possible to compile less stuff," this issue promotes a slightly more radical approach. Namely, it is well known that splitting a crate up into multiple crates will help with compile times, presumably because it helps make more effective use of multiple CPUs.

I did the same thing with regex. Although, I didn't do it because of build times. I did it because I wanted to expose lower level primitives outside of a standard regex API (memchr and aho-corasick being examples of that) and I wanted to expose some of the regex engine internals for more flexible use cases (that's regex-syntax and regex-automata). I'd guess that this ended up helping build times, although there's no real comparison point there.

My problem with doing this is: 1) it expands the dependency tree and 2) it introduces more semver boundaries. I am loathe to have more semver boundaries. They are a huge fucking pain in the ass. They make releases and refactoring more annoying. Moreover, you have to be super careful about introducing public dependencies, or else the semver API evolution of one crate is tied to another.

With that said... Jiff doesn't actually have a ton of internal code. It has some. But most of what I'd put into separate crates are already in Jiff's public API.

Anyway, here's what I'm thinking:

  • jiff-primitive would have Timestamp, SignedDuration, tz::Offset, civil::{DateTime, Date, Time, ISOWeekDate, Weekday} and maybe some others that I'm thinking about.
  • jiff-tz would have the TZif and POSIX time zone parsers. It would have a public dependency on jiff-primitive. Probably TimeZone has to live here too.
  • jiff-fmt has what's in jiff::fmt today, and would have public dependencies on jiff-primitive and jiff-tz.
  • jiff glues everything together. It still has some non-trivial code in it, like Zoned and Span. Along with TimeZoneDatabase. But otherwise is a facade over the aforementioned crates. Users of Jiff (like users of regex) wouldn't need to worry about the crates above. Jiff's API would stay the same cohesive self. Annoyingly, Jiff would not have public dependencies on any of the above crates.

From my perspective, there are significant challenges with the above blueprint.

  • All 4 crates, as they exist inside of Jiff today, would want to use ranged integers. So I would need to make a new jiff-ranged or something that exposes the ranged integer types. I really do not like this idea because the ranged integers are a giant fucking mess IMO. So it's more likely that in order for the above to work, I'd want to rip ranged integers out of Jiff. (This raises the question of what I'd do instead, because we still need to check boundary conditions everywhere.)
  • The API surface of these crates is huge, and the thought of writing docs for them and then copying most of those docs verbatim into Jiff proper, and then writing all of the facade wrappers is just... well... it's terrifying. So in order to make this work, I'd probably have to at least settle for the jiff-{primitive,tz,fmt} crates to have light or almost no docs. Basically they'd be "internal only, not intended for public use."
  • Changes at the bottom of the crate dependency graph that are needed higher up require an annoying about Cargo interaction: 1) bump version, 2) release, 3) bump version in dependent, 4) release, 5) repeat. I have to do this in ripgrep and it's awful. It's part of the reason why I don't do ripgrep releases often.

This could be done in a piecemeal fashion to get a sense of whether it's worth doing. I think the first thing here would be to start ripping ranged integers out, probably starting with the civil types. Then the other primitives. Once those are free of ranged integers, we could in theory move them out into a separate crate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions