#line 169 "/home/travis/build/felix-lang/felix/src/packages/fibres.fdoc"
  
  Sychronous Channels.
  Used to exchange control and possibly data
  between Felix f-threads (aka fibres).
  
  open class Schannel
  {
    The type of a bidirectional synchronous channel.
    _gc_pointer type schannel[t] = "::flx::rtl::schannel_t*";
  
    The type of an input synchronous channel.
    _gc_pointer type ischannel[t] = "::flx::rtl::schannel_t*";
  
    The type of an output synchronous channel.
    _gc_pointer type oschannel[t] = "::flx::rtl::schannel_t*";
  
    Create a bidirectional synchronous channel.
    gen mk_schannel[t]: 1->schannel[t] =
      "new(*PTF gcp,::flx::rtl::schannel_ptr_map,false) ::flx::rtl::schannel_t(PTF gcp)"
      requires property "needs_gc"
    ;
  
    Model a NULL pointer as an schannel.
    Necessary for killing off schannels,
    so as to make them unreachable, so the gc can reap them.
    Note: null_schannels are safe.
    gen mk_null_schannel[t]: 1->schannel[t] = "NULL";
  
    Model a NULL pointer as an ischannel.
    Necessary for killing off schannels,
    so as to make them unreachable, so the gc can reap them.
    gen mk_null_ischannel[t]: 1->ischannel[t] = "NULL";
  
    Model a NULL pointer as an oschannel.
    Necessary for killing off schannels,
    so as to make them unreachable, so the gc can reap them.
    gen mk_null_oschannel[t]: 1->oschannel[t] = "NULL";
  
    Check if an schannel is NULL.
    fun isNULL[T] :schannel[T] -> bool = "NULL==$1";
  
    Check if an ischannel is NULL.
    fun isNULL[T] :ischannel[T] -> bool = "NULL==$1";
  
    Check if an oschannel is NULL.
    fun isNULL[T] :oschannel[T] -> bool = "NULL==$1";
  
    Safe cast from bidirectional to ouput synchronous channel.
    ctor[t] oschannel[t](x:schannel[t]) => C_hack::cast[oschannel[t]] x;
  
    Safe cast from bidirectional to input synchronous channel.
    ctor[t] ischannel[t](x:schannel[t]) => C_hack::cast[ischannel[t]] x;
  
    Make an input and an output channel out of a bidirectional channel.
    gen mk_ioschannel_pair[t](var ch:schannel[t]) =>
      ischannel[t] ch, oschannel[t] ch
    ;
  
    Construct a connected input and output channel pair.
    gen mk_ioschannel_pair[t]() =>
      mk_ioschannel_pair[t]$ mk_schannel[t] ()
    ;
  
    Read an item from a bidirectional channel.
    inline gen read[T] (chan:schannel[T]) = {
      var loc: &T;
      svc$ svc_sread$ C_hack::cast[_schannel] chan, C_hack::reinterpret[&root::address] (&loc);
      return deref loc;
    }
  
    Read an item from an input channel.
    inline gen read[T] (chan:ischannel[T]) => read$ C_hack::cast[schannel[T]] chan;
  
    Write an item to a bidirectional channel.
    proc write[T] (chan:schannel[T], v:T) {
      var ps = C_hack::cast[root::address]$ new v;
      svc$ svc_swrite$ C_hack::cast[_schannel] chan, &ps;
    }
  
    Multi Write an item to a bidirectional channel.
    proc broadcast[T] (chan:schannel[T], v:T) {
      var ps = C_hack::cast[root::address]$ new v;
      svc$ svc_multi_swrite$ C_hack::cast[_schannel] chan, &ps;
    }
  
    Multi Write an item to an output channel.
    proc write[T] (chan:oschannel[T], v:T) {
      write (C_hack::cast[schannel[T]] chan, v);
    }
    proc broadcast[T] (chan:oschannel[T], v:T) {
      broadcast (C_hack::cast[schannel[T]] chan, v);
    }
  
    // Very high power though not very efficient conversion
    // from ischannel to iterator.
    // Given i: ischannel[T] you can just write
    // for j in i do .. done
    gen iterator[T] (i:ischannel[T]) () : opt[T] = {
    next:>
      var y = None[T];
      frun { var x = read i; y = Some x; };
      match y do
      | Some _ => yield y; goto next;
      | None => return y;
      done
    }
  }