Expand description
§doc_for
[WARNING] This crate is still in development, and the API is subject to BREAKING CHANGES.
📖 Get the documentation comment for structs, enums and unions, in a zero-cost fashion.
§🪄 Features
- Zero-cost: All work is done at compile-time
- Simple: Just annotate your struct with
#[doc_impl]and use thedoc_for!ordoc!macro
§🤔 Usage
§Get the documentation comment for a type
First, bring doc_for and doc_impl into scope:
use doc_for::{doc_for, doc_impl};Then, annotate your struct with #[doc_impl] attribute macro:
/// Some documentation
#[doc_impl]
struct MyStruct {
field: i32,
}Finally, use the doc_for! macro to get the documentation comment, which returns an Option<&'static str>:
assert_eq!(doc_for!(MyStruct).unwrap(), " Some documentation");Note that the leading spaces are preserved. Multi-line comments are also supported:
/// Some documentation
/// that spans multiple lines
///
/// Additional information
#[doc_impl]
struct MyStruct {
field: i32,
}
assert_eq!(doc_for!(MyStruct).unwrap(), r#" Some documentation
that spans multiple lines
Additional information"#);If the type does not have a documentation comment, doc_for! will return None:
// No documentation comment here
#[doc_impl]
struct MyStruct {
field: i32,
}
assert!(doc_for!(MyStruct).is_none());Also works with tuple structs, enums and unions:
/// Tuple struct documentation
#[doc_impl]
struct MyTupleStruct(i32);
assert_eq!(doc_for!(MyTupleStruct).unwrap(), " Tuple struct documentation");
/// Enum documentation
#[doc_impl]
enum MyEnum {
Variant,
}
assert_eq!(doc_for!(MyEnum).unwrap(), " Enum documentation");
/// Union documentation
#[doc_impl]
union MyUnion {
field: i32,
}
assert_eq!(doc_for!(MyUnion).unwrap(), " Union documentation");§Get the documentation comment for fields and variants
Same as before, bring doc_impl and doc_for! into scope and annotate your struct with #[doc_impl] attribute macro:
use doc_for::{doc_for, doc_impl};
#[doc_impl]
struct MyStruct {
/// Field documentation
field: i32,
not_documented: i32,
}Then, use the doc_for! macro to get the documentation comment. If the field does not have a documentation comment, doc_for! will return None:
assert_eq!(doc_for!(MyStruct, field).unwrap(), " Field documentation");
assert!(doc_for!(MyStruct, not_documented).is_none());If the field or variant does not exist, doc_for! will panic, thus failing the compilation:
// Won't compile due to `Field or variant does not exist`
assert_eq!(doc_for!(MyStruct, non_existent), None);Similarly, it also works with union fields (not listed here), enum variants and tuple struct fields:
#[doc_impl]
enum MyEnum {
/// Variant documentation
Variant,
NotDocumented,
}
assert_eq!(doc_for!(MyEnum, Variant).unwrap(), " Variant documentation");
assert!(doc_for!(MyEnum, NotDocumented).is_none());
// Won't compile due to `Field or variant does not exist`
// assert_eq!(doc_for!(MyEnum, NonExistent), None);
#[doc_impl]
struct MyTupleStruct(
/// Tuple struct field documentation
i32,
i32,
);
assert_eq!(doc_for!(MyTupleStruct, 0).unwrap(), " Tuple struct field documentation");
assert!(doc_for!(MyTupleStruct, 1).is_none());
// Won't compile due to `Field or variant does not exist`
// assert_eq!(doc_for!(MyTupleStruct, 2), None);§Stripping the documentation comment
The strip attribute can be used to strip leading whitespace characters of the documentation comment. If all, all will be stripped; if n, at most n whitespace characters will be stripped. Default is 0.
use doc_for::{doc_for, doc_impl};
/// Some documentation
#[doc_impl(strip = 1)]
struct MyStruct {
field: i32,
}
assert_eq!(doc_for!(MyStruct).unwrap(), "Some documentation");
/// Two leading spaces
#[doc_impl(strip = 1)]
struct TwoLeadingSpaces {
field: i32,
}
assert_eq!(doc_for!(TwoLeadingSpaces).unwrap(), " Two leading spaces");
/// Too many spaces
#[doc_impl(strip = all)]
struct TooManySpaces {
field: i32,
}
assert_eq!(doc_for!(TooManySpaces).unwrap(), "Too many spaces");§If you don’t care about the Option
The doc! macro is basically doc_for! with unwrap:
use doc_for::{doc, doc_impl};
#[doc_impl]
struct MyStruct {
/// Field documentation
field: i32,
not_documented: i32,
}
assert_eq!(doc!(MyStruct, field), " Field documentation");…So it panics and fails the compilation if the requested type or field is not documented:
// Won't compile due to `The type is not documented`
println!("{}", doc!(MyStruct));// Won't compile due to `The field is not documented`
println!("{}", doc!(MyStruct, not_documented));Of course, trying to access a non-existent field or variant will also fail the compilation:
// Won't compile due to `Field or variant does not exist`
println!("{}", doc!(MyStruct, non_existent));§Get the documentation comment for an enum variant
This time, bring DocDyn and doc_impl into scope:
use doc_for::{DocDyn, doc_impl};Then, annotate your enum with #[doc_impl(doc_for = false, doc_dyn = true)]:
#[doc_impl(doc_for = false, doc_dyn = true)]
enum MyEnum {
/// Variant documentation
Variant,
NotDocumented,
}Finally, call the doc_dyn method on the enum variant:
assert_eq!(MyEnum::Variant.doc_dyn().unwrap(), " Variant documentation");
assert!(MyEnum::NotDocumented.doc_dyn().is_none());Note that this method is not zero-cost, as it matches the enum variant at runtime.
To use both doc_for! and doc_dyn on the same enum, annotate it with #[doc_impl(doc_dyn = true)]. You can include doc_for = true if you want, but since it’s the default, it’s not necessary.
#[doc_impl(doc_dyn = true, strip = 1)]
enum MyEnum {
/// Variant documentation
Variant,
NotDocumented,
}
assert_eq!(doc_for!(MyEnum, Variant).unwrap(), "Variant documentation");
assert_eq!(MyEnum::Variant.doc_dyn().unwrap(), "Variant documentation");§Automatically generate attribute macros with documentation as parameters
Consider the following scenario:
use thiserror::Error;
#[derive(Debug, Error)]
enum MyError {
/// Error1 message
#[error("Error1 message")]
Error1,
/// Error2 message
#[error("Error2 message")]
Error2,
}Which seems quite repetitive. Luckily, doc_impl provides a way to automatically generate those repetitive attribute macros. Simply append gen_attr = "your_attr({doc})", and respective documentation will take the place of {doc}:
use doc_for::doc_impl;
use thiserror::Error;
/// Some documentation
#[doc_impl(strip = 1, doc_for = false, gen_attr = "error({doc})")]
#[derive(Debug, Error)]
enum MyError {
/// Error1 message
Error1,
/// Error2 message
Error2,
}
assert_eq!(format!("{}", MyError::Error1), "Error1 message");
assert_eq!(format!("{}", MyError::Error2), "Error2 message");Also works on struct fields, where you might want to generate #[serde(rename = "...")] attributes:
use doc_for::doc_impl;
use serde::Deserialize;
/// Some documentation
#[doc_impl(strip = 1, doc_for = false, gen_attr = "serde(rename = {doc})")]
#[derive(Deserialize)]
struct MyStruct {
/// field1_rename
// No need for #[serde(rename = "field1_rename")]
field1: i32,
/// field2_rename
// No need for #[serde(rename = "field2_rename")]
field2: i32,
}
let json = r#"{"field1_rename": 1, "field2_rename": 2}"#;
let my_struct: MyStruct = serde_json::from_str(json).unwrap();
assert_eq!(my_struct.field1, 1);
assert_eq!(my_struct.field2, 2);Do note that:
doc_implannotation must be placed BEFORE attribute macros that introduced the target attribute.gen_attrcan be used multiple times.
§The derive alternative
If you prefer to use derive, you can use DocFor and DocDyn to replace doc_for and doc_dyn respectively:
use doc_for::{DocDyn, DocFor, doc_for};
#[derive(DocFor, DocDyn)]
/// Some documentation
enum MyEnum {
/// Variant documentation
Variant,
NotDocumented,
}
assert_eq!(doc_for!(MyEnum).unwrap(), " Some documentation");
assert_eq!(doc_for!(MyEnum, Variant).unwrap(), " Variant documentation");
assert_eq!(MyEnum::Variant.doc_dyn().unwrap(), " Variant documentation");However, you won’t be able to configure the strip and gen_attr attribute in this case.
§⚙️ Implementation
§DocFor and doc_for!
The doc_for crate provides a DocFor trait and a doc_for! macro:
- The
DocFortrait requires an associated constantDOCto be implemented for the type - Deriving the
DocFortrait sets theDOCconstant as the documentation comment of the type, and generates aconst fn doc_for_field(name) -> Option<&'static str>function- Currently Rust doesn’t support constant functions in traits, so the
doc_for_fieldfunction is implemented directly on the annotated type - If the annotated type is a struct, union or enum, the
nameparameter accepts a&'static str - If the annotated type is a tuple struct, the
nameparameter accepts anusize
- Currently Rust doesn’t support constant functions in traits, so the
- If given a type, the
doc_for!macro retrieves the value of this constant; If given a type and a field name, thedoc_for!macro calls thedoc_for_fieldfunction with the given field name
Using these APIs is zero-cost, as all the work is done at compile-time:
- When compiled, types that derive
DocForwill have their documentation comments inlined as associated constants or in constant functions - Calls to
doc_for!will be replaced with the value of the associated constant or the result of the constant function
§DocDyn and doc_dyn
The doc_for crate also provides a DocDyn trait and a doc_dyn method:
- The
DocDyntrait requires adoc_dynmethod to be implemented for the type, which returns anOption<&'static str> - Deriving the
DocDyntrait generates adoc_dynmethod, which returns the documentation comment that matches the variant of the enum
This method is not zero-cost, as it matches the enum variant at runtime.
§doc_impl
The doc_impl attribute macro is used to derive the DocFor and DocDyn traits for a type, along with configuring the strip attribute. gen_attr attribute, when set, prepends the specified attribute macros to fields or variants.
§✅ TODO
-
Strip each line of the documentation comment, via a
stripattribute - Better error reporting and handling
-
Access module documentation (e.g.
doc_for!(my_module)) -
Access trait documentation (e.g.
doc_for!(MyTrait)) -
Access sub-item documentation
-
Access field documentation (e.g.
doc_for!(MyStruct, field)ordoc_for!(MyUnion, field)) -
Access tuple struct field documentation (e.g.
doc_for!(MyTupleStruct, 0)) -
Access enum variant documentation (statically) (e.g.
doc_for!(MyEnum, Variant)) -
Access enum variant documentation (dynamically) (e.g.
doc_for!(my_enum_variant)) -
Access method documentation (e.g.
doc_for!(MyStruct, method)) -
Access associated constant documentation (e.g.
doc_for!(MyStruct, CONSTANT)) -
Access associated type documentation (e.g.
doc_for!(MyStruct, Type))
-
Access field documentation (e.g.
Macros§
- doc
- Get the documentation comment for a type or its fields. Basically
doc_for!withunwrap. - doc_for
- Get the documentation comment for a type or its fields, returning
Noneif not documented.
Traits§
- DocDyn
- Trait for enums that allows getting the documentation comment for the variant.
- DocFor
- Trait for types that allows getting the documentation comment for the type.
Attribute Macros§
- doc_
impl - Derives the
DocFortrait anddoc_for_fieldmethod for a type.