Skip to main content

rs_graph_derive/
lib.rs

1/*
2 * Copyright (c) 2017-2022 Frank Fischer <frank-fischer@shadow-soft.de>
3 *
4 * This program is free software: you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see  <http://www.gnu.org/licenses/>
16 */
17
18#![recursion_limit = "256"]
19#![forbid(unsafe_code)]
20
21//! This crate provides automatic graph derivations.
22//!
23//! In order to automatically implement graph traits for a struct that contains
24//! the actual graph data structure in a field, add #[derive(Graph)] to the
25//! struct. The field containing the graph must either be named `graph` or be
26//! attributed with `#[graph]`. All graph traits (`Graph`, `Digraph`, and
27//! `IndexGraph`) that are implemented for the nested graph, are implemented for
28//! the annotated struct, too.
29//!
30//! # Example
31//!
32//! ```
33//! use rs_graph_derive::Graph;
34//! use rs_graph::traits::*;
35//! use rs_graph::linkedlistgraph::*;
36//! use rs_graph::classes;
37//!
38//! #[derive(Graph)]
39//! struct MyGraph {
40//!     #[graph] graph: LinkedListGraph, // #[graph] not needed for fields named `graph`.
41//!     balances: Vec<f64>,
42//!     bounds: Vec<f64>,
43//! }
44//!
45//! impl From<LinkedListGraph> for MyGraph {
46//!     fn from(g: LinkedListGraph) -> MyGraph {
47//!         let n = g.num_nodes();
48//!         let m = g.num_edges();
49//!         MyGraph {
50//!             graph: g,
51//!             balances: vec![0.0; n],
52//!             bounds: vec![0.0; m],
53//!         }
54//!     }
55//! }
56//!
57//! impl MyGraph {
58//!     fn balance_mut(&mut self, u: Node) -> &mut f64 {
59//!         &mut self.balances[self.graph.node_id(u)]
60//!     }
61//!
62//!     fn bound_mut(&mut self, e: Edge) -> &mut f64 {
63//!         &mut self.bounds[self.graph.edge_id(e)]
64//!     }
65//! }
66//!
67//! # fn main() {
68//! let mut g: MyGraph = classes::path::<LinkedListGraph>(5).into();
69//! let (s, t) = (g.id2node(0), g.id2node(4));
70//! *g.balance_mut(s) = 1.0;
71//! *g.balance_mut(t) = -1.0;
72//! for eid in 0..g.num_edges() { *g.bound_mut(g.id2edge(eid)) = eid as f64; }
73//! # }
74//! ```
75//!
76//! # Attributed graphs
77//!
78//! Some algorithms require the presence of specific node or edge attributes.
79//! These requirements are represented by `NodeAttributes` and `EdgeAttributes`
80//! traits from `rs_graph::attributes`. These traits can also be automatically
81//! implemented using `#[derive(Graph)]` given that the wrapped graph is an
82//! `IndexGraph`. The node/edge attributes must be collected in indexable arrays
83//! (slice, `Vec`, ...) of an appropriate size and be annotated with `nodeattrs`
84//! or `edgeattrs` attributes. Note that it is the responsibility of the user to
85//! ensure that these vectors have to correct size.
86//!
87//! # Example
88//!
89//! ```
90//! use rs_graph_derive::Graph;
91//! use rs_graph::{traits::*};
92//! use rs_graph::linkedlistgraph::*;
93//! use rs_graph::classes;
94//! use rs_graph::attributes::{NodeAttributes, EdgeAttributes, AttributedGraph};
95//!
96//! #[derive(Clone, Default)]
97//! struct NodeData {
98//!     balance: f64,
99//! }
100//!
101//! #[derive(Clone, Default)]
102//! struct EdgeData {
103//!     bound: f64,
104//! }
105//!
106//! #[derive(Graph)]
107//! struct MyGraph {
108//!     #[graph] graph: LinkedListGraph,
109//!     #[nodeattrs(NodeData)] nodedata: Vec<NodeData>,
110//!     #[edgeattrs(EdgeData)] edgedata: Vec<EdgeData>,
111//! }
112//!
113//! #[derive(Graph)]
114//! struct MyGraph2 {
115//!     #[graph] graph: LinkedListGraph,
116//!     #[nodeattrs(NodeData)] nodedata: Vec<NodeData>,
117//!     #[edgeattrs(EdgeData)] edgedata: Vec<EdgeData>,
118//! }
119//!
120//! impl From<LinkedListGraph> for MyGraph {
121//!     fn from(g: LinkedListGraph) -> MyGraph {
122//!         let n = g.num_nodes();
123//!         let m = g.num_edges();
124//!         MyGraph {
125//!             graph: g,
126//!             nodedata: vec![Default::default(); n],
127//!             edgedata: vec![Default::default(); m],
128//!         }
129//!     }
130//! }
131//!
132//! # fn main() {
133//! let mut g: MyGraph = classes::peterson::<LinkedListGraph>().into();
134//! let (s, t) = (g.id2node(0), g.id2node(4));
135//! g.node_mut(s).balance = 1.0;
136//! g.node_mut(t).balance = -1.0;
137//! for eid in 0..g.num_edges() { g.edge_mut(g.id2edge(eid)).bound = eid as f64; }
138//!
139//! {
140//!     let (g, mut attrs) = g.split();
141//!     // this would also work: let (g, mut attrs) = attrs.split();
142//!     for u in g.nodes() {
143//!         for (e, v) in g.outedges(u) {
144//!             attrs.node_mut(v).balance = 42.0 + g.node_id(v) as f64;
145//!         }
146//!     }
147//! }
148//! for u in g.nodes() {
149//!     assert_eq!(g.node(u).balance, 42.0 + g.node_id(u) as f64);
150//! }
151//! # }
152//! ```
153//!
154
155use quote::{format_ident, quote};
156#[allow(unused_imports)]
157use syn::Token; // we use the `Token!` macro
158use syn::{self, parse_quote};
159
160use proc_macro::TokenStream;
161use proc_macro2::Span;
162use proc_macro2::TokenStream as TokenStream2;
163
164#[derive(Debug, PartialEq)]
165struct Var {
166    name: syn::Ident,
167    typ: syn::Type,
168}
169
170struct StructInfo {
171    name: syn::Ident,
172    visibility: syn::Visibility,
173    generic_parameters: syn::Generics,
174
175    graph: Var,
176
177    node_attr: Option<Var>,
178    edge_attr: Option<Var>,
179}
180
181fn parse_graph_structure(input: TokenStream2) -> StructInfo {
182    let mut ast: syn::DeriveInput = syn::parse2(input).unwrap();
183    let vis = &ast.vis;
184    let name = &ast.ident;
185    let generics = &mut ast.generics;
186
187    let mut have_graph_attr = false;
188    let mut graph = None;
189
190    let mut node_attr = None;
191    let mut edge_attr = None;
192
193    // Collect all fields with attribute #[graph] or named `graph`.
194    if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = ast.data {
195        for (i, ref field) in fields.iter().enumerate() {
196            if let Some(attrvar) = get_attr_var(field, i, "nodeattrs") {
197                if node_attr.is_some() {
198                    panic!("Only one field can be tagged `nodeattrs`");
199                }
200                node_attr = Some(attrvar);
201            }
202
203            if let Some(attrvar) = get_attr_var(field, i, "edgeattrs") {
204                if edge_attr.is_some() {
205                    panic!("Only one field can be tagged `edgeattrs`");
206                }
207                edge_attr = Some(attrvar);
208            }
209
210            if field.attrs.iter().any(|attr| attr.path.is_ident("graph")) {
211                if have_graph_attr {
212                    panic!("Only one field can be tagged `graph`");
213                }
214                have_graph_attr = true;
215            } else if field.ident.as_ref().map(|s| s == "graph").unwrap_or(false) {
216                if have_graph_attr {
217                    continue;
218                }
219            } else {
220                continue;
221            }
222
223            graph = Some(Var {
224                name: field.ident.clone().unwrap_or_else(|| format_ident!("{}", i)),
225                typ: field.ty.clone(),
226            });
227        }
228    }
229
230    StructInfo {
231        name: name.clone(),
232        visibility: vis.clone(),
233        generic_parameters: generics.clone(),
234
235        graph: graph.expect("No field `graph` or field with attribute #[graph] found"),
236        node_attr,
237        edge_attr,
238    }
239}
240
241fn get_attr_var(field: &syn::Field, index: usize, attrname: &str) -> Option<Var> {
242    for attr in field.attrs.iter() {
243        if attr.path.is_ident(attrname) {
244            return Some(Var {
245                name: field.ident.clone().unwrap_or_else(|| format_ident!("{}", index)),
246                typ: match attr
247                    .parse_meta()
248                    .unwrap_or_else(|_| panic!("Missing `{}` type", attrname))
249                {
250                    syn::Meta::List(list) => {
251                        assert_eq!(
252                            list.nested.len(),
253                            1,
254                            "expected exactly one type argument for `{}`",
255                            attrname
256                        );
257                        if let Some(syn::NestedMeta::Meta(syn::Meta::Path(id))) = list.nested.iter().next() {
258                            // TODO: This is actually not very sophisticated. It only
259                            // extracts plain path types without generics (nothing fancy).
260                            syn::Type::Path(syn::TypePath {
261                                qself: None,
262                                path: id.clone(),
263                            })
264                        } else {
265                            panic!("expected exactly one type argument for `{}`", attrname);
266                        }
267                    }
268                    _ => panic!("expected exactly one type argument for `{}`", attrname),
269                },
270            });
271        }
272    }
273
274    None
275}
276
277fn graph_derive(input: TokenStream2) -> TokenStream2 {
278    let graph = parse_graph_structure(input);
279
280    let name = graph.name;
281    let generics = graph.generic_parameters;
282    let vis = graph.visibility;
283    let var = graph.graph.name;
284    let typ = graph.graph.typ;
285    let nodeattrs = graph.node_attr;
286    let edgeattrs = graph.edge_attr;
287
288    // Implement all graph traits the nested graph implements.
289
290    let ident_it = format_ident!("{}", "__rs_graph_I__");
291    let ident_lt = syn::Lifetime::new("'__rs_graph_z__", Span::call_site());
292    let ty_generics = generics.clone();
293    let mut it_generics = generics.clone();
294    it_generics
295        .params
296        .push(syn::GenericParam::Type(ident_it.clone().into()));
297    // generics
298    //     .params
299    //     .push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(ident_lt.clone())));
300
301    let gens = [
302        "GraphType",
303        "FiniteGraph",
304        "FiniteDigraph",
305        "Undirected",
306        "Directed",
307        "IndexGraph",
308    ]
309    .iter()
310    .map(|name| {
311        let name = format_ident!("{}", name);
312        let mut g = generics.clone();
313        g.make_where_clause()
314            .predicates
315            .push(parse_quote!(#typ: ::rs_graph::traits::#name));
316        //.push(parse_quote!(#typ: ::rs_graph::traits::#name<#ident_lt>));
317        g
318    })
319    .collect::<Vec<_>>();
320
321    let (basegraph_impl, _, basegraph_where) = gens[0].split_for_impl();
322    let (finitegraph_impl, _, finitegraph_where) = gens[1].split_for_impl();
323    let (finitedigraph_impl, _, finitedigraph_where) = gens[2].split_for_impl();
324    let (undirected_impl, _, undirected_where) = gens[3].split_for_impl();
325    let (directed_impl, _, directed_where) = gens[4].split_for_impl();
326    let (indexgraph_impl, _, indexgraph_where) = gens[5].split_for_impl();
327
328    let mut expanded = quote! {
329        impl #it_generics ::rs_graph::traits::GraphIterator<#name #ty_generics> for ::rs_graph::traits::refs::WrapIt<#ident_it> where #ident_it: GraphIterator<#typ> {
330            type Item = #ident_it :: Item;
331
332            fn next(&mut self, g: &#name #ty_generics) -> Option<Self::Item> {
333                self.0.next(&g.#var)
334            }
335        }
336
337        impl #basegraph_impl ::rs_graph::traits::GraphType for #name #ty_generics #basegraph_where
338        {
339            type Node<#ident_lt> = <#typ as ::rs_graph::traits::GraphType>::Node<#ident_lt>;
340
341            type Edge<#ident_lt> = <#typ as ::rs_graph::traits::GraphType>::Edge<#ident_lt>;
342        }
343
344        impl #finitegraph_impl ::rs_graph::traits::FiniteGraph for #name #ty_generics #finitegraph_where
345        {
346            type NodeIt<#ident_lt> where Self: #ident_lt = ::rs_graph::traits::refs::WrapIt<<#typ as ::rs_graph::traits::FiniteGraph>::NodeIt<#ident_lt>>;
347
348            type EdgeIt<#ident_lt> where Self: #ident_lt = ::rs_graph::traits::refs::WrapIt<<#typ as ::rs_graph::traits::FiniteGraph>::EdgeIt<#ident_lt>>;
349
350            fn num_nodes(&self) -> usize {
351                self.#var.num_nodes()
352            }
353
354            fn num_edges(&self) -> usize {
355                self.#var.num_edges()
356            }
357
358            fn nodes_iter(&self) -> Self::NodeIt<'_> {
359                ::rs_graph::traits::refs::WrapIt(self.#var.nodes_iter())
360            }
361
362            fn edges_iter(&self) -> Self::EdgeIt<'_> {
363                ::rs_graph::traits::refs::WrapIt(self.#var.edges_iter())
364            }
365
366            fn enodes(&self, e: Self::Edge<'_>) -> (Self::Node<'_>, Self::Node<'_>) {
367                self.#var.enodes(e)
368            }
369        }
370
371        impl #finitedigraph_impl ::rs_graph::traits::FiniteDigraph for #name #ty_generics #finitedigraph_where
372        {
373            fn src(&self, e: Self::Edge<'_>) -> Self::Node<'_> {
374                self.#var.src(e)
375            }
376
377            fn snk(&self, e: Self::Edge<'_>) -> Self::Node<'_> {
378                self.#var.snk(e)
379            }
380        }
381
382        impl #undirected_impl ::rs_graph::traits::Undirected for #name #ty_generics #undirected_where
383        {
384            type NeighIt<#ident_lt> where Self: #ident_lt = ::rs_graph::traits::refs::WrapIt<<#typ as ::rs_graph::traits::Undirected>::NeighIt<#ident_lt>>;
385
386            fn neigh_iter(&self, u: Self::Node<'_>) -> Self::NeighIt<'_> {
387                ::rs_graph::traits::refs::WrapIt(self.#var.neigh_iter(u))
388            }
389        }
390
391        impl #directed_impl ::rs_graph::traits::Directed for #name #ty_generics #directed_where
392        {
393            type OutIt<#ident_lt> where Self: #ident_lt = ::rs_graph::traits::refs::WrapIt<<#typ as ::rs_graph::traits::Directed>::OutIt<#ident_lt>>;
394
395            type InIt<#ident_lt> where Self: #ident_lt = ::rs_graph::traits::refs::WrapIt<<#typ as ::rs_graph::traits::Directed>::InIt<#ident_lt>>;
396
397            type IncidentIt<#ident_lt> where Self: #ident_lt = ::rs_graph::traits::refs::WrapIt<<#typ as ::rs_graph::traits::Directed>::IncidentIt<#ident_lt>>;
398
399            type DirectedEdge<#ident_lt> where Self: #ident_lt = <#typ as ::rs_graph::traits::Directed>::DirectedEdge<#ident_lt>;
400
401            fn out_iter(&self, u: Self::Node<'_>) -> Self::OutIt<'_> {
402                ::rs_graph::traits::refs::WrapIt(self.#var.out_iter(u))
403            }
404
405            fn in_iter(&self, u: Self::Node<'_>) -> Self::InIt<'_> {
406                ::rs_graph::traits::refs::WrapIt(self.#var.in_iter(u))
407            }
408
409            fn incident_iter(&self, u: Self::Node<'_>) -> Self::IncidentIt<'_> {
410                ::rs_graph::traits::refs::WrapIt(self.#var.incident_iter(u))
411            }
412        }
413
414        impl #indexgraph_impl ::rs_graph::traits::IndexGraph for #name #ty_generics #indexgraph_where
415        {
416            fn node_id(&self, u: Self::Node<'_>) -> usize {
417                self.#var.node_id(u)
418            }
419
420            fn id2node(&self, id: usize) -> Self::Node<'_> {
421                self.#var.id2node(id)
422            }
423
424            fn edge_id(&self, e: Self::Edge<'_>) -> usize {
425                self.#var.edge_id(e)
426            }
427
428            fn id2edge(&self, id: usize) -> Self::Edge<'_> {
429                self.#var.id2edge(id)
430            }
431        }
432    };
433
434    let mut attrdefs = TokenStream2::new();
435    let mut attrsets = TokenStream2::new();
436    let mut attrsets2 = TokenStream2::new();
437    if let Some(Var {
438        name: attrvar,
439        typ: attrtyp,
440    }) = nodeattrs.as_ref()
441    {
442        expanded.extend(quote! {
443            impl #indexgraph_impl ::rs_graph::attributes::NodeAttributes<#typ, #attrtyp> for #name #ty_generics #indexgraph_where
444            {
445                fn node(&self, u: <#typ as ::rs_graph::traits::GraphType>::Node<'_>) -> &#attrtyp {
446                    &self.#attrvar[self.#var.node_id(u)]
447                }
448
449                fn node_mut(&mut self, u: <#typ as ::rs_graph::traits::GraphType>::Node<'_>) -> &mut #attrtyp {
450                    &mut self.#attrvar[self.#var.node_id(u)]
451                }
452            }
453        });
454        attrdefs.extend(quote!(nodeattrs: &#ident_lt mut [#attrtyp],));
455        attrsets.extend(quote!(nodeattrs: &mut self.#attrvar,));
456        attrsets2.extend(quote!(nodeattrs: self.nodeattrs,));
457    }
458
459    if let Some(Var {
460        name: attrvar,
461        typ: attrtyp,
462    }) = edgeattrs.as_ref()
463    {
464        expanded.extend(quote! {
465            impl #indexgraph_impl ::rs_graph::attributes::EdgeAttributes<#typ, #attrtyp> for #name #ty_generics #indexgraph_where
466            {
467                fn edge(&self, u: <#typ as ::rs_graph::traits::GraphType>::Edge<'_>) -> &#attrtyp {
468                    &self.#attrvar[self.#var.edge_id(u)]
469                }
470
471                fn edge_mut(&mut self, u: <#typ as ::rs_graph::traits::GraphType>::Edge<'_>) -> &mut #attrtyp {
472                    &mut self.#attrvar[self.#var.edge_id(u)]
473                }
474            }
475        });
476        attrdefs.extend(quote!(edgeattrs: &#ident_lt mut [#attrtyp],));
477        attrsets.extend(quote!(edgeattrs: &mut self.#attrvar,));
478        attrsets2.extend(quote!(edgeattrs: self.edgeattrs,));
479    }
480
481    if !attrdefs.is_empty() {
482        let (_, orig_ty_generics, orig_where) = ty_generics.split_for_impl();
483        let attrstruct = format_ident!("{}_Attributes", name);
484        expanded.extend(quote! {
485            #vis struct #attrstruct<#ident_lt> {
486                graph: &#ident_lt #typ,
487                #attrdefs
488            }
489
490            impl #basegraph_impl ::rs_graph::attributes::AttributedGraph for #name #orig_ty_generics #orig_where {
491                type Graph = #typ;
492                type Attributes<#ident_lt> = #attrstruct<#ident_lt>;
493                fn split(&mut self) -> (&#typ, #attrstruct<'_>) {
494                        (
495                            &self.#var,
496                            #attrstruct {
497                                graph: &self.#var,
498                                #attrsets
499                            },
500                        )
501                }
502            }
503
504            // impl ::rs_graph::attributes::AttributedGraph for #attrstruct {
505            //     type Graph = #typ;
506            //     type Attributes<#ident_lt> = #attrstruct<#ident_lt>;
507            //     fn split(&mut self) -> (&#typ, #attrstruct<'_>) {
508            //         (self.graph, #attrstruct {
509            //             graph: self.graph,
510            //             #attrsets2
511            //         })
512            //     }
513            // }
514        });
515
516        if let Some(Var { typ: attrtyp, .. }) = nodeattrs.as_ref() {
517            expanded.extend(quote! {
518                impl<#ident_lt> #indexgraph_impl ::rs_graph::attributes::NodeAttributes<#typ, #attrtyp> for #attrstruct <#ident_lt> #indexgraph_where
519                {
520                    fn node(&self, u: <#typ as ::rs_graph::traits::GraphType>::Node<'_>) -> &#attrtyp {
521                        &self.nodeattrs[self.#var.node_id(u)]
522                    }
523
524                    fn node_mut(&mut self, u: <#typ as ::rs_graph::traits::GraphType>::Node<'_>) -> &mut #attrtyp {
525                        &mut self.nodeattrs[self.#var.node_id(u)]
526                    }
527                }
528            });
529        }
530
531        if let Some(Var { typ: attrtyp, .. }) = edgeattrs.as_ref() {
532            expanded.extend(quote! {
533                impl<#ident_lt> #indexgraph_impl ::rs_graph::attributes::EdgeAttributes<#typ, #attrtyp> for #attrstruct <#ident_lt> #indexgraph_where
534                {
535                    fn edge(&self, u: <#typ as ::rs_graph::traits::GraphType>::Edge<'_>) -> &#attrtyp {
536                        &self.edgeattrs[self.#var.edge_id(u)]
537                    }
538
539                    fn edge_mut(&mut self, u: <#typ as ::rs_graph::traits::GraphType>::Edge<'_>) -> &mut #attrtyp {
540                        &mut self.edgeattrs[self.#var.edge_id(u)]
541                    }
542                }
543            });
544        }
545    }
546
547    expanded
548}
549
550#[proc_macro_derive(Graph, attributes(graph, nodeattrs, edgeattrs))]
551pub fn graph(input: TokenStream) -> TokenStream {
552    graph_derive(TokenStream2::from(input)).into()
553}
554
555#[cfg(test)]
556mod tests {
557    use super::*;
558
559    fn var(name: &str, vartyp: &str) -> Var {
560        Var {
561            name: format_ident!("{}", name),
562            typ: typ(vartyp),
563        }
564    }
565
566    fn typ(t: &str) -> syn::Type {
567        syn::TypePath {
568            qself: None,
569            path: format_ident!("{}", t).into(),
570        }
571        .into()
572    }
573
574    #[test]
575    fn test_parse_simple_graph() {
576        let g = parse_graph_structure(quote!(
577            struct MyGraph {
578                graph: Graph,
579                other: usize,
580            }
581        ));
582        assert_eq!(g.name, "MyGraph");
583        assert_eq!(g.visibility, syn::Visibility::Inherited);
584        assert!(g.generic_parameters.params.is_empty());
585        assert!(g.generic_parameters.where_clause.is_none());
586        assert_eq!(g.graph, var("graph", "Graph"));
587        assert!(g.node_attr.is_none());
588        assert!(g.edge_attr.is_none());
589    }
590
591    #[test]
592    fn test_parse_simple_graph_with_graph_tag() {
593        let g = parse_graph_structure(quote!(
594            struct MyGraph {
595                graph: usize,
596                #[graph]
597                other: Graph,
598            }
599        ));
600        assert_eq!(g.name, "MyGraph");
601        assert_eq!(g.visibility, syn::Visibility::Inherited);
602        assert!(g.generic_parameters.params.is_empty());
603        assert!(g.generic_parameters.where_clause.is_none());
604        assert_eq!(g.graph, var("other", "Graph"));
605        assert!(g.node_attr.is_none());
606        assert!(g.edge_attr.is_none());
607    }
608
609    #[test]
610    #[should_panic]
611    fn test_parse_simple_graph_without_graph_tag() {
612        parse_graph_structure(quote!(
613            struct MyGraph {
614                something: usize,
615                other: Graph,
616            }
617        ));
618    }
619
620    #[test]
621    #[should_panic]
622    fn test_parse_simple_graph_with_multiple_graph_tags() {
623        parse_graph_structure(quote!(
624            struct MyGraph {
625                #[graph]
626                something: Graph,
627                #[graph]
628                other: Graph,
629            }
630        ));
631    }
632
633    #[test]
634    fn test_parse_graph_with_node_attr() {
635        let g = parse_graph_structure(quote!(
636            struct MyGraph {
637                graph: Graph,
638                #[nodeattrs(NodeData)]
639                nodes: Vec<NodeData>,
640            }
641        ));
642        assert_eq!(g.name, "MyGraph");
643        assert_eq!(g.visibility, syn::Visibility::Inherited);
644        assert!(g.generic_parameters.params.is_empty());
645        assert!(g.generic_parameters.where_clause.is_none());
646        assert_eq!(g.graph, var("graph", "Graph"));
647        assert_eq!(g.node_attr, Some(var("nodes", "NodeData")));
648        assert!(g.edge_attr.is_none());
649    }
650
651    #[test]
652    #[should_panic]
653    fn test_parse_graph_with_multiple_node_attr() {
654        parse_graph_structure(quote!(
655            struct MyGraph {
656                graph: Graph,
657                #[nodeattrs(NodeData)]
658                nodes: Vec<NodeData>,
659                #[nodeattrs(NodeData)]
660                nodes2: Vec<NodeData>,
661            }
662        ));
663    }
664
665    #[test]
666    fn test_parse_graph_with_edge_attr() {
667        let g = parse_graph_structure(quote!(
668            struct MyGraph {
669                graph: Graph,
670                #[edgeattrs(EdgeData)]
671                edges: Vec<EdgeData>,
672            }
673        ));
674        assert_eq!(g.name, "MyGraph");
675        assert_eq!(g.visibility, syn::Visibility::Inherited);
676        assert!(g.generic_parameters.params.is_empty());
677        assert!(g.generic_parameters.where_clause.is_none());
678        assert_eq!(g.graph, var("graph", "Graph"));
679        assert!(g.node_attr.is_none());
680        assert_eq!(g.edge_attr, Some(var("edges", "EdgeData")));
681    }
682
683    #[test]
684    #[should_panic]
685    fn test_parse_graph_with_multiple_edge_attr() {
686        parse_graph_structure(quote!(
687            struct MyGraph {
688                graph: Graph,
689                #[edgeattrs(EdgeData)]
690                edges: Vec<EdgeData>,
691                #[edgeattrs(EdgeData)]
692                edges2: Vec<EdgeData>,
693            }
694        ));
695    }
696
697    #[test]
698    fn test_parse_graph_with_visiblity() {
699        let g = parse_graph_structure(quote!(
700            pub struct MyGraph {
701                graph: Graph,
702                other: usize,
703            }
704        ));
705        assert_eq!(g.name, "MyGraph");
706        assert_eq!(
707            g.visibility,
708            syn::VisPublic {
709                pub_token: <Token![pub]>::default().into()
710            }
711            .into()
712        );
713        assert!(g.generic_parameters.params.is_empty());
714        assert!(g.generic_parameters.where_clause.is_none());
715        assert_eq!(g.graph, var("graph", "Graph"));
716        assert!(g.node_attr.is_none());
717        assert!(g.edge_attr.is_none());
718    }
719
720    #[test]
721    fn test_graph_traits() {
722        let generated = graph_derive(quote!(
723            struct MyGraph {
724                graph: Graph,
725            }
726        ));
727
728        let expected = quote! {
729            impl<__rs_graph_I__>::rs_graph::traits::GraphIterator<MyGraph>
730                for ::rs_graph::traits::refs::WrapIt<__rs_graph_I__>
731            where
732                __rs_graph_I__: GraphIterator<Graph>
733            {
734                type Item = __rs_graph_I__::Item;
735                fn next(&mut self, g: &MyGraph) -> Option<Self::Item> {
736                    self.0.next(&g.graph)
737                }
738            }
739        };
740
741        assert!(generated.to_string().starts_with(&expected.to_string()));
742    }
743}