1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::sync::Arc;
use async_std::task;
use async_macros::join;
use async_std::sync::{ channel };

use crate::base::{
  Protocol,
  Session,
  Context,
  AppendContext,
  PartialSession,
  unsafe_run_session,
  unsafe_create_session,
};

use crate::functional::nat::*;

pub struct PersistentSession < P >
where
  P : Protocol
{
  new_session : Arc <
    dyn Fn () -> Session < P >
      + Send + Sync
  >
}

impl < P >
  Clone for
  PersistentSession < P >
where
  P : Protocol
{
  fn clone(&self) -> Self {
    PersistentSession {
      new_session : self.new_session.clone()
    }
  }
}

pub fn create_persistent_session
  < F, P >
  (f : F)
  -> PersistentSession < P >
where
  P : Protocol,
  F : Fn () -> Session < P >
      + Send + Sync + 'static
{
  return PersistentSession {
    new_session: Arc::new ( f )
  }
}

pub fn
  clone_session
  < I, P, Q, F >
  ( session1 : &PersistentSession < P >,
    cont_builder : F
  ) ->
    PartialSession < I, Q >
where
  P : Protocol,
  Q : Protocol,
  I : Context,
  I : AppendContext < ( P, () ) >,
  F : FnOnce
        ( I::Length )
        ->
          PartialSession <
            < I as
              AppendContext <
                ( P, () )
              >
            > :: Appended,
            Q
          >
{
  let session2 = session1.clone();

  let cont = cont_builder (
    I::Length::nat()
  );

  unsafe_create_session (
    move | ctx1, sender1 | async move {
      let session3 = (session2.new_session)();

      let (sender2, receiver2) = channel(1);

      let child1 = task::spawn(async move {
        unsafe_run_session
          ( session3, (), sender2
          ).await;
      });

      let ctx2 =
        < I as
          AppendContext <
            ( P, () )
          >
        > :: append_context ( ctx1, (receiver2, ()) );

      let child2 = task::spawn(async move {
        unsafe_run_session
          ( cont, ctx2, sender1
          ).await;
      });

      join!(child1, child2).await;
    })
}