scsys_derive/
lib.rs

1/*
2    Appellation: scsys-derive <library>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5//! # scsys-derive
6//!
7//! This crate implements the derive macros for the `scsys` ecosystem.
8//!
9//! ## Macros
10//!
11//! - [`Display`]: automatically implements the `Display` trait for a struct or enum, using the
12//!   `scsys` attributes to customize the output.
13//! - [`VariantConstructors`]: generate functional constructors for all variants of an enum
14#![allow(
15    non_snake_case,
16    clippy::module_inception,
17    clippy::missing_safety_doc,
18    clippy::needless_doctest_main,
19    clippy::upper_case_acronyms
20)]
21#![doc(
22    html_logo_url = "https://raw.githubusercontent.com/scattered-systems/.github/main/assets/logo.png",
23    html_favicon_url = "https://raw.githubusercontent.com/scattered-systems/.github/main/assets/favicon.ico"
24)]
25extern crate proc_macro;
26extern crate quote;
27extern crate syn;
28
29pub(crate) mod attrs;
30pub(crate) mod impls;
31pub(crate) mod utils;
32
33pub(crate) mod ast;
34use proc_macro::TokenStream;
35use syn::{Data, DeriveInput, parse_macro_input};
36
37/// the [`Display`] macro automatically implements the [`Display`](core::fmt::Display) trait
38/// for a struct or enum, using the `scsys` attributes to customize the output.
39///
40/// ## Examples
41///
42/// ### _Example #1: Using the `json` attribute_
43///
44/// ```rust
45/// use scsys_derive::Display;
46///
47/// #[derive(Display, serde::Deserialize, serde::Serialize)]
48/// #[scsys(json)]
49/// pub struct MyStruct {
50///     pub name: String,
51///     pub age: u32,
52/// }
53///
54/// fn main() {
55///     let my_struct = MyStruct {
56///         name: "Alice".to_string(),
57///         age: 30,
58///     };
59///
60///    // This will print the struct in JSON format
61///     println!("{}", my_struct);
62/// }
63/// ```
64///
65/// #### Output:
66///
67/// ```json
68/// {"name": "Alice", "age": 30}
69/// ```
70///
71///
72/// **note:** for now, the primary use case is to automatically implement the `Display` trait
73/// for implementors of both `Deserialize` and `Serialize` from [`serde`](https://serde.rs),
74///
75#[proc_macro_derive(Display, attributes(scsys))]
76pub fn display(input: TokenStream) -> TokenStream {
77    // Parse the inputs into the proper struct
78    let ast = parse_macro_input!(input as DeriveInput);
79
80    // Build the impl
81    let res = impls::impl_display(&ast);
82
83    res.into()
84}
85
86#[deprecated(since = "0.3.2", note = "use the variants crate instead")]
87/// This macro automatically generates functional constructors for all enclosed variants.
88#[proc_macro_derive(VariantConstructors, attributes(scsys))]
89pub fn variant_constructors(input: TokenStream) -> TokenStream {
90    let ast: DeriveInput = syn::parse(input).unwrap();
91
92    match ast.data {
93        Data::Enum(inner) => impls::impl_functional_constructors(&ast.ident, &inner.variants),
94        _ => panic!("This derive macro only works with enums"),
95    }
96    .into()
97}
98/// The [`Wrapper`] macro is designed for single-field structs, implementing additional methods
99/// supporting interactions with the inner value
100#[proc_macro_derive(Wrapper, attributes(scsys))]
101pub fn wrapper(input: TokenStream) -> TokenStream {
102    // Parse the inputs into the proper struct
103    let ast = parse_macro_input!(input as DeriveInput);
104
105    // Build the impl
106    let res = impls::impl_wrapper(&ast);
107
108    res.into()
109}
110
111#[proc_macro_derive(Getter, attributes(scsys))]
112pub fn derive_getter(input: TokenStream) -> TokenStream {
113    let input = parse_macro_input!(input as DeriveInput);
114
115    let get = impls::impl_getter(&input);
116    let get_mut = impls::impl_getter_mut(&input);
117
118    let merged = quote::quote! {
119        #get
120        #get_mut
121    };
122
123    merged.into()
124}
125
126#[proc_macro_derive(Get, attributes(scsys))]
127pub fn derive_get(input: TokenStream) -> TokenStream {
128    let input = parse_macro_input!(input as DeriveInput);
129    impls::impl_getter(&input).into()
130}
131
132#[proc_macro_derive(GetMut, attributes(scsys))]
133pub fn derive_get_mut(input: TokenStream) -> TokenStream {
134    let input = parse_macro_input!(input as DeriveInput);
135    impls::impl_getter_mut(&input).into()
136}
137
138#[proc_macro_derive(Set, attributes(scsys))]
139pub fn derive_set(input: TokenStream) -> TokenStream {
140    let input = parse_macro_input!(input as DeriveInput);
141    impls::impl_set(&input).into()
142}
143
144#[proc_macro_derive(With, attributes(scsys))]
145pub fn derive_with(input: TokenStream) -> TokenStream {
146    let input = parse_macro_input!(input as DeriveInput);
147    impls::impl_with(&input).into()
148}