Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How should we handle provider APIs and their visibility? #165

Open
nekevss opened this issue Jan 16, 2025 · 10 comments
Open

How should we handle provider APIs and their visibility? #165

nekevss opened this issue Jan 16, 2025 · 10 comments
Labels
question Further information is requested

Comments

@nekevss
Copy link
Member

nekevss commented Jan 16, 2025

We need to deal with the provider API vs. non-provider API in a way that is ergonomic and
sane to deal with rather than keeping them in the same files (Mea culpa).

Currently, if we expose a non with_provider API, the with_provider method is still available. So if we make ZonedDateTime::to_ixdtf_string available then ZonedDateTime::to_ixdtf_string_with_provider will be available as well.

My initial thought is to separate the the two APIs into separate modules and then expose
them via feature flags.

General proposal overview

The general directory structure would be one of the two below.

NOTE: any bikeshedding on names would be fine by me. I like the core terminology for the
main implementation, but I'm not entirely convinced std is a good name. (Sort of mimicking
Rust's core vs. std separation).

.
+-- _src
|   +-- _core
|   +-- _std
|   +-- lib.rs

OR

.
+-- _src
|   +-- _builtins
|       +-- _core
|       +-- _std
|       +-- mod.rs
|   +-- lib.rs

The main idea would be to have all non-feature flagged APIs live in core. Meanwhile, for
all the general usage APIs (currently flagged "experimental") would be under std.

The general usage APIs would then just be either a reexport of the core impl or a
NewType of the core implementations if it has any provider APIs.

Other Options:

  • Leave as is, with features in one file with both APIs exposed.
  • Other suggestions
@nekevss nekevss added the question Further information is requested label Jan 16, 2025
nekevss added a commit that referenced this issue Jan 22, 2025
…APIs (#169)

This PR lays out the general concept laid out in #165.

Primarily, this PR splits the core Temporal functionality that can be
used by engines into the `builtins::core` module and then builds out
wrappers for nearly all of the core builtins (Currently only
`PlainYearMonth` and `PlainMonthDay` have not had wrappers implemented)
that can be used directly from Rust in the `builtins::native` module.

Ideally, this provides a better experience for using the library
natively from Rust (while also giving us a cleaner API to write tests
with), but still allows `with_provider` API to be used for engines
and/or anyone else who wants to implement their own `TimeZoneProvider`.
@jedel1043
Copy link
Member

jedel1043 commented Jan 22, 2025

@nekevss Knowing that #169 is causing problems for the FFI, maybe we could use separate impl blocks instead of wrapper types? All our structs are in the same crate anyways.

@nekevss
Copy link
Member Author

nekevss commented Jan 22, 2025

Yeah, I have a feeling that might be the best way to go about handling this.

That being said, the other solution is to remove "full" from being a default feature and have the wrapper types be opt-in. It prevents the problems with the FFI and stops any of the rust-analyzer workspace issues that happen when temporal_capi is set to default-feature = false.

@Manishearth
Copy link
Contributor

I'd not use core vs std, it makes it feel like this is a no_std vs with_std distinction.

@nekevss
Copy link
Member Author

nekevss commented Jan 22, 2025

I'd not use core vs std, it makes it feel like this is a no_std vs with_std distinction.

Agreed, that's why the initial change was core and native.

@nekevss
Copy link
Member Author

nekevss commented Jan 22, 2025

The big reasons for the breaks here is that the previous implementation was greedy and tried to get away with using the core implementation of PlainYearMonth and PlainMonthDay. That's probably a mea culpa.

To fix it, the current implementation wrappers can be added for the PlainYearMonth and PlainMonthDay. that should shore up the major issues with the API from the native side, or we can go back to using impl blocks. The implementation blocks concern me because there will end up being two methods, i.e. round and round_with_provider on various types.

But adding the wrappers doesn't address the "opt-in" or "opt-out" behavior if the wrappers or kept.

Is there any preference for one approach over the other?

@Manishearth
Copy link
Contributor

I'm still unclear on the purpose of this split; why it is implemented the way it is. If it's extra APIs, it should be implemented on the same type, right?

It's a violation of feature unification to hide APIs when a feature is enabled. Users of this crate may end up with breakages when found in a larger deptree.

Currently, if we expose a non with_provider API, the with_provider method is still available. So if we make ZonedDateTime::to_ixdtf_string available then ZonedDateTime::to_ixdtf_string_with_provider will be available as well.

This seems fine to me?

@jedel1043
Copy link
Member

+1 for @Manishearth's comment. If having wrappers is just overcomplicating FFI and feature resolution, we should just return to separate impl blocks. I think we can have all the benefits of nicely delimited feature sets if we split the impl blocks into different modules, then flag the whole module as feature-gated.

@nekevss
Copy link
Member Author

nekevss commented Jan 22, 2025

I'd be open to that idea. That would solve the issue with multiple feature flagged impl blocks all in one file.

Is there any preference as to how to handle API visibility. Do we forego attempting to separate with_provider methods from other methods? Or do we move ahead with just allowing the two to coexist?

@jedel1043
Copy link
Member

I think it's fine to leave them exposed. The impl blocks will nicely split the provider APIs from the bundled data APIs in the documentation.

@nekevss
Copy link
Member Author

nekevss commented Jan 22, 2025

Submitted #181 to hopefully address the points mentioned in the above discussion.

jedel1043 pushed a commit that referenced this issue Jan 23, 2025
This PR fixes #169 and is related to #165, and a couple of other issues
/ discussions that popped up after the restructure merge.

This mainly restructures the codebase to remove the wrapping types and
flag the non "with_provider" methods behind a non-default
"compiled_data" flag.

Let me know what you think!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants