spider_macro/lib.rs
1//! # spider-macro
2//!
3//! Provides procedural macros for the `spider-lib` framework to reduce boilerplate code.
4//!
5//! ## Overview
6//!
7//! The `spider-macro` crate contains procedural macros that automate the
8//! implementation of common traits and patterns used in the spider framework.
9//! These macros significantly reduce the amount of boilerplate code required
10//! when defining custom data structures for scraped items and spider state.
11//!
12//! ## Key Macros
13//!
14//! - **`#[scraped_item]`**: Derives the `ScrapedItem` trait along with necessary
15//! implementations for serialization, deserialization, cloning, and type
16//! conversions.
17//!
18//! ## Features
19//!
20//! - **Automatic Trait Derivation**: Implements `Serialize`, `Deserialize`,
21//! `Clone`, and `Debug` traits automatically
22//! - **ScrapedItem Implementation**: Provides the complete implementation of
23//! the `ScrapedItem` trait required by the framework
24//! - **Type Safety**: Maintains type safety while reducing boilerplate
25//! - **Performance**: Generates efficient code without runtime overhead
26//!
27//! ## Dependencies
28//!
29//! When using this macro, your project must include the following dependencies:
30//!
31//! ```toml
32//! [dependencies]
33//! spider-lib = "1.1.1"
34//! serde = { version = "1.0", features = ["derive"] }
35//! serde_json = "1.0"
36//! ```
37//!
38//! ## Example
39//!
40//! ```rust,ignore
41//! use spider_lib::prelude::*;
42//!
43//! #[scraped_item]
44//! struct Article {
45//! title: String,
46//! content: String,
47//! author: String,
48//! published_date: String,
49//! }
50//!
51//! // The macro generates all necessary implementations automatically
52//! // including serialization, deserialization, and the ScrapedItem trait
53//! //
54//! // Note: Make sure your Cargo.toml includes serde and serde_json as dependencies
55//! ```
56
57extern crate proc_macro;
58
59use proc_macro::TokenStream;
60use quote::quote;
61use syn::{ItemStruct, parse_macro_input};
62
63/// A procedural macro to derive the `ScrapedItem` trait.
64///
65/// This macro:
66/// 1. Implements the ScrapedItem trait
67/// 2. Adds serde Serialize and Deserialize derives
68/// 3. Makes use of items that should be in scope via prelude import
69///
70/// # Dependencies
71///
72/// Your project must include `serde` and `serde_json` as direct dependencies:
73///
74/// ```toml
75/// [dependencies]
76/// serde = { version = "1.0", features = ["derive"] }
77/// serde_json = "1.0"
78/// ```
79#[proc_macro_attribute]
80pub fn scraped_item(_attr: TokenStream, item: TokenStream) -> TokenStream {
81 let ast = parse_macro_input!(item as ItemStruct);
82 let name = &ast.ident;
83
84 let expanded = quote! {
85 #[derive(
86 ::serde::Serialize,
87 ::serde::Deserialize,
88 Clone,
89 Debug
90 )]
91 #ast
92
93 impl ScrapedItem for #name {
94 fn as_any(&self) -> &dyn ::std::any::Any {
95 self
96 }
97
98 fn box_clone(&self) -> Box<dyn ScrapedItem + Send + Sync> {
99 Box::new(self.clone())
100 }
101
102 fn to_json_value(&self) -> ::serde_json::Value {
103 match ::serde_json::to_value(self) {
104 Ok(value) => value,
105 Err(err) => panic!("failed to serialize ScrapedItem '{}': {}", stringify!(#name), err),
106 }
107 }
108 }
109 };
110
111 TokenStream::from(expanded)
112}