-
Notifications
You must be signed in to change notification settings - Fork 285
Derive Macro for typespec_client_core::http::Model
#1772
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
Derive Macro for typespec_client_core::http::Model
#1772
Conversation
Do we even need to re-export it from
typespec is a dependency and, conceptually, a package deal with typespec_client_core already. The idea for re-exporting from azure_core was trying to hide the "typespec"iness, though rust-analyzer seems to know better when suggesting to import types.
@analogrelay, @RickWinter, @JeffreyRichter, @LarryOsterman thoughts about re-exporting |
We don't need to, but it does provide one advantage. I've noticed that generally when you see a use serde::Deserialize;
use typespec_client_core::http::Model;
#[derive(Model, Deserialize)]
pub struct MyModel {} If we don't re-export the derive macro next to the trait (which is actually where I started in an earlier iteration of this branch), then you have to import them separately. Now, if you're just deriving the trait, you don't actually have to import the trait, so you can do this: use serde::Deserialize
use typespec_derive::Model;
#[derive(Model, Deserialize)]
pub struct MyModel {} If you later want to use use serde::Deserialize
use typespec_derive::Model;
use typespec_client_core::http::Model;
#[derive(Model, Deserialize)]
pub struct MyModel {}
fn do_something(m: impl Model) {} The trick is that the symbol
In general, I'm against re-exporting unless there are specific reasons to do it. But I've also lived a life forever tainted by having to work on NuGet dependency algorithms, so I like to avoid hiding dependencies as much as possible 😅 . I will say, the layering felt backwards to me when I saw it. I initially assumed that My inclination is to start with as few re-exports as possible and see what customers think. It's generally an additive change to re-export a type elsewhere after you've shipped it, but a breaking change to stop re-exporting a type. |
As for re-exports, I may just end up removing most. I still want to keep them in It does make me want to revisit preludes. We opted against them since they seem to be falling out of favor. Probably won't change our minds, though. |
My personal preference here would be to just drop the re-exports here and have client code reference |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great but while I see nothing truly blocking, I expect enough changes I want to look at this again.
c9a8ab2
to
8db1d80
Compare
I believe all the feedback has been resolved. In addition, I've added tests that validate compilation errors. I was originally looking at compiletest_rs for this (which is an extraction of the compiletest utility used in rustc itself to test errors) but ran into some issues getting dependencies right. I realized it was actually fairly easy to just have a Cargo project that produced all the expected errors and then write a standard integration test that ran |
2c76972
to
d868827
Compare
There are some build failures. Rebase on feature/track2 as well, which should fix one of them that @hallipr fixed and I merged just now. You can also update |
sdk/typespec/typespec_derive/compilation-tests/src/model/bad_attributes.rs
Outdated
Show resolved
Hide resolved
516fc30
to
4da2575
Compare
I'm hitting a strange difference between the GitHub and AzDO builds. The GitHub build uses I don't understand why, but there's a difference in enabled features between these two options when running
Note that When building the package directly, without
Note that this time This impacts the doctests for Unfortunately, if built with the For now, what I've done is just to fix the doctest. I can conditionally import |
e992466
to
c2add94
Compare
This PR adds a new
typespec_derive
crate. This crate provides a derive macro for theModel
type that replaces thejson_model
andxml_model
declarative macros I added in #1724 . The generated code is essentially the same. Instead of two separate macros to choose formats, you can use#[typespec(format = "xml")]
to change the format toxml
(and other formats in the future. Primarily to support testing inside the crate, I also added support for an attribute to set the crate that containsModel
, based on serde's equivalent.I was going to have the
azure_core
crate re-exports this macro, like it re-exports theModel
trait. However, there's a problem. You need to referencetypespec_client_core
in order to get theModel
trait in scope. We re-export that trait fromazure_core
but the generated code won't use that, it'll usetypespec_client_core
. That can be overridden with a#[typespec(crate = "azure_core")]
attribute, but that would require clients that don't referencetypespec_client_core
directly to put that attribute on every model type.Instead, I'm re-exporting it from
typespec_client_core
. This means that service client crates now need to add a reference totypespec_client_core
directly, but I think that's reasonable. It's not like crates can avoid being aware of typespec, or it's related libraries.There are some alternative approaches we could take, but I'm not a huge fan of those. For example, we could make the macro reference
Model
fromazure_core
and move it to anazure_derive
crate, but that means it's no longer available in the unbranded libraries. Or we could do something even funkier and find a way to "re-wrap" the proc_macro defined intypespec_derive
in a new macro inazure_derive
that sets the crate. That feels really clunky and difficult to achieve. So, I've stuck with this approach for now.