pub( crate ) mod private
{
  use crate::prelude::*;
  
  macro_rules! NODE_ID
  {
    () => { < < Self as GraphNodesNominalInterface >::NodeHandle as HasId >::Id };
  }
  macro_rules! EDGE_ID
  {
    () => { < < Self as GraphEdgesNominalInterface >::EdgeHandle as HasId >::Id };
  }
      
  pub trait GraphNodesNominalInterface
  {
                type NodeHandle : NodeBasicInterface;
        #[ allow( non_snake_case ) ]
    #[ inline ]
    fn NodeId< Id >( id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    {
      id.into()
    }
        #[ inline ]
    fn node_id< Id >( &self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    {
      id.into()
    }
        fn node< Id >( &self, id : Id ) -> &Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;
                                
                            
        fn out_nodes_ids< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = NODE_ID!() > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    ;
        fn out_nodes< 'a, 'b, Id >( &'a self, node_id : Id )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      Id : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_nodes_ids( node_id ).map( | id |
      {
        ( id, self.node( id ) )
      }))
    }
  }
      
  pub trait GraphEdgesNominalInterface
  where
    Self : GraphNodesNominalInterface,
  {
                type EdgeHandle : EdgeBasicInterface;
        #[ allow( non_snake_case ) ]
    #[ inline ]
    fn EdgeId< Id >( id : Id ) -> EDGE_ID!()
    where
      Id : Into< EDGE_ID!() >
    {
      id.into()
    }
        #[ inline ]
    fn edge_id< Id >( &self, id : Id ) -> EDGE_ID!()
    where
      Id : Into< EDGE_ID!() >
    {
      Self::EdgeId( id )
    }
        fn edge< Id >( &self, id : Id ) -> &Self::EdgeHandle
    where
      Id : Into< EDGE_ID!() >
    ;
        fn out_edges_ids< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = EDGE_ID!() > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    ;
        fn out_edges< 'a, 'b, IntoId >( &'a self, node_id : IntoId )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      IntoId : Into< NODE_ID!() >,
      'a : 'b,
    {
      Box::new( self.out_edges_ids( node_id ).map( | id |
      {
        ( id, self.edge( id ) )
      }))
    }
  }
      
    pub trait GraphNodesEnumerableInterface
  where
    Self : GraphNodesNominalInterface,
              {
                    
        fn nodes< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( NODE_ID!(), &< Self as GraphNodesNominalInterface >::NodeHandle ) > + 'b >
    where
      'a : 'b,
    ;
        fn nnodes( &self ) -> usize
    {
      self.nodes().count()
    }
  }
      
  pub trait GraphEdgesEnumerableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {
        fn edges< 'a, 'b >( &'a self )
    ->
    Box< dyn Iterator< Item = ( EDGE_ID!(), &< Self as GraphEdgesNominalInterface >::EdgeHandle ) > + 'b >
    where
      'a : 'b,
    ;
        fn nedges( &self ) -> usize
    {
      self.edges().count()
    }
  }
      
  pub trait GraphNodesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
    ,
  {
        fn node_mut< Id >( &mut self, id : Id ) -> &mut Self::NodeHandle
    where
      Id : Into< NODE_ID!() >
    ;
        fn node_add_out_nodes< IntoId1, IntoId2, Iter >
    (
      &mut self,
      node_id : IntoId1,
      out_nodes_iter : Iter,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId2 : Into< NODE_ID!() >,
      Iter : IntoIterator< Item = IntoId2 >,
      Iter::IntoIter : Clone,
    ;
        fn node_add_out_node< IntoId1, IntoId2 >
    (
      &mut self,
      node_id : IntoId1,
      out_node_id : IntoId2,
    )
    where
      IntoId1 : Into< NODE_ID!() >,
      IntoId1 : Clone,
      IntoId2 : Into< NODE_ID!() >,
      IntoId2 : Clone,
    {
      self.node_add_out_nodes( node_id, core::iter::once( out_node_id ) );
    }
        fn node_making< Id >( &mut self, id : Id ) -> NODE_ID!()
    where
      Id : Into< NODE_ID!() >
    ;
        fn make_with_edge_list< IntoIter, Id >( &mut self, into_iter : IntoIter )
    where
      Id : Into< NODE_ID!() >,
      IntoIter : IntoIterator< Item = Id >,
      IntoIter::IntoIter : core::iter::ExactSizeIterator< Item = Id >,
    {
      use wtools::iter::prelude::*;
      let iter = into_iter.into_iter();
      debug_assert_eq!( iter.len() % 2, 0 );
      for mut chunk in &iter.chunks( 2 )
      {
        let id1 = chunk.next().unwrap().into();
        let id2 = chunk.next().unwrap().into();
        self.node_making( id1 );
        self.node_making( id2 );
        self.node_add_out_node( id1, id2 );
      }
    }
  }
      
  pub trait GraphEdgesExtendableInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
      GraphNodesExtendableInterface +
    ,
  {
        fn _edge_id_generate( &mut self, node1 : NODE_ID!(), node2 : NODE_ID!() ) -> EDGE_ID!();
        fn _edge_add( &mut self, edge_id : EDGE_ID!(), node1 : NODE_ID!(), node2 : NODE_ID!() );
        fn _edge_make_for_nodes< IntoNodeId1, IntoNodeId2 >( &mut self, node1 : IntoNodeId1, node2 : IntoNodeId2 ) -> EDGE_ID!()
    where
      IntoNodeId1 : Into< NODE_ID!() >,
      IntoNodeId2 : Into< NODE_ID!() >,
    {
      let node1 = node1.into();
      let node2 = node2.into();
      let edge = self._edge_id_generate( node1, node2 );
      self._edge_add( edge, node1, node2 );
      edge
    }
  }
      
  pub trait GraphNodesKindGetterInterface
  where
    Self : GraphNodesNominalInterface,
  {
        type NodeKind : crate::NodeKindInterface;
        fn node_kind( &self, node_id : NODE_ID!() ) -> Self::NodeKind;
  }
      
  pub trait GraphEdgesKindGetterInterface
  where
    Self :
      GraphNodesNominalInterface +
      GraphEdgesNominalInterface +
    ,
  {
        type EdgeKind : crate::EdgeKindInterface;
        fn edge_kind( &self, edge_id : EDGE_ID!() ) -> Self::EdgeKind;
  }
}
pub mod protected
{
  pub use super::orphan::*;
}
pub use protected::*;
pub mod orphan
{
  pub use super::exposed::*;
}
pub mod exposed
{
  pub use super::prelude::*;
}
pub use exposed::*;
pub mod prelude
{
  pub use super::private::
  {
    GraphNodesNominalInterface,
        GraphEdgesNominalInterface,
    GraphNodesEnumerableInterface,
    GraphEdgesEnumerableInterface,
    GraphNodesExtendableInterface,
    GraphEdgesExtendableInterface,
    GraphNodesKindGetterInterface,
    GraphEdgesKindGetterInterface,
  };
}