Skip to main content

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}