Add baseline ZoneInfo64 data provider#354
Conversation
This adds a ZoneInfo64Provider that directly uses zoneinfo64.res bytes. This does not implement any resolution for now for the actual provider. Ideally, long term, it may be best for this to take in bytes and complete some zerocopy deserialization, but there's some real difficulty around handling zoneinfo64's u16 strings that may require some custom types.
| # ZoneInfo64 dependencies | ||
| resb = { git = "https://github.com/unicode-org/icu4x.git", optional = true } | ||
| rustc-hash = { workspace = true, optional = true } | ||
| writeable = { workspace = true, optional = true } No newline at end of file |
There was a problem hiding this comment.
Whitespace 👮♂️
| writeable = { workspace = true, optional = true } | |
| writeable = { workspace = true, optional = true } | |
| #[serde(borrow)] | ||
| pub final_rule: Option<ZoneInfo64String<'data>>, | ||
| pub final_raw: Option<i32>, | ||
| pub final_year: Option<i32>, |
There was a problem hiding this comment.
Remark: Seems like from the data that the year can fit in a i16
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum Zone<'data> { | ||
| Table(ZoneTable<'data>), |
There was a problem hiding this comment.
Since ZoneTable is 108 bytes bigger than the Link variant maybe we should wrap it in a Box.
| Table(ZoneTable<'data>), | |
| Table(Box<ZoneTable<'data>>), |
There was a problem hiding this comment.
Not useful if it's being zero-copy deserialized. Could be a Cow though.
Probably, yes. Make sure it's included in the published package! |
| serde_json = { version = "1.0.140", optional = true } | ||
|
|
||
| # ZoneInfo64 dependencies | ||
| resb = { git = "https://github.com/unicode-org/icu4x.git", optional = true } |
There was a problem hiding this comment.
We should cut a release; make a PR to ICU4X that finalizes the resb Cargo.toml (make it publish = false), write a changelog entry, and ping me for a release.
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum Zone<'data> { | ||
| Table(ZoneTable<'data>), |
There was a problem hiding this comment.
Not useful if it's being zero-copy deserialized. Could be a Cow though.
|
More thoughts on zerocopy stuff: Really I think there's not as much benefit doing this through the serde model if you want to do it zerocopy, doing zerocopy in the serde model is easier if you control the data format itself, but here we do not. If we want to do 100% zerocopy stuff we should write a custom parser with the right intermediate types. But it's not super necessary, a handful of allocations isn't a big deal here. |
| #[cfg(target_endian = "little")] | ||
| let bytes = include_bytes!("./data/zoneinfo64/2025b/le/zoneinfo64.res"); | ||
| #[cfg(target_endian = "big")] | ||
| let bytes = include_bytes!("./data/zoneinfo64/2025b/be/zoneinfo64.res"); |
There was a problem hiding this comment.
hm. This won't actually work.
ZeroVec does two things: it allows data to be unaligned, and it consistently serializes in little-endian format. You only need the first one if your parsers are different for LE/BE.
Either the resb parser needs to be written to allow selecting endianness in the caller, OR you should exclusively access the ZeroVec data here in a way that inverts the numbers on BE.
Probably something to be fixed later.
There was a problem hiding this comment.
Yeah, I added it initially, and then realized the day after that the BE wouldn't work with ZeroVec. I just haven't gotten around to fixing it just yet.
There was a problem hiding this comment.
If the resb data that is available from platforms uses native endianness, the resb crate should just not use ZeroVec.
There was a problem hiding this comment.
Agreed. In this case, the zoneinfo file is provided, so the BE zoneinfo file just needs to be removed.
robertbastian
left a comment
There was a problem hiding this comment.
Would it make sense to move some of the logic, and more importantly the data and tests into the resb crate? This should also solve the license problem as resb is already Unicode-licensed.
| #[cfg(target_endian = "little")] | ||
| let bytes = include_bytes!("./data/zoneinfo64/2025b/le/zoneinfo64.res"); | ||
| #[cfg(target_endian = "big")] | ||
| let bytes = include_bytes!("./data/zoneinfo64/2025b/be/zoneinfo64.res"); |
There was a problem hiding this comment.
If the resb data that is available from platforms uses native endianness, the resb crate should just not use ZeroVec.
Yeah, I think there's a good argument here for moving it into the The only issue is that I'm not entirely convinced that the |
|
It should definitely be feature-flagged for the scenario where there's already a zoneinfo64 available from somewhere else. |
|
Closing as this is being implemented in a different approach |
This adds a ZoneInfo64Provider that directly uses zoneinfo64.res bytes. This does not implement any resolution for now for the actual provider.
Ideally, long term, it may be best for this to take in bytes and complete some zerocopy deserialization, but there's some real difficulty around handling zoneinfo64's u16 strings that may require some custom types.
I think this may also require us to carry a Unicode license in the root for
timezone_providerdue to the res files. CC: @Manishearth for confirmation on that