#![recursion_limit = "256"]
extern crate proc_macro;
use proc_macro2;
use quote::quote;
use syn::{self, parse_quote};
use proc_macro::TokenStream;
use proc_macro2::Span;
use proc_macro2::TokenStream as TokenStream2;
#[proc_macro_derive(Graph, attributes(graph))]
pub fn graph(input: TokenStream) -> TokenStream {
let input: TokenStream2 = input.into();
let mut ast: syn::DeriveInput = syn::parse2(input).unwrap();
let name = &ast.ident;
let generics = &mut ast.generics;
let mut var = None;
let mut typ = None;
#[allow(clippy::block_in_if_condition_stmt)]
let fields = match ast.data {
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => fields.iter().enumerate().filter_map(|(i, field)| {
if field
.ident
.as_ref()
.map(|id| id.to_string())
.unwrap_or_else(String::new)
== "graph"
{
var = Some(syn::Ident::new("graph", Span::call_site()));
typ = Some(&field.ty);
None
} else if field.attrs.iter().any(|attr| {
attr.path.segments.len() == 1
&& attr.path.segments.first().unwrap().into_value().ident
== syn::Ident::new("graph", Span::call_site())
}) {
Some((
field
.ident
.clone()
.unwrap_or_else(|| syn::Ident::new(&format!("{}", i), Span::call_site())),
&field.ty,
))
} else {
None
}
}),
_ => panic!("Only structs containing a graph field can be derived."),
}
.collect::<Vec<_>>();
if fields.is_empty() && var.is_none() {
panic!("No field named `graph` or with #[graph] attribute found");
} else if fields.len() > 1 {
panic!(
"Multiple fields with #[graph] attribute found: {}",
fields
.iter()
.map(|&(ref name, _)| name.to_string())
.collect::<Vec<_>>()
.join(", ")
);
} else if !fields.is_empty() {
let field = fields.into_iter().next().unwrap();
var = Some(field.0);
typ = Some(field.1);
}
let ty_generics = generics.clone();
generics.params.push(parse_quote!('a));
let gens = [
"GraphType",
"GraphSize",
"Undirected",
"Directed",
"BiDirected",
"IndexGraph",
"IndexNetwork",
]
.iter()
.map(|name| {
let name = syn::Ident::new(name, Span::call_site());
let mut g = generics.clone();
g.make_where_clause()
.predicates
.push(parse_quote!(#typ: ::rs_graph::traits::#name<'a>));
g
})
.collect::<Vec<_>>();
let (basegraph_impl, _, basegraph_where) = gens[0].split_for_impl();
let (graphsize_impl, _, graphsize_where) = gens[1].split_for_impl();
let (undirected_impl, _, undirected_where) = gens[2].split_for_impl();
let (directed_impl, _, directed_where) = gens[3].split_for_impl();
let (bidirected_impl, _, bidirected_where) = gens[4].split_for_impl();
let (indexgraph_impl, _, indexgraph_where) = gens[5].split_for_impl();
let (indexnetwork_impl, _, indexnetwork_where) = gens[6].split_for_impl();
let expanded = quote! {
impl #basegraph_impl ::rs_graph::traits::GraphType<'a> for #name #ty_generics #basegraph_where
{
type Node = <#typ as ::rs_graph::traits::GraphType<'a>>::Node;
type Edge = <#typ as ::rs_graph::traits::GraphType<'a>>::Edge;
}
impl #graphsize_impl ::rs_graph::traits::GraphSize<'a> for #name #ty_generics #graphsize_where
{
type NodeIter = <#typ as ::rs_graph::traits::GraphSize<'a>>::NodeIter;
type EdgeIter = <#typ as ::rs_graph::traits::GraphSize<'a>>::EdgeIter;
fn num_nodes(&self) -> usize {
self.#var.num_nodes()
}
fn num_edges(&self) -> usize {
self.#var.num_edges()
}
fn nodes(&'a self) -> Self::NodeIter {
self.#var.nodes()
}
fn edges(&'a self) -> Self::EdgeIter {
self.#var.edges()
}
}
impl #undirected_impl ::rs_graph::traits::Undirected<'a> for #name #ty_generics #undirected_where
{
type NeighIter = <#typ as ::rs_graph::traits::Undirected<'a>>::NeighIter;
fn enodes(&'a self, e: Self::Edge) -> (Self::Node, Self::Node) {
self.#var.enodes(e)
}
fn neighs(&'a self, u: Self::Node) -> Self::NeighIter {
self.#var.neighs(u)
}
}
impl #directed_impl ::rs_graph::traits::Directed<'a> for #name #ty_generics #directed_where
{
type OutEdgeIter = <#typ as ::rs_graph::traits::Directed<'a>>::OutEdgeIter;
type InEdgeIter = <#typ as ::rs_graph::traits::Directed<'a>>::InEdgeIter;
fn src(&'a self, e: Self::Edge) -> Self::Node {
self.#var.src(e)
}
fn snk(&'a self, e: Self::Edge) -> Self::Node {
self.#var.snk(e)
}
fn outedges(&'a self, u: Self::Node) -> Self::OutEdgeIter {
self.#var.outedges(u)
}
fn inedges(&'a self, u: Self::Node) -> Self::InEdgeIter {
self.#var.inedges(u)
}
}
impl #bidirected_impl ::rs_graph::traits::BiDirected<'a> for #name #ty_generics #bidirected_where
{
fn is_reverse(&self, e: Self::Edge, f: Self::Edge) -> bool {
self.#var.is_reverse(e, f)
}
fn reverse(&'a self, e: Self::Edge) -> Self::Edge {
self.#var.reverse(e)
}
fn is_forward(&self, e: Self::Edge) -> bool {
self.#var.is_forward(e)
}
fn forward(&'a self, e: Self::Edge) -> Self::Edge {
self.#var.forward(e)
}
fn is_backward(&self, e: Self::Edge) -> bool {
self.#var.is_backward(e)
}
fn backward(&'a self, e: Self::Edge) -> Self::Edge {
self.#var.backward(e)
}
fn bisrc(&'a self, e: Self::Edge) -> Self::Node {
self.#var.bisrc(e)
}
fn bisnk(&'a self, e: Self::Edge) -> Self::Node {
self.#var.bisnk(e)
}
}
impl #indexgraph_impl ::rs_graph::traits::IndexGraph<'a> for #name #ty_generics #indexgraph_where
{
fn node_id(&self, u: Self::Node) -> usize {
self.#var.node_id(u)
}
fn id2node(&'a self, id: usize) -> Self::Node {
self.#var.id2node(id)
}
fn edge_id(&self, e: Self::Edge) -> usize {
self.#var.edge_id(e)
}
fn id2edge(&'a self, id: usize) -> Self::Edge {
self.#var.id2edge(id)
}
}
impl #indexnetwork_impl ::rs_graph::traits::IndexNetwork<'a> for #name #ty_generics #indexnetwork_where
{
fn biedge_id(&self, e: Self::Edge) -> usize {
self.#var.biedge_id(e)
}
fn id2biedge(&'a self, id: usize) -> Self::Edge {
self.#var.id2biedge(id)
}
}
};
expanded.into()
}