virtue/lib.rs
1//! # Virtue, a sinless derive macro helper
2//!
3//! ## Goals
4//!
5//! - Zero dependencies, so fast compile times
6//! - No other dependencies needed
7//! - Declarative code generation
8//! - As much typesystem checking as possible
9//! - Build for modern rust: 1.57 and up
10//! - Build with popular crates in mind:
11//! - [bincode](https://docs.rs/bincode)
12//! - Will always respect semver. Minor releases will never have:
13//! - Breaking API changes
14//! - MSRV changes
15//!
16//! ## Example
17//!
18//! First, add this to your Cargo.toml:
19//! ```toml
20//! [lib]
21//! proc-macro = true
22//! ```
23//!
24//! Then instantiate your project with:
25//!
26//! ```ignore
27//! use virtue::prelude::*;
28//!
29//! #[proc_macro_derive(RetHi)] // change this to change your #[derive(...)] name
30//! pub fn derive_ret_hi(input: TokenStream) -> TokenStream {
31//! derive_ret_hi_inner(input).unwrap_or_else(|error| error.into_token_stream())
32//! }
33//!
34//! fn derive_ret_hi_inner(input: TokenStream) -> Result<TokenStream> {
35//! let parse = Parse::new(input)?;
36//! let (mut generator, _attributes, _body) = parse.into_generator();
37//! generator
38//! .generate_impl()
39//! .generate_fn("hi")
40//! .with_self_arg(FnSelfArg::RefSelf)
41//! .with_return_type("&'static str")
42//! .body(|body| {
43//! body.lit_str("hi");
44//! Ok(())
45//! })?;
46//! generator.finish()
47//! }
48//! ```
49//!
50//! You can invoke this with
51//!
52//! ```ignore
53//! #[derive(RetHi)]
54//! struct Foo;
55//!
56//! fn main() {
57//! println!("{}", Foo.hi());
58//! }
59//! ```
60//!
61//! The generated code is:
62//!
63//! ```ignore
64//! impl Foo {
65//! fn hi(&self) -> &'static str {
66//! "hi"
67//! }
68//! }
69//! ```
70#![warn(missing_docs)]
71
72mod error;
73
74pub mod generate;
75pub mod parse;
76pub mod utils;
77
78/// Result alias for virtue's errors
79pub type Result<T = ()> = std::result::Result<T, Error>;
80
81pub use self::error::Error;
82
83/// Useful includes
84pub mod prelude {
85 pub use crate::generate::{FnSelfArg, Generator, StreamBuilder};
86 pub use crate::parse::{
87 AttributeAccess, Body, EnumVariant, Fields, FromAttribute, Parse, UnnamedField,
88 };
89 pub use crate::{Error, Result};
90
91 #[cfg(any(test, feature = "proc-macro2"))]
92 pub use proc_macro2::*;
93
94 #[cfg(not(any(test, feature = "proc-macro2")))]
95 extern crate proc_macro;
96 #[cfg(not(any(test, feature = "proc-macro2")))]
97 pub use proc_macro::*;
98}
99
100#[cfg(test)]
101pub(crate) fn token_stream(
102 s: &str,
103) -> std::iter::Peekable<impl Iterator<Item = proc_macro2::TokenTree>> {
104 use std::str::FromStr;
105
106 let stream = proc_macro2::TokenStream::from_str(s)
107 .unwrap_or_else(|e| panic!("Could not parse code: {:?}\n{:?}", s, e));
108 stream.into_iter().peekable()
109}