public Value ReadValue()
        {
            Value val = null;
            CsFaslTags type = (CsFaslTags)_br.ReadByte();
            switch(type)
            {
                case CsFaslTags.CsFaslTagUndefined:
                    val = new Value { type = CsFaslTags.CsFaslTagUndefined };
                    break;

                case CsFaslTags.CsFaslTagNull:
                    val = new Value { type = CsFaslTags.CsFaslTagNull };
                    break;

                case CsFaslTags.CsFaslTagTrue:
                    val = new Value { type = CsFaslTags.CsFaslTagTrue };
                    break;

                case CsFaslTags.CsFaslTagFalse:
                    val = new Value { type = CsFaslTags.CsFaslTagFalse };
                    break;

                case CsFaslTags.CsFaslTagProxy:
                    int id = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    val = new Value { type = CsFaslTags.CsFaslTagProxy, intPayload = id };
                    break;

                case CsFaslTags.CsFaslTagCode:
                    int codesz = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    Debug.Assert(false);
                    // TODO
                    break;

                case CsFaslTags.CsFaslTagVector:
                    int vectorsz = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    ValueVector vector = new ValueVector();
                    vector.values = new Value[vectorsz];
                    for(int i = 0; i < vectorsz; i++)
                        vector.values[i] = this.ReadValue();
                    val = vector;
                    break;

                case CsFaslTags.CsFaslTagObject:
                    CsFaslTags undefined = (CsFaslTags)_br.ReadByte();// TODO("handle class names!")
                    int prop_count = IPAddress.NetworkToHostOrder(_br.ReadInt32());

                    ValueObject obj = new ValueObject();
                    obj.props = new Dictionary<string, Value>(prop_count);

                    for(int i = 0; i < prop_count; i++)
                    {
                        Value vprop = this.ReadValue();
                        Value vvalue = this.ReadValue();

                        if(vprop.type == CsFaslTags.CsFaslTagSymbol)
                        {
                            string key = (vprop as ValueSymbol).sym;
                            obj.props.Add(key, vvalue);
                        }
                        else
                        {
                            Debug.Assert(false);
                        }
                    }
                    val = obj;
                    break;

                case CsFaslTags.CsFaslTagSymbol:
                    int symID = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    val = new ValueSymbol { sym = _id2symbol[symID] };
                    break;

                case CsFaslTags.CsFaslTagString:
                    int strsz = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    var bytes = _br.ReadBytes(strsz);
                    val = new ValueString { str = Encoding.UTF8.GetString(bytes) };
                    break;

                case CsFaslTags.CsFaslTagInteger:
                    val = new Value { type = CsFaslTags.CsFaslTagInteger, intPayload = IPAddress.NetworkToHostOrder(_br.ReadInt32()) };
                    break;

                case CsFaslTags.CsFaslTagFloat:
                    long f = _br.ReadInt64();
                    val = new ValueFloat { d = BitConverter.Int64BitsToDouble(IPAddress.NetworkToHostOrder(f)) };
                    break;

                case CsFaslTags.CsFaslTagBytes:
                    int bytessz = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    val = new ValueBytes { bytes = _br.ReadBytes(bytessz) };
                    break;

                case CsFaslTags.CsFaslTagDate:
                    long ft = IPAddress.NetworkToHostOrder(_br.ReadInt64());
                    val = new ValueDate { dt = DateTime.FromFileTime(ft) };
                    break;

                case CsFaslTags.CsFaslTagColor:
                    val = new Value { type = CsFaslTags.CsFaslTagColor, intPayload = IPAddress.NetworkToHostOrder(_br.ReadInt32()) };
                    break;

                case CsFaslTags.CsFaslTagLength:
                    val = new ValueLength
                    {
                        n = IPAddress.NetworkToHostOrder(_br.ReadInt32()),
                        u = IPAddress.NetworkToHostOrder(_br.ReadInt32())
                    };
                    break;

                case CsFaslTags.CsFaslTagTuple:
                    Value val_name = ReadValue();
                    Debug.Assert(val_name.type == CsFaslTags.CsFaslTagString);

                    int tuple_sz = IPAddress.NetworkToHostOrder(_br.ReadInt32());
                    ValueTuple val_tuple = new ValueTuple { name = val_name, values = new Value[tuple_sz] };
                    for(int i = 0; i < tuple_sz; i++)
                        val_tuple.values[i] = ReadValue();
                    val = val_tuple;
                    break;

                case CsFaslTags.CsFaslTagAngle:
                    val = new ValueAngle
                    {
                        n = IPAddress.NetworkToHostOrder(_br.ReadInt32()),
                        u = IPAddress.NetworkToHostOrder(_br.ReadInt32())
                    };
                    break;

                case CsFaslTags.CsFaslTagDuration:
                    long l = IPAddress.NetworkToHostOrder(_br.ReadInt64());
                    double d = BitConverter.Int64BitsToDouble(l);
                    val = new ValueDuration { dur = TimeSpan.FromSeconds(d) };
                    break;

                default:
                    Debug.Assert(false);
                    break;
            }
            return val;
        }
 public static Value Create(Value[] arr)
 {
     return new ValueVector { values = arr };
 }
 public void Send(Value val)
 {
     PrepareValue(val);// we need to prepare before we write the header
     WriteHeader();
     WriteValue(val);
     Flush();
 }
        public void WriteValue(Value val)
        {
            _bw.Write((byte)val.type);

            switch(val.type)
            {
                case CsFaslTags.CsFaslTagUndefined:
                case CsFaslTags.CsFaslTagNull:
                case CsFaslTags.CsFaslTagTrue:
                case CsFaslTags.CsFaslTagFalse:
                case CsFaslTags.CsFaslTagInteger:
                case CsFaslTags.CsFaslTagProxy:
                case CsFaslTags.CsFaslTagSymbol:
                case CsFaslTags.CsFaslTagColor:
                    _bw.Write(IPAddress.HostToNetworkOrder(val.intPayload));
                    break;

                case CsFaslTags.CsFaslTagFloat:
                    long l = BitConverter.DoubleToInt64Bits((val as ValueFloat).d);
                    _bw.Write(IPAddress.HostToNetworkOrder(l));
                    break;

                case CsFaslTags.CsFaslTagCode:
                    // TODO
                    break;

                case CsFaslTags.CsFaslTagVector:
                    ValueVector vector = (ValueVector)val;
                    _bw.Write(IPAddress.HostToNetworkOrder(vector.values.Length));
                    foreach(var item in vector.values)
                        WriteValue(item);
                    break;

                case CsFaslTags.CsFaslTagObject:
                    ValueObject obj = (ValueObject)val;
                    _bw.Write((byte)CsFaslTags.CsFaslTagUndefined);
                    _bw.Write(IPAddress.HostToNetworkOrder(obj.props.Count));

                    foreach(var item in obj.props)
                    {
                        int id = _symbol2id[item.Key];
                        _bw.Write((byte)CsFaslTags.CsFaslTagSymbol);
                        _bw.Write(IPAddress.HostToNetworkOrder(id));
                        WriteValue(item.Value);
                    }
                    break;

                case CsFaslTags.CsFaslTagString:
                    ValueString str = (ValueString)val;
                    _bw.Write(IPAddress.HostToNetworkOrder(str.str.Length));
                    _bw.Write(Encoding.UTF8.GetBytes(str.str));
                    break;

                case CsFaslTags.CsFaslTagBytes:
                    ValueBytes by = (ValueBytes)val;
                    _bw.Write(IPAddress.HostToNetworkOrder(by.bytes.Length));
                    _bw.Write(by.bytes);
                    break;

                case CsFaslTags.CsFaslTagDate:
                    ValueDate dt = (ValueDate)val;
                    long ft = dt.dt.ToFileTimeUtc();
                    _bw.Write(IPAddress.HostToNetworkOrder(ft));
                    break;

                case CsFaslTags.CsFaslTagLength:
                    ValueLength len = (ValueLength)val;
                    _bw.Write(IPAddress.HostToNetworkOrder(len.n));
                    _bw.Write(IPAddress.HostToNetworkOrder(len.u));
                    break;

                case CsFaslTags.CsFaslTagTuple:
                    ValueTuple tup = (ValueTuple)val;
                    WriteValue(tup.name);
                    _bw.Write(IPAddress.HostToNetworkOrder(tup.values.Length));
                    foreach(var item in tup.values)
                        WriteValue(item);
                    break;

                case CsFaslTags.CsFaslTagAngle:
                    ValueAngle ang = (ValueAngle)val;
                    _bw.Write(IPAddress.HostToNetworkOrder(ang.n));
                    _bw.Write(IPAddress.HostToNetworkOrder(ang.u));
                    break;

                case CsFaslTags.CsFaslTagDuration:
                    ValueDuration dur = (ValueDuration)val;
                    _bw.Write(dur.dur.TotalSeconds);
                    break;

                default:
                    Debug.Assert(false);
                    break;
            }
        }
 public void PrepareValue(Value val)
 {
     if(val.type == CsFaslTags.CsFaslTagObject)
     {
         foreach(var item in (val as ValueObject).props)
         {
             if(!_symbol2id.ContainsKey(item.Key))
                 _symbol2id[item.Key] = _symbol2id.Count;
             PrepareValue(item.Value);
         }
     }
     else if(val.type == CsFaslTags.CsFaslTagVector)
     {
         foreach(var item in (val as ValueVector).values)
             PrepareValue(item);
     }
     else if(val.type == CsFaslTags.CsFaslTagTuple)
     {
         foreach(var item in (val as ValueTuple).values)
             PrepareValue(item);
     }
     else if(val.type == CsFaslTags.CsFaslTagSymbol)
     {
         ValueSymbol vsym = (ValueSymbol)val;
         if(!_symbol2id.ContainsKey(vsym.sym))
             _symbol2id[vsym.sym] = _symbol2id.Count;
     }
 }