rs-graph-derive 0.10.0

Automatic implementation of graph types
Documentation
/*
 * Copyright (c) 2017, 2018 Frank Fischer <frank-fischer@shadow-soft.de>
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see  <http://www.gnu.org/licenses/>
 */

#![recursion_limit = "256"]

//! This create provides automatic graph derivations.
//!
//! In order to automatically implement graph traits for
//! a struct that contains the actual graph data structure in a field,
//! add #[derive(Graph)] to the struct. The field containing the graph
//! must either be named `graph` or be attributed with `#[graph]`.
//! All graph traits (`Graph`, `Digraph`, `Network`, `IndexGraph` and
//! `IndexNetwork`) that are implemented for the nested graph, are
//! implemented for the annotated struct, too.
//!
//! # Example
//!
//! ```
//! extern crate rs_graph;
//! #[macro_use]
//! extern crate rs_graph_derive;
//! use rs_graph::{Graph, IndexGraph};
//! use rs_graph::linkedlistgraph::*;
//! use rs_graph::classes;
//!
//! #[derive(Graph)]
//! struct MyGraph {
//!     #[graph] graph: LinkedListGraph, // #[graph] not need for fields named `graph`.
//!     balances: Vec<f64>,
//!     bounds: Vec<f64>,
//! }
//!
//! impl From<LinkedListGraph> for MyGraph {
//!     fn from(g: LinkedListGraph) -> MyGraph {
//!         let n = g.num_nodes();
//!         let m = g.num_edges();
//!         MyGraph {
//!             graph: g,
//!             balances: vec![0.0; n],
//!             bounds: vec![0.0; m],
//!         }
//!     }
//! }
//!
//! impl MyGraph {
//!     fn balance_mut(&mut self, u: Node) -> &mut f64 {
//!         &mut self.balances[self.graph.node_id(u)]
//!     }
//!
//!     fn bound_mut(&mut self, e: Edge) -> &mut f64 {
//!         &mut self.bounds[self.graph.edge_id(e)]
//!     }
//! }
//!
//! # fn main() {
//! let mut g: MyGraph = classes::path::<LinkedListGraph>(5).into();
//! let (s, t) = (g.id2node(0), g.id2node(4));
//! *g.balance_mut(s) = 1.0;
//! *g.balance_mut(t) = -1.0;
//! for e in g.edges() { *g.bound_mut(e) = g.edge_id(e) as f64; }
//! # }
//! ```

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate rs_graph;
extern crate syn;

use proc_macro::TokenStream;

#[proc_macro_derive(Graph, attributes(graph))]
pub fn graph(input: TokenStream) -> TokenStream {
    let ast: syn::DeriveInput = syn::parse(input).unwrap();
    let name = &ast.ident;

    let mut var = None;
    let mut typ = None;

    // Collect all fields with attribute #[graph] or named `graph`.
    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.as_ref()).unwrap_or("") == &"graph" {
                var = Some("graph".into());
                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::from("graph")
            }) {
                Some((
                    field
                        .ident
                        .clone()
                        .unwrap_or_else(|| syn::Ident::from(format!("{}", i))),
                    &field.ty,
                ))
            } else {
                None
            }
        }),
        _ => panic!("Only structs containing a graph field can be derived."),
    }.collect::<Vec<_>>();

    // Ensure there is a single #[graph] field or (if none exists) a
    // field named `graph`.
    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.as_ref())
                .collect::<Vec<_>>()
                .join(", ")
        );
    } else if !fields.is_empty() {
        let field = fields.into_iter().next().unwrap();
        var = Some(field.0);
        typ = Some(field.1);
    }

    // Implement all graph traits the nested graph implements.
    let expanded = quote! {
        impl<'a> Graph<'a> for #name
        where #typ: Graph<'a>
        {
            type Node = <#typ as Graph<'a>>::Node;

            type Edge = <#typ as Graph<'a>>::Edge;

            type NodeIter = <#typ as Graph<'a>>::NodeIter;

            type EdgeIter = <#typ as Graph<'a>>::EdgeIter;

            type NeighIter = <#typ as Graph<'a>>::NeighIter;

            fn num_nodes(&self) -> usize {
                self.#var.num_nodes()
            }

            fn num_edges(&self) -> usize {
                self.#var.num_edges()
            }

            fn enodes(&'a self, e: Self::Edge) -> (Self::Node, Self::Node) {
                self.#var.enodes(e)
            }

            fn nodes(&'a self) -> Self::NodeIter {
                self.#var.nodes()
            }

            fn edges(&'a self) -> Self::EdgeIter {
                self.#var.edges()
            }

            fn neighs(&'a self, u: Self::Node) -> Self::NeighIter {
                self.#var.neighs(u)
            }
        }

        impl<'a> ::rs_graph::Digraph<'a> for #name
        where
            #typ: ::rs_graph::Digraph<'a>,
        {
            type OutEdgeIter = <#typ as ::rs_graph::Digraph<'a>>::OutEdgeIter;

            type InEdgeIter = <#typ as ::rs_graph::Digraph<'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<'a> ::rs_graph::Network<'a> for #name
        where
            #typ: ::rs_graph::Network<'a>,
        {
            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<'a> ::rs_graph::IndexGraph<'a> for #name
        where #typ: ::rs_graph::IndexGraph<'a>
        {
            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<'a> ::rs_graph::IndexNetwork<'a> for #name
        where
            #typ: ::rs_graph::IndexNetwork<'a>,
        {
            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()
}