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