Macro graphene::custom_graph [] [src]

macro_rules! custom_graph {
    {
		pub $($rest:tt)*
	} => { ... };
    {
		struct $($rest:tt)*
	} => { ... };
    {
		[ @privacy $($stack:tt)* ]
		struct $struct_name:ident
		$($rest:tt)*
	} => { ... };
    {	// There might not be any generics for the structs so accept
		// backing graph immediately and put empty generics on the stack
		[ @struct_name $($stack:tt)* ]
		as $base_graph_name:ident $($rest:tt)*
	} => { ... };
    {	// If the generics of the struct are done, accept the base graph name
		[ @generics $($stack:tt)* ]
		as $base_graph_name:ident $($rest:tt)*
	} => { ... };
    {
		//Can only specify wrappers to use after the definition of the backing struct
		//the '@generics' ensures that the last thing to parse is a generic group
		[  @generics $($stack:tt)* ]
		use $($rest:tt)*
	} => { ... };
    {	//Can specify constraints after the wrappers are done
		[ @constraint_wrappers[$($wraps:tt)*] $($stack:tt)* ]
		$(,)*impl $($rest:tt)*
	} => { ... };
    {	//Can specify constraints after the generics of the base graph
		[ @generics $base_graph_generics:tt @base_graph_name $($stack:tt)* ]
		impl $($rest:tt)*
	} => { ... };
    {	//If the last thing to be decoded is the base graphs generics
		// Add empty blocks for wrappers
		[ @generics $base_g:tt @base_graph_name $($stack:tt)*] where $($rest:tt)*
	} => { ... };
    {	//If the last thing to be decoded is the constaint wrappers
		// Add empty blocks for wrappers
		[ @constraint_wrappers $($stack:tt)*] $(,)*where $($rest:tt)*
	} => { ... };
    {	//If the last thing to be decoded is the constraints
		// then we are ready to decode the rest of the input
		// as being in the 'where clause'
		[ @constraints $($stack:tt)*] $(,)* where $($rest:tt)*
	} => { ... };
    {	// While grouping 'where' groups if you encounter a ',' but there is more
		// input, it means the group is done, and there is a new one.
		// so ready a new group.
		[ @where_clause[[$($current_group:tt)*] $($rest_groups:tt)*] $($stack:tt)*]
		$next:tt , $($rest:tt)+
	} => { ... };
    {	// While grouping 'where' groups if you encounter a ',' and there is no more
		// input, the where clause is done.
		[ @where_clause[[$($current_group:tt)*] $($rest_groups:tt)*] $($stack:tt)*]
		$next:tt ,
	} => { ... };
    {	// While grouping 'where' groups if you dont encounter a ','
		// you add the token to the current group
		[ @where_clause[[$($current_group:tt)*] $($rest_groups:tt)*] $($stack:tt)*]
		$next:tt $($rest:tt)*
	} => { ... };
    { //Start generics after struct declaration
		[ @struct_name $($stack:tt)*]
		< $($rest:tt)*
	} => { ... };
    { //Start generics after base graph declaration
		[ @base_graph_name $($stack:tt)*]
		< $($rest:tt)*
	} => { ... };
    { //Stop generics
		[@generics[$($generics:tt)*] $($stack:tt)*]
		> $($rest:tt)*
	} => { ... };
    { //Continue generics
		[@generics[$($generics:tt)*] $($stack:tt)*]
		$next:tt $($rest:tt)*
	} => { ... };
    {
		// If the previous token was an identifier, require a ','
		[ @constraint_wrappers[$w:ident $($prev:tt)*] $($stack:tt)* ]
		, $v:ident $($rest:tt)*
	} => { ... };
    {
		// Previous token wasn't an identifier, no ','
		[@constraint_wrappers[$($prev:tt)*] $($stack:tt)* ]
		$v:ident $($rest:tt)*
	} => { ... };
    {
		// The first contraint does have to have ',' before it
		[ @constraints[] $($stack:tt)* ]
		$v:ident $($rest:tt)*
	} => { ... };
    {
		// next constraint needs a comma
		[@constraints[ $($other_constraints:tt)+ ] $($stack:tt)* ]
		, $next:ident $($rest:tt)*
	} => { ... };
    {
		@add_until
		[[$($into:tt)*] $($stack:tt)*]
		[$next:tt > $($rest:tt)*]
		>
	} => { ... };
    {	//If the last thing to be decoded is generics, there must not be any
		// wrappers, constraints or 'where' defined.
		// Therefore, define empty wrappers
		[ @generics $($stack:tt)*]
	} => { ... };
    {	//If the last thing to be decoded are wrappers,
		// there must not be constraints or 'where' defined.
		// Therefore, define empty constraints
		[ @constraint_wrappers $($stack:tt)*] $(,)*
	} => { ... };
    {	//If the last thing to be decoded are constraints,
		// there must not be a 'where' defined.
		// Therefore, define an empty 'where' block
		[ @constraints $($stack:tt)*] $(,)*
	} => { ... };
    {	// If the last block is 'where' we are done decoding
		[ @where_clause $($stack:tt)*]
	} => { ... };
    {
		@declare_struct_and_impl_minimum
		[$($stack:tt)*]
	} => { ... };
    {
		@declare_struct
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy[]
		]
	} => { ... };
    {
		@declare_struct
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy[pub]
		]
	} => { ... };
    {
		@impl_graph_wrapper
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*]@struct_name[$struct_name:ident]
			@privacy$privacy:tt
		]
	} => { ... };
    {
		@impl_base_graph
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[<$T1:ty,$T2:ty>] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy$privacy:tt
		]
	} => { ... };
    {
		@impl_contained_graph
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy$privacy:tt
		]
	} => { ... };
    {
		@derive_debug
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy$privacy:tt
		]
	} => { ... };
    {
		@derive_clone
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[$($constraints:tt)*] @constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy$privacy:tt
		]
	} => { ... };
    {
		@impl_constraint_traits
		[	@where_clause[$([$($where_clause:tt)*])*]
			@constraints[[$first_con_trait:ident] $($constraints:tt)*]
			@constraint_wrappers[$($constraint_wrappers:tt)*]
			@generics[$($base_generics:tt)*] @base_graph_name[$base_graph_name:ident]
			@generics[$($struct_generics:tt)*] @struct_name[$struct_name:ident]
			@privacy$privacy:tt
		]
	} => { ... };
    {
		@impl_constraint_traits
		// When all but all constraints have been implemented, as we are done.
		[	@where_clause $where_clause:tt
			@constraints[] $($rest_stack:tt)*]
	} => { ... };
    {
		@as_associated
		$($rest:tt)*
	} => { ... };
    {
		@in_struct
		$con_graph:ident,$base_graph_name:ident >>
		$($rest:tt)*
	} => { ... };
    {
		@in_struct
		$base_graph_name:ident $($base_generics:tt)*
	} => { ... };
}

Declares a custom graph with a specific set of constraints:

#[macro_use]
extern crate graphene;

use graphene::core::{
    Vertex,Weight,GraphWrapper,
    constraint::{Unique,Undirected,UniqueGraph,UndirectedGraph}
};
use graphene::common::{AdjListGraph};

custom_graph!{
    pub struct MyGraph<V,W>
    as AdjListGraph<V,W>
    use UndirectedGraph, UniqueGraph
    impl Undirected, Unique
    where V: Vertex, W: Weight
}
fn main(){}

Syntax

  • (pub) struct : Defines the name of the graph struct to be created. Also defines the visibility of it in the usual syntax.

  • as : The graph implementation to back up the created struct. The struct is therefore just a wrapper around the backing implmentation.

  • use : Graph wrappers to wrap around the backing graph to ensure the chosen constraints are supported. The struct is then wrapped around these wrappers.

  • impl : Which constraints the struct implements. It is the users responsibility to ensure that the struct, its backing graph and the wrappers together maintain the required invariants of there constraints.

  • where : Trait bounds on any generic type.

The struct and as clauses are mandatory. use is optional, but, if present, must be followed by the impl clause, while impl may appear without the use clause. The where is optional as needed by the type system like any other where clause.

The above invocation of the macro can be read as follows:

Declare the public struct MyGraph as an AdjListGraph using UndirectedGraph and UniqueGraph to implement the constraints Undirected and Unique.

Produces

The resulting graph is a wrapper around the types given in the as and use clauses. The macro guarantees that the struct implements the basic graph traits (most notably BaseGraph and ConstrainedGraph. Additionally, the traits in the impl clause (and they should be constraint traits only), are implemented regardless of whether their invariants are maintained by the resulting struct. Therefore, the user should make sure that the specified backing graph and wrappers actually implement the constraint type that are specified.

Other than that, the struct is ready to use as a full blown graph without any need to implement anything else (excepting task specific functionality).