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

Is there any way to create inline comments? #205

Closed
therealprof opened this issue Nov 12, 2019 · 8 comments
Closed

Is there any way to create inline comments? #205

therealprof opened this issue Nov 12, 2019 · 8 comments

Comments

@therealprof
Copy link

therealprof commented Nov 12, 2019

As people may or may not be aware, in embedded we generate Rust code from MCU register descriptions, including remarks and metadata provided by those descriptions as comments with a tool called svd2rust and republish those as crates for common use. Those look like e.g. https://docs.rs/stm32f0/0.9.0/stm32f0/stm32f0x0/adc/ccr/struct.TSEN_W.html

Now as you can imagine the generated code files are huge which comes with the usual negative side effects that everything about using them is happening in slow motion; compilation is slow and we regularly de-rail or least block docs.rs infrastructure for considerable amounts of time.

Reducing and improving our generated code has been a huge focus for us but the #[doc] comments were not too much of a concern except for saving a few bytes, however recently rust-lang/rust#65750 has landed which I presume would be a massive benefit for use if we could change our large number of single line comments to /// instead.

Now the question is: How can we get there?

We're using quote! extensively so our code looks like:

let doc = format!("Checks if the value of the field is `{}`", pc);
enum_items.push(quote! {
    #[doc = #doc]
    #[inline(always)]
    pub fn #is_variant(&self) -> bool {
        *self == #pc_r::#pc
    }
});

Changing to

let doc = format!("Checks if the value of the field is `{}`", pc);
enum_items.push(quote! {
    /// #doc
    #[inline(always)]
    pub fn #is_variant(&self) -> bool {
        *self == #pc_r::#pc
    }
});

does not work because the #doc is not interpolated anymore

Changing to

let doc = Literal::string(&format!("Checks if the value of the field is `{}`", pc));
enum_items.push(quote! {
    #doc
    #[inline(always)]
    pub fn #is_variant(&self) -> bool {
        *self == #pc_r::#pc
    }
});

does not work because quote! will quote the comment.

Parsing it does also not work because it will convert it back to a #[doc] attribute.

Is there any way to do this now or is there any plan to tackle this?

@dtolnay
Copy link
Owner

dtolnay commented Nov 12, 2019

As I understand it, rust-lang/rust#65750 does not apply to proc macros. Both input and output of proc macros is always in the form of #[doc = "..."]. There is no single token that would correspond to a ///-style comment.

As such, you may be better off not using quote / TokenStream for generating these files. Is it possible to produce a String directly instead?

@therealprof
Copy link
Author

We're using proc_macros2 to generate code. The code itself does not use macros.

The generated code e.g. looks like:

impl W {
# [ doc = "Bit 0 - Filter bits" ] # [ inline ( always ) ] pub fn fb0 ( & mut self ) -> FB0_W { FB0_W { w : self } }
# [ doc = "Bit 1 - Filter bits" ] # [ inline ( always ) ] pub fn fb1 ( & mut self ) -> FB1_W { FB1_W { w : self } }                                                                                                                          # [ doc = "Bit 2 - Filter bits" ] # [ inline ( always ) ] pub fn fb2 ( & mut self ) -> FB2_W { FB2_W { w : self } }
# [ doc = "Bit 3 - Filter bits" ] # [ inline ( always ) ] pub fn fb3 ( & mut self ) -> FB3_W { FB3_W { w : self } }
# [ doc = "Bit 4 - Filter bits" ] # [ inline ( always ) ] pub fn fb4 ( & mut self ) -> FB4_W { FB4_W { w : self } }
# [ doc = "Bit 5 - Filter bits" ] # [ inline ( always ) ] pub fn fb5 ( & mut self ) -> FB5_W { FB5_W { w : self } }
# [ doc = "Bit 6 - Filter bits" ] # [ inline ( always ) ] pub fn fb6 ( & mut self ) -> FB6_W { FB6_W { w : self } }
# [ doc = "Bit 7 - Filter bits" ] # [ inline ( always ) ] pub fn fb7 ( & mut self ) -> FB7_W { FB7_W { w : self } }
# [ doc = "Bit 8 - Filter bits" ] # [ inline ( always ) ] pub fn fb8 ( & mut self ) -> FB8_W { FB8_W { w : self } }
# [ doc = "Bit 9 - Filter bits" ] # [ inline ( always ) ] pub fn fb9 ( & mut self ) -> FB9_W { FB9_W { w : self } }
# [ doc = "Bit 10 - Filter bits" ] # [ inline ( always ) ] pub fn fb10 ( & mut self ) -> FB10_W { FB10_W { w : self } }                                                                                                                      # [ doc = "Bit 11 - Filter bits" ] # [ inline ( always ) ] pub fn fb11 ( & mut self ) -> FB11_W { FB11_W { w : self } }
# [ doc = "Bit 12 - Filter bits" ] # [ inline ( always ) ] pub fn fb12 ( & mut self ) -> FB12_W { FB12_W { w : self } }
# [ doc = "Bit 13 - Filter bits" ] # [ inline ( always ) ] pub fn fb13 ( & mut self ) -> FB13_W { FB13_W { w : self } }
# [ doc = "Bit 14 - Filter bits" ] # [ inline ( always ) ] pub fn fb14 ( & mut self ) -> FB14_W { FB14_W { w : self } }
# [ doc = "Bit 15 - Filter bits" ] # [ inline ( always ) ] pub fn fb15 ( & mut self ) -> FB15_W { FB15_W { w : self } }
# [ doc = "Bit 16 - Filter bits" ] # [ inline ( always ) ] pub fn fb16 ( & mut self ) -> FB16_W { FB16_W { w : self } }
# [ doc = "Bit 17 - Filter bits" ] # [ inline ( always ) ] pub fn fb17 ( & mut self ) -> FB17_W { FB17_W { w : self } }
# [ doc = "Bit 18 - Filter bits" ] # [ inline ( always ) ] pub fn fb18 ( & mut self ) -> FB18_W { FB18_W { w : self } }
# [ doc = "Bit 19 - Filter bits" ] # [ inline ( always ) ] pub fn fb19 ( & mut self ) -> FB19_W { FB19_W { w : self } }
# [ doc = "Bit 20 - Filter bits" ] # [ inline ( always ) ] pub fn fb20 ( & mut self ) -> FB20_W { FB20_W { w : self } }
# [ doc = "Bit 21 - Filter bits" ] # [ inline ( always ) ] pub fn fb21 ( & mut self ) -> FB21_W { FB21_W { w : self } }
# [ doc = "Bit 22 - Filter bits" ] # [ inline ( always ) ] pub fn fb22 ( & mut self ) -> FB22_W { FB22_W { w : self } }
# [ doc = "Bit 23 - Filter bits" ] # [ inline ( always ) ] pub fn fb23 ( & mut self ) -> FB23_W { FB23_W { w : self } }
# [ doc = "Bit 24 - Filter bits" ] # [ inline ( always ) ] pub fn fb24 ( & mut self ) -> FB24_W { FB24_W { w : self } }
# [ doc = "Bit 25 - Filter bits" ] # [ inline ( always ) ] pub fn fb25 ( & mut self ) -> FB25_W { FB25_W { w : self } }                                                                                                                      # [ doc = "Bit 26 - Filter bits" ] # [ inline ( always ) ] pub fn fb26 ( & mut self ) -> FB26_W { FB26_W { w : self } }
# [ doc = "Bit 27 - Filter bits" ] # [ inline ( always ) ] pub fn fb27 ( & mut self ) -> FB27_W { FB27_W { w : self } }
# [ doc = "Bit 28 - Filter bits" ] # [ inline ( always ) ] pub fn fb28 ( & mut self ) -> FB28_W { FB28_W { w : self } }
# [ doc = "Bit 29 - Filter bits" ] # [ inline ( always ) ] pub fn fb29 ( & mut self ) -> FB29_W { FB29_W { w : self } }
# [ doc = "Bit 30 - Filter bits" ] # [ inline ( always ) ] pub fn fb30 ( & mut self ) -> FB30_W { FB30_W { w : self } }                                                                                                                      # [ doc = "Bit 31 - Filter bits" ] # [ inline ( always ) ] pub fn fb31 ( & mut self ) -> FB31_W { FB31_W { w : self } }
}

As such, you may be better off not using quote / TokenStream for generating these files. Is it possible to produce a String directly instead?

For just the comments or the whole code in general? If there's a way how we can inject comments as a TokenStream that'd be certainly possible but I haven't found one...

@dtolnay
Copy link
Owner

dtolnay commented Nov 12, 2019

It would have to be the whole code, since there isn't a way for proc_macro2::TokenStream to represent /// comments.

Alternatively you could fork proc-macro2 and add a new token type for /// comments.

@therealprof
Copy link
Author

I might add a Comment type to proc-macro2 if there's a chance that would be accepted as part of the upstream project. The ability to generate and handle comments directly rather than interpolating through quote! seems like a quite useful feature to me.

@dtolnay
Copy link
Owner

dtolnay commented Nov 12, 2019

I don't think it would be accepted into proc-macro2; you would need to maintain a fork for svd2rust to use.

@therealprof
Copy link
Author

That's a complete non-starter for me. We'll probably have to unwind our gratuitous use of TokenStreams and turn them into Strings so we can mix in saner doc strings directly. It's a shame really that we cannot use existing tools to generate efficient Rust code but if that's what it's going to be so be it.

@dtolnay
Copy link
Owner

dtolnay commented Nov 12, 2019

Oh I just remembered about https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#normalize_doc_attributes, so if you are putting the result through nightly rustfmt then you can request for it to replace doc attributes with ///. Maybe a sed could even imitate this to some extent.

@R9295
Copy link

R9295 commented Aug 28, 2024

I found that this worked.
rustc 1.82.0-nightly (41dd149fd 2024-08-11)

#[doc = concat!("foo: ", stringify!(#bar))]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants