Skip to content

Commit

Permalink
Added beginning support for generics to serbin and debin proc macros
Browse files Browse the repository at this point in the history
  • Loading branch information
knickish authored and not-fl3 committed Nov 5, 2022
1 parent a821a3b commit 9eece5a
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 30 deletions.
119 changes: 105 additions & 14 deletions derive/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use alloc::{format, vec};

use proc_macro::{Delimiter, Group, TokenStream, TokenTree};


#[derive(Debug)]
pub struct Attribute {
pub name: String,
Expand All @@ -36,7 +37,7 @@ pub struct Field {
}

#[allow(dead_code)]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Type {
pub is_option: bool,
pub path: String,
Expand All @@ -48,6 +49,7 @@ pub struct Struct {
pub named: bool,
pub fields: Vec<Field>,
pub attributes: Vec<Attribute>,
pub generics: Vec<String>
}

#[derive(Debug)]
Expand All @@ -63,6 +65,7 @@ pub struct Enum {
pub name: String,
pub variants: Vec<EnumVariant>,
pub attributes: Vec<Attribute>,
pub generics: Vec<String>
}

#[allow(dead_code)]
Expand Down Expand Up @@ -186,7 +189,7 @@ pub fn next_group(source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Opt
// println!("{:?}", source.peek());
// }

fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Option<Type> {
fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>, generic_typenames: &HashSet<String> ) -> Option<Type> {
let group = next_group(&mut source);
if group.is_some() {
let mut group = group.unwrap().stream().into_iter().peekable();
Expand All @@ -196,7 +199,7 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt
path: "".to_string(),
};

while let Some(next_ty) = next_type(&mut group) {
while let Some(next_ty) = next_type(&mut group, generic_typenames) {
tuple_type.path.push_str(&format!("{}, ", next_ty.path));
}

Expand All @@ -214,9 +217,9 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt

let angel_bracket = next_exact_punct(&mut source, "<");
if angel_bracket.is_some() {
let mut generic_type = next_type(source).expect("Expecting generic argument");
let mut generic_type = next_type(source, generic_typenames).expect("Expecting generic argument");
while let Some(_comma) = next_exact_punct(&mut source, ",") {
let next_ty = next_type(source).expect("Expecting generic argument");
let next_ty = next_type(source, generic_typenames).expect("Expecting generic argument");
generic_type.path.push_str(&format!(", {}", next_ty.path));
}

Expand All @@ -225,7 +228,7 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt

if ty == "Option" {
Some(Type {
path: generic_type.path,
path: generic_type.path.clone(),
is_option: true,
})
} else {
Expand All @@ -235,8 +238,9 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt
})
}
} else {
// panic!("{} \n{:?}", &ty, generic_typenames);
Some(Type {
path: ty,
path: ty.clone(),
is_option: false,
})
}
Expand Down Expand Up @@ -311,6 +315,7 @@ fn next_attributes_list(source: &mut Peekable<impl Iterator<Item = TokenTree>>)
fn next_fields(
mut body: &mut Peekable<impl Iterator<Item = TokenTree>>,
named: bool,
generic_typenames: &HashSet<String>
) -> Vec<Field> {
let mut fields = vec![];

Expand All @@ -330,7 +335,7 @@ fn next_fields(
None
};

let ty = next_type(&mut body).expect("Expected field type");
let ty = next_type(&mut body, &generic_typenames).expect("Expected field type");
let _punct = next_punct(&mut body);

fields.push(Field {
Expand All @@ -345,7 +350,7 @@ fn next_fields(

fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Struct {
let struct_name = next_ident(&mut source).expect("Unnamed structs are not supported");

let generic_types = get_bounds(source);
let group = next_group(&mut source);
// unit struct
if group.is_none() {
Expand All @@ -357,8 +362,10 @@ fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> St
fields: vec![],
attributes: vec![],
named: false,
generics: vec![]
};
};

let group = group.unwrap();
let delimiter = group.delimiter();
let named = match delimiter {
Expand All @@ -369,7 +376,7 @@ fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> St
};

let mut body = group.stream().into_iter().peekable();
let fields = next_fields(&mut body, named);
let fields = next_fields(&mut body, named, &generic_types);

if named == false {
next_exact_punct(&mut source, ";").expect("Expected ; on the end of tuple struct");
Expand All @@ -380,19 +387,21 @@ fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> St
named,
fields,
attributes: vec![],
generics: generic_types.into_iter().collect()
}
}

fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum {
let enum_name = next_ident(&mut source).expect("Unnamed enums are not supported");

let generic_types = get_bounds(source);
let group = next_group(&mut source);
// unit enum
if group.is_none() {
return Enum {
name: enum_name,
variants: vec![],
attributes: vec![],
generics: vec![]
};
};
let group = group.unwrap();
Expand Down Expand Up @@ -428,7 +437,7 @@ fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum
};
{
let mut body = group.stream().into_iter().peekable();
let fields = next_fields(&mut body, named);
let fields = next_fields(&mut body, named, &generic_types);
variants.push(EnumVariant {
name: variant_name,
named,
Expand All @@ -444,7 +453,90 @@ fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum
name: enum_name,
variants,
attributes: vec![],
generics: generic_types.into_iter().collect()
}
}

fn get_bounds(source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> HashSet<String> {
let mut ret = HashSet::new();
let mut tmp: Vec<String> = Vec::new();

match source.peek() {
Some(content) if content.to_string() == "<" => {
source.next();
let mut typename = "".to_string();
let mut in_type = true;
while let Some(tok) = source.next() {
tmp.push(tok.to_string());
match tok.to_string().as_str() {
">" => {
if !typename.is_empty(){
ret.insert(typename.clone());
}
break
},
":" => {
ret.insert(typename.clone());
typename.clear();
in_type = false
},
"," => {
if in_type {
ret.insert(typename.clone());
typename.clear();
}
in_type = true
},
c => {
if in_type {
typename+=c
}
}
}
}
},
_ => ()
}
ret
}

pub(crate) fn struct_bounds_strings(struct_: &Struct, bound_name: &str) -> (String, String) {
let generics: &Vec<String> = &struct_.generics;
if generics.is_empty() {
return ("".to_string(), "".to_string());
}
let mut generic_w_bounds = "<".to_string();
for generic in generics.iter() {
generic_w_bounds += &format!("{}: nanoserde::{}, ", generic, bound_name);
}
generic_w_bounds += ">";

let mut generic_no_bounds = "<".to_string();
for generic in generics.iter() {
generic_no_bounds += &format!("{}, ", generic);
}
generic_no_bounds += ">";
return (generic_w_bounds, generic_no_bounds);
}

pub(crate) fn enum_bounds_strings(enum_: &Enum, bound_name: &str) -> (String, String) {
let generics: &Vec<String> = &enum_.generics;

if generics.is_empty() {
return ("".to_string(), "".to_string());
}
let mut generic_w_bounds = "<".to_string();
for generic in generics.iter() {
generic_w_bounds += &format!("{}: nanoserde::{}, ", generic, bound_name);
}
generic_w_bounds += ">";

let mut generic_no_bounds = "<".to_string();
for generic in generics.iter() {
generic_no_bounds += &format!("{}, ", generic);
}
generic_no_bounds += ">";
return (generic_w_bounds, generic_no_bounds);
}

pub fn parse_data(input: TokenStream) -> Data {
Expand All @@ -466,8 +558,8 @@ pub fn parse_data(input: TokenStream) -> Data {
"struct" => {
let mut struct_ = next_struct(&mut source);
struct_.attributes = attributes;

res = Data::Struct(struct_);

}
"enum" => {
let enum_ = next_enum(&mut source);
Expand All @@ -481,6 +573,5 @@ pub fn parse_data(input: TokenStream) -> Data {
source.next().is_none(),
"Unexpected data after end of the struct"
);

res
}
Loading

0 comments on commit 9eece5a

Please sign in to comment.