I wrote a proc-macro library to accompany a library I'm writing - they go together, with the former being used to abstract away a lot of redundant code in the latter.
I am successfully generating several structs and impls in my proc macro. I am also using cargo doc with the library, and my documentation is what I expect. However, the documentation comments I'm creating in my proc macro aren't working as expected. Some code from my proc macro looks roughly like this:
#[proc_macro_derive(MyDerive)]
pub fn derive(input: TokenStream) -> TokenStream {
...
let expanded = quote! {
...
impl #my_struct {
/// This comment doesn't show up in documentation
pub fn foo(&self, n: i32) -> bool {
false
}
/// This comment DOES show up in documentation
pub fn bar(n: i32) -> Vec<String> {
...
}
}
}
expanded.into()
}
When I open up the generated documentation:
foo itself shows up in the documentation, but its comment doesn't
bar and its comment are in the documentation
If I change the comment for bar, the comment is not updated.
This third point tells me that I probably used some cargo doc flag at some point that works correctly, but I'm now using a different set of flags that don't work with proc macros. I don't want to document all my external crate dependencies (--no-deps), but I do want to document my private items (--document-private-items). I'm therefore generating docs with cargo doc --no-deps --document-private-items. I've also tried with --release.
I assume documentation is built from the source code and not from the built .so file itself, so I haven't been doing cargo build before doing cargo doc, though I have also tried this to debug this issue. So what is the right way to make sure my proc macro-generated code's documentation gets properly generated and updated?
Related
Im following this tutorial, because I want to create a gstreamer plugin. I think the tutorial I a bit outdated, but the Cargo.toml files don't specify which versions they're using for the tutorial. I'm having some problems with glib, and I was hoping someone with more experience with glib could help me.
The tutorial prompts me to write the following lines.
I added the errors I'm getting, and the things I've already tried in the comments:
mod rgb2gray/imp
#[derive(Default)]
pub struct Rgb2Gray {}
impl Rgb2Gray {}
// This macro doesn't seem to exist
// I tried putting "glib::glib_object_subclass!();" inside the struct (???)
// after that I get: "the trait `glib::subclass::object::ObjectImpl` is not implemented for `rgb2gray::imp::Rgb2Gray`"
#[glib::object_subclass]
impl ObjectSubclass for Rgb2Gray {
const NAME: &'static str = "RsRgb2Gray";
type Type = super::Rgb2Gray; // TYPE is not a variable in ObjectSubclass
type ParentType = gst_base::BaseTransform;
}
mod rgb2gray
mod imp;
// Again, this macro doesn't seem to exist
// I tried glib::glib_wrapper
glib::wrapper! {
// The following line doesn't accept ObjectSubclass, it does accept Boxed, or Object, or Shared.
// I tried Object, but then it wants more information in the angle brackets... And I'm not sure what kind of information.
pub struct Rgb2Gray(ObjectSubclass<imp::Rgb2Gray>) #extends gst_base::BaseTransform, gst::Element, gst::Object;
}
// more code...
Did you compare it to the code at https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/tree/master/tutorial ? That one builds fine, so I assume that somewhere the code and the markdown are not in sync.
Judging from the error you wrote on above, you are using the latest release of glib and not the git version. See the Cargo.toml in there for how to select the git version.
If you're using the latest release you need the code/markdown from the 0.6 branch here: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/tree/0.6/tutorial
I'm very new to rust's syntax of using libraries. Well, mostly new to rust overall.
I've included a library, that is unfinished, and seemingly doesn't work. The library is called "hours", the lib.rs contains the following:
// #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Hours {
pub rules: Vec<types::RuleSequence>,
pub tz: Tz,
}
impl Hours {
pub fn from(s: &str, tz: Tz) -> Result<Self, String> {
//... abbreviated
}
pub fn at(self: &Self, dt: &DateTime<Tz>) -> types::Modifier {
//... abbreviated
}
}
It is included in Cargo.toml: relevant lines:
edition = "2018"
[dependencies]
hours = "0.0.1"
I want to know if it is possible to include and use the from() function, so far, I'm without luck. Here's what I tried:
use hours;
fn main() {
//... abbreviated
let hours = Hours::from(example_hrs, Amsterdam).unwrap();
}
Gives compile error: Hours::from(example_hrs, Amsterdam).unwrap(); ^^^^^ use of undeclared type or moduleHours``
use hours::Hours;
fn main() {
//... abbreviated
let hours = Hours::from(example_hrs, Amsterdam).unwrap();
}
Gives compile error: use hours::Hours; ^^^^^^^^^^^^ no ``Hours`` in the root
use hours;
fn main() {
//... abbreviated
let hours = hours::Hours::from(example_hrs, Amsterdam).unwrap();
}
Gives compile error: hours::Hours::from(example_hrs, Amsterdam).unwrap(); ^^^^^ could not findHoursinhours``
Is there any way to include and use this library? Do I need to change the library, or am I simply using it wrong?
Problem in here, the code in repository link you've shared doesn't match with the dependency in crates.io and naturally Rust can't find the required api components. In this case owner of the crate hasn't published the code in gitlab yet.
To see that you can quickly check the source from the docs.rs. This is the link for the required dependency docs.rs/crate/hours/0.0.1/source/.
If you want to use the current code in the repository
you may have it locally by downloading(or using git clone) then you can use it by specifying the path in cargo.toml
Or define git repository directly in cargo toml.
hours = { git = "https://gitlab.com/alantrick/hours.git", rev="7b7d369796c209db7b61db71aa7396f2ec59f942"}
Adding revision number or tag might help since the updates on master branch may break the compatibility.
Why this source in docs.rs is accurate with crates.io ?
Please check the about section in docs.rs :
Docs.rs automatically builds crates' documentation released on
crates.io using the nightly release of the Rust compiler
This means it is synchronized with crates.io.
To be sure you can also check the crate's source from a local repository cache.
## Note that this path is built with default cargo settings
$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/hours-0.0.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^ github reigstry for crates io
Why crate's repository link in crates.io doesn't match with the crate's source
Please check the publishing crate reference, repository information is specified in package's metadata(in cargo.toml).
According to package metadata reference these information are used for :
These URLs point to more information about the package. These are
intended to be webviews of the relevant data, not necessarily compatible
with VCS tools and the like.
documentation = "..."
homepage = "..."
repository = "..."
You may also check the popular crates as well, they point their github(usually) main page which points master branch, not a tag of the current version.
I'm interested in using wasm-bindgen via rust-webpack-template to compile Rust code to WebAssembly. However, I'd like to avoid directly wrapping my code with the #[wasm_bindgen] attribute macro directly so that I can separate out the function logic from the generated WebAssembly interface to better organize my project. Instead, I would prefer to have binding generation be in a separate file, for example:
mod my_code;
use my_code::my_function;
#[wasm_bindgen]
my_function; // I want to do something like this!
I understand that #[wasm_bindgen] is a macro attribute that operates on the AST of the function definition that usually follows, but is there an approach for applying that macro to code defined elsewhere?
As far as I know, there's no way to do this. Macros operate on the AST of the code they are attached to, and there's no code to be attached to here.
If you really need this, you'll have to copy-and-paste the signature of your function:
mod my_code {
pub fn my_function(_: i32) -> String {
unimplemented!()
}
}
#[wasm_bindgen]
fn my_function(a: i32) -> String {
my_code::my_function(a)
}
It's possible you could write a macro to make the wrapping slightly less tedious, but you'll still need to replicate the function name, argument types, and return type.
I'm creating a procedural macro that auto-generates a library from some configuration file (it's a register layout, but that's not important for the question).
I would like the library to auto-generate the documentation accompanying the auto-library and include doc tests that should run with cargo test. Now, I've implemented most of this, but there is one issue I can't see a solution to.
Say we have a library called my_lib in which we invoke the macro to populate it:
use my_macro_lib::hello;
hello!();
which expands to something like:
/// `foo` will always return `true`
/// ```
/// use my_lib;
/// assert!(my_lib::foo());
/// ```
pub fn foo() -> bool {
true
}
This will run as expected - cargo doc will do the right thing and cargo test will run the doctests as expected.
The problem is that in this example, use my_lib is hard-coded into the my_macro_lib which is clearly undesirable.
How can I create a macro which infers the name of crate that is doing the calling?
I tried using a macro_rules! inside the procedural macro to expand $crate, but this breaks the hygiene rules.
You can obtain the name of the crate that is using your macro by reading the CARGO_PKG_NAME environment variable. Note that you have to read it via
std::env (at "runtime" of your macro) and not via env! (which would be when your proc macro crate is compiled).
#[proc_macro]
pub fn hello(input: TokenStream) -> TokenStream {
let crate_name = std::env::var("CARGO_PKG_NAME").unwrap();
let use_statement = format!("use {}::foo;", crate_name);
let output = quote! {
/// `foo` will always return `true`
/// ```
#[doc = #use_statement]
/// assert!(foo());
/// ```
pub fn foo() -> bool {
true
}
};
output.into()
}
There are a few complications here regarding interpolating things in doc comments. Interpolating like /// #an_ident does not work as doc comments are parsed in a special way. The only way we can do this is to create a string and using the #[doc = ...] syntax. It's a bit annoying because you have to create strings before the quote! invocation, but it works.
However, I don't think it is guaranteed that this works. Currently proc macros can access all of the environment (including the file system, network, ...). To my knowledge, proc macros aren't guaranteed this access and proc macros might be sandboxed in the future. So this solution is not perfect yet, but it works for now (and probably for quite some time still).
An alternative would be to just let the user pass the crate name to your macro:
hello!(my_lib);
If your macro is only invoked once per crate, this is probably the preferred solution. If your macro is invoked a lot, then repeating the crate name might be annoying.
I'm building a Rust library and want to give it some polish. In the rustdoc, I'd sometimes like to link to other parts of the library within the docs, e.g. fns, traits or structs. What is the official syntax for this?
As of Rust 1.48, you can now rely on RFC 1946. This adds the concept of intra-documentation links. This allows using Rust paths as the URL of a link:
[Iterator](std::iter::Iterator)
[Iterator][iter], and somewhere else in the document: [iter]: std::iter::Iterator
[Iterator], and somewhere else in the document: [Iterator]: std::iter::Iterator
The RFC also introduces "Implied Shortcut Reference Links". This allows leaving out the link reference, which is then inferred automatically.
[std::iter::Iterator], without having a link reference definition for Iterator anywhere else in the document
[`std::iter::Iterator`], without having a link reference definition for Iterator anywhere else in the document (same as previous style but with back ticks to format link as inline code)
As a concrete example, this source code:
//! Check out [ExampleStruct], especially [this
//! method](ExampleStruct::foo), but [the trait method][trait] is also
//! cool. There is also [an enum variant you can
//! use](nested::ExampleEnum::Beta).
//!
//! [trait]: ExampleTrait::bar
pub struct ExampleStruct;
impl ExampleStruct {
pub fn foo(&self) {}
}
pub trait ExampleTrait {
fn bar();
}
pub mod nested {
pub enum ExampleEnum {
Alpha,
Beta,
}
}
Produces this documentation:
Specifically, this HTML is generated:
<p>Check out ExampleStruct, especially this method, but the trait method is also cool. There is also an enum variant you can use.</p>
As of Rust 1.48, Rustdoc now supports direct intra-doc links.
Pre Rust 1.48:
Rustdoc seems to generate mostly deterministic filenames for constituent elements of a crate. Therefore if you have an enum named Complex you can generally link to it using:
[Complex](enum.Complex.html)
Similarly a struct called Point would look like:
[Point](struct.Point.html)
This should carry over to most definitions (fn, trait, and so on).
For referencing elements of a crate at different nesting levels, you can use relative paths (where each module is its own folder):
[Point](../model/struct.Point.html)
or use absolute paths:
[Point](/crate_name/model/struct.Point.html)
More of these "conventions", including anchors for specific fields, etc., can be deduced if one builds docs (cargo doc --no-deps --open) and navigates to the field or item they want and takes note of the URL. Remember that only pub items are published to docs.
If one wants to link some specific part of a struct e.g., a method named foo in the same struct (using stable rust, not nightly)
[foo](#method.foo)
or if it is in another struct
[foo](struct.OtherStruct.html#method.foo)
In Rust 1.49 nightly it works (1.48 stable not released yet):
[super::structs::WebApiResponse]
[mycrate::structs::WebApiResponse]
etc.
Read here
Since the documentation is written in Markdown, just use the Markdown syntax for Hyperlinks; i.e.
[anchor text](URL)
Also, take a look at this: https://doc.rust-lang.org/book/documentation.html