serde
Serde is a framework for serializing and deserializing Rust data structures efficiently and generically.
仅依赖syn ,quote ,proc-macro2
基本操作
use serde::{Deserialize, Serialize};
// 主要是 Serialize,Deserialize 这两个宏
#[derive(Serialize, Deserialize, Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 1, y: 2 };
// Convert the Point to a JSON string.
let serialized = serde_json::to_string(&point).unwrap();
// Prints serialized = {"x":1,"y":2}
println!("serialized = {}", serialized);
// Convert the JSON string back to a Point.
let deserialized: Point = serde_json::from_str(&serialized).unwrap();
// Prints deserialized = Point { x: 1, y: 2 }
println!("deserialized = {:?}", deserialized);
}
Deserialize
// 以该结构为例子
#[derive(Serialize,Debug)]
struct Duration{
secs:usize,
nanos:usize,
}
// 方便反序列化
impl Duration {
fn new(secs:usize,nanos:usize) -> Duration{
return Duration {
secs:secs,
nanos:nanos,
}
}
}
// 实现反序列化
impl<'de> Deserialize<'de> for Duration {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field { Secs, Nanos }
// This part could also be generated independently by:
//
// #[derive(Deserialize)]
// #[serde(field_identifier, rename_all = "lowercase")]
// enum Field { Secs, Nanos }
// 给每个字段实现反序列化
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
// visitor用于处理基本类型
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`secs` or `nanos`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"secs" => Ok(Field::Secs),
"nanos" => Ok(Field::Nanos),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
// 处理字段名
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct DurationVisitor;
impl<'de> Visitor<'de> for DurationVisitor {
type Value = Duration;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Duration")
}
// 针对序列
fn visit_seq<V>(self, mut seq: V) -> Result<Duration, V::Error>
where
V: SeqAccess<'de>,
{
let secs = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let nanos = seq.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
Ok(Duration::new(secs, nanos))
}
// 常见的反序列化map
fn visit_map<V>(self, mut map: V) -> Result<Duration, V::Error>
where
V: MapAccess<'de>,
{
let mut secs = None;
let mut nanos = None;
while let Some(key) = map.next_key()? {
match key {
Field::Secs => {
if secs.is_some() {
return Err(de::Error::duplicate_field("secs"));
}
secs = Some(map.next_value()?);
}
Field::Nanos => {
if nanos.is_some() {
return Err(de::Error::duplicate_field("nanos"));
}
nanos = Some(map.next_value()?);
}
}
}
let secs = secs.ok_or_else(|| de::Error::missing_field("secs"))?;
let nanos = nanos.ok_or_else(|| de::Error::missing_field("nanos"))?;
Ok(Duration::new(secs, nanos))
}
}
const FIELDS: &'static [&'static str] = &["secs", "nanos"];
deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor)
}
}
// 最后测试
let d = Duration{secs:123,nanos:345};
let ds = serde_json::to_string(&d).unwrap();
println!("{}",ds);
let dd:Duration = serde_json::from_str(&ds).unwrap();
println!("{:#?}",dd);
quote
This crate provides the quote! macro for turning Rust syntax tree data structures into tokens of source code. The idea of quasi-quoting is that we write code that we treat as data.
基本类型
let u = 12usize;
let i = -38i32;
let f = 3.1415926f64;
let c = '\r';
let s = "\r\nhello\tworld\r\n";
assert_eq!(
"12usize - 38i32 3.1415926f64 '\\r' \"\\r\\nhello\\tworld\\r\\n\"",
quote! {
#u #i #f #c #s
}
.to_string()
);
macro_rules! m {
($literal:literal) => {
quote!($literal)
};
}
let expected = "- false";
assert_eq!(expected, m!(-false).to_string());
重复、循环
let f0 = format_ident!("World");
let f1 = format_ident!("Hello{x}", x = f0);
assert_eq!("HelloWorld",f1.to_string());
// ident not impl f64
let f2 = format_ident!("Hello{x}", x = 4050usize);
assert_eq!("Hello4050",f2.to_string());
let num: u32 = 10;
let octal = format_ident!("Id_{:o}", num);
assert_eq!(octal, "Id_12");
let binary = format_ident!("Id_{:b}", num);
assert_eq!(binary, "Id_1010");
let lower_hex = format_ident!("Id_{:x}", num);
assert_eq!(lower_hex, "Id_a");
let upper_hex = format_ident!("Id_{:X}", num);
assert_eq!(upper_hex, "Id_A");
注释
let token1 = quote!{
/* comment */
};
let token2 = quote!{
// comment
};
assert_eq!(token1.to_string(),token2.to_string())
syn
Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code.
syn::File
let mut file = File::open(&filename).expect("Unable to open file");
let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
let ast = syn::parse_file(&src).unwrap();
if let Some(shebang) = ast.shebang {
println!("{}", shebang);
}
println!("{} items", ast.items.len());
DeriveInput for proc_macro_derive
#[proc_macro_derive(HeapSize)]
pub fn derive_heap_size(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// Parse the input tokens into a syntax tree.
let input = parse_macro_input!(input as DeriveInput);
// Used in the quasi-quotation below as `#name`.
let name = input.ident;
// Add a bound `T: HeapSize` to every type parameter T.
let generics = add_trait_bounds(input.generics);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
// Generate an expression to sum up the heap size of each field.
let sum = heap_size_sum(&input.data);
let expanded = quote! {
// The generated impl.
...
};
// Hand the output tokens back to the compiler.
proc_macro::TokenStream::from(expanded)
}
fold 可以在语法转换时hook
impl Fold for Args {
// 处理expr类型时
fn fold_expr(&mut self, e: Expr) -> Expr {
match e {
Expr::Assign(e) => {
if self.should_print_expr(&e.left) {
self.assign_and_print(*e.left, &e.eq_token, *e.right)
} else {
Expr::Assign(fold::fold_expr_assign(self, e))
}
}
Expr::Binary(e) if is_assign_op(e.op) => {
if self.should_print_expr(&e.left) {
self.assign_and_print(*e.left, &e.op, *e.right)
} else {
Expr::Binary(fold::fold_expr_binary(self, e))
}
}
_ => fold::fold_expr(self, e),
}
}
// 处理stmt类型
fn fold_stmt(&mut self, s: Stmt) -> Stmt {
match s {
Stmt::Local(s) => {
if s.init.is_some() && self.should_print_pat(&s.pat) {
self.let_and_print(s)
} else {
Stmt::Local(fold::fold_local(self, s))
}
}
_ => fold::fold_stmt(self, s),
}
}
}