1//
2// Doc comment
3//
4// Copyright (c) 2018 Guillaume Gomez
5//
6
7#![cfg_attr(feature = "no_core", feature(no_core))]
8#![cfg_attr(feature = "no_core", no_core)]
9#![cfg_attr(not(feature = "no_core"), no_std)]
10
11//! The point of this (small) crate is to allow you to add doc comments from macros or
12//! to test external markdown files' code blocks through `rustdoc`.
13//!
14//! ## Including file(s) for testing
15//!
16//! Let's assume you want to test code examples in your `README.md` file which
17//! looks like this:
18//!
19//! ````text
20//! # A crate
21//!
22//! Here is a code example:
23//!
24//! ```rust
25//! let x = 2;
26//! assert!(x != 0);
27//! ```
28//! ````
29//!
30//! You can use the `doc_comment!` macro to test it like this:
31//!
32//! ```
33//! #[macro_use]
34//! extern crate doc_comment;
35//!
36//! // When running `cargo test`, rustdoc will check this file as well.
37//! doc_comment!(include_str!("../README.md"));
38//! # fn main() {}
39//! ```
40//!
41//! Please note that can also use the `doctest!` macro to have a shorter way to test an outer
42//! file:
43//!
44//! ```no_run
45//! #[macro_use]
46//! extern crate doc_comment;
47//!
48//! doctest!("../README.md");
49//! # fn main() {}
50//! ```
51//!
52//! Please also note that you can use `#[cfg(doctest)]`:
53//!
54//! ```no_run
55//! # #[macro_use]
56//! # extern crate doc_comment;
57//! #[cfg(doctest)]
58//! doctest!("../README.md");
59//! # fn main() {}
60//! ```
61//!
62//! In this case, the examples in the `README.md` file will only be run on `cargo test`. You
63//! can find more information about `#[cfg(doctest)]` in [this blogpost](https://blog.guillaume-gomez.fr/articles/2020-03-07+cfg%28doctest%29+is+stable+and+you+should+use+it).
64//!
65//! ## Generic documentation
66//!
67//! Now let's imagine you want to write documentation once for multiple types but
68//! still having examples specific to each type:
69//!
70//! ```
71//! // The macro which generates types
72//! macro_rules! gen_types {
73//! ($tyname:ident) => {
74//! /// This is a wonderful generated struct!
75//! ///
76//! /// You can use it as follow:
77//! ///
78//! /// ```
79//! /// let x = FirstOne {
80//! /// field1: 0,
81//! /// field2: 0,
82//! /// field3: 0,
83//! /// field4: 0,
84//! /// };
85//! ///
86//! /// println!("Created a new instance of FirstOne: {:?}", x);
87//! /// ```
88//! #[derive(Debug)]
89//! pub struct $tyname {
90//! pub field1: u8,
91//! pub field2: u16,
92//! pub field3: u32,
93//! pub field4: u64,
94//! }
95//! }
96//! }
97//!
98//! // Now let's actually generate types:
99//! gen_types!(FirstOne);
100//! gen_types!(SecondOne);
101//! gen_types!(Another);
102//! ```
103//!
104//! So now we have created three structs with different names, but they all have the exact same
105//! documentation, which is an issue for any structs not called `FirstOne`. That's where
106//! [`doc_comment!`] macro comes in handy!
107//!
108//! Let's rewrite the `gen_types!` macro:
109//!
110//! // Of course, we need to import the `doc_comment` macro:
111//! #[macro_use]
112//! extern crate doc_comment;
113//!
114//! macro_rules! gen_types {
115//! ($tyname:ident) => {
116//! doc_comment! {
117//! concat!("This is a wonderful generated struct!
118//!
119//! You can use it as follow:
120//!
121//! ```
122//! let x = ", stringify!($tyname), " {
123//! field1: 0,
124//! field2: 0,
125//! field3: 0,
126//! field4: 0,
127//! };
128//!
129//! println!(\"Created a new instance of ", stringify!($tyname), ": {:?}\", x);
130//! ```"),
131//! #[derive(Debug)]
132//! pub struct $tyname {
133//! pub field1: u8,
134//! pub field2: u16,
135//! pub field3: u32,
136//! pub field4: u64,
137//! }
138//! }
139//! }
140//! }
141//!
142//! gen_types!(FirstOne);
143//! gen_types!(SecondOne);
144//! gen_types!(Another);
145//! # fn main() {}
146//!
147//! Now each struct has doc which match itself!
148
149/// This macro can be used to generate documentation upon a type/item (or just to test outer
150/// markdown file code examples).
151///
152/// # Example
153///
154/// ```
155/// #[macro_use]
156/// extern crate doc_comment;
157///
158/// // If you just want to test an outer markdown file:
159/// doc_comment!(include_str!("../README.md"));
160///
161/// // If you want to document an item:
162/// doc_comment!("fooo", pub struct Foo {});
163/// # fn main() {}
164/// ```
165#[macro_export]
166macro_rules! doc_comment {
167 ($x:expr) => {
168 #[doc = $x]
169 extern {}
170 };
171 ($x:expr, $($tt:tt)*) => {
172 #[doc = $x]
173 $($tt)*
174 };
175}
176
177/// This macro provides a simpler way to test an outer markdown file.
178///
179/// # Example
180///
181/// ```
182/// extern crate doc_comment;
183///
184/// // The two next lines are doing exactly the same thing:
185/// doc_comment::doc_comment!(include_str!("../README.md"));
186/// doc_comment::doctest!("../README.md");
187///
188/// // If you want to have a name for your tests:
189/// doc_comment::doctest!("../README.md", another);
190/// # fn main() {}
191/// ```
192#[cfg(not(feature = "old_macros"))]
193#[macro_export]
194macro_rules! doctest {
195 ($x:expr) => {
196 doc_comment::doc_comment!(include_str!($x));
197 };
198 ($x:expr, $y:ident) => {
199 doc_comment::doc_comment!(include_str!($x), mod $y {});
200 };
201}
202
203/// This macro provides a simpler way to test an outer markdown file.
204///
205/// # Example
206///
207/// ```
208/// #[macro_use]
209/// extern crate doc_comment;
210///
211/// // The two next lines are doing exactly the same thing:
212/// doc_comment!(include_str!("../README.md"));
213/// doctest!("../README.md");
214///
215/// // If you want to have a name for your tests:
216/// doctest!("../README.md", another);
217/// # fn main() {}
218/// ```
219#[cfg(feature = "old_macros")]
220#[macro_export]
221macro_rules! doctest {
222 ($x:expr) => {
223 doc_comment!(include_str!($x));
224 };
225 ($x:expr, $y:ident) => {
226 doc_comment!(include_str!($x), mod $y {});
227 };
228}
229