virtue_next/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// =========================================================================
72// RUST LINT CONFIGURATION: bincode-next -- virtue
73// =========================================================================
74
75// -------------------------------------------------------------------------
76// LEVEL 1: CRITICAL ERRORS (Deny)
77// -------------------------------------------------------------------------
78#![deny(
79 // Rust Compiler Errors
80 dead_code,
81 unreachable_code,
82 improper_ctypes_definitions,
83 future_incompatible,
84 nonstandard_style,
85 rust_2018_idioms,
86 clippy::perf,
87 clippy::correctness,
88 clippy::suspicious,
89 clippy::unwrap_used,
90 clippy::expect_used,
91 clippy::indexing_slicing,
92 clippy::arithmetic_side_effects,
93 clippy::missing_safety_doc,
94 clippy::same_item_push,
95 clippy::implicit_clone,
96 clippy::all,
97 clippy::pedantic,
98 warnings,
99 missing_docs,
100 clippy::nursery,
101 clippy::single_call_fn,
102)]
103// -------------------------------------------------------------------------
104// LEVEL 2: STYLE WARNINGS (Warn)
105// -------------------------------------------------------------------------
106#![warn(
107 unsafe_code,
108 clippy::dbg_macro,
109 clippy::todo,
110 clippy::unnecessary_safety_comment
111)]
112// -------------------------------------------------------------------------
113// LEVEL 3: ALLOW/IGNORABLE (Allow)
114// -------------------------------------------------------------------------
115#![allow(
116 clippy::restriction,
117 clippy::inline_always,
118 unused_doc_comments,
119 clippy::empty_line_after_doc_comments
120)]
121
122mod error;
123
124pub mod generate;
125pub mod parse;
126pub mod utils;
127
128/// Result alias for virtue's errors
129pub type Result<T = ()> = std::result::Result<T, Error>;
130
131pub use self::error::Error;
132
133/// Useful includes
134pub mod prelude {
135 pub use crate::generate::{FnSelfArg, Generator, StreamBuilder};
136 pub use crate::parse::{
137 AttributeAccess, Body, EnumVariant, Fields, FromAttribute, Parse, UnnamedField,
138 };
139 pub use crate::{Error, Result};
140
141 #[cfg(any(test, feature = "proc-macro2"))]
142 pub use proc_macro2::*;
143
144 #[cfg(not(any(test, feature = "proc-macro2")))]
145 extern crate proc_macro;
146 #[cfg(not(any(test, feature = "proc-macro2")))]
147 pub use proc_macro::*;
148}
149
150#[cfg(test)]
151pub(crate) fn token_stream(
152 s: &str,
153) -> std::iter::Peekable<impl Iterator<Item = proc_macro2::TokenTree> + use<>> {
154 use std::str::FromStr;
155
156 let stream = proc_macro2::TokenStream::from_str(s)
157 .unwrap_or_else(|e| panic!("Could not parse code: {:?}\n{:?}", s, e));
158 stream.into_iter().peekable()
159}