You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by cl...@apache.org on 2011/02/20 03:39:21 UTC

svn commit: r1072478 [4/8] - in /thrift/trunk: ./ compiler/cpp/ compiler/cpp/src/generate/ lib/ lib/go/ lib/go/thrift/ test/ tutorial/go/ tutorial/go/src/

Added: thrift/trunk/lib/go/thrift/tframed_transport.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tframed_transport.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tframed_transport.go (added)
+++ thrift/trunk/lib/go/thrift/tframed_transport.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "encoding/binary"
+  "bytes"
+  "os"
+)
+
+
+type TFramedTransport struct {
+  transport   TTransport
+  writeBuffer *bytes.Buffer
+  readBuffer  *bytes.Buffer
+}
+
+type tFramedTransportFactory struct {
+  factory TTransportFactory
+}
+
+func NewTFramedTransportFactory(factory TTransportFactory) TTransportFactory {
+  return &tFramedTransportFactory{factory: factory}
+}
+
+func (p *tFramedTransportFactory) GetTransport(base TTransport) TTransport {
+  return NewTFramedTransport(p.factory.GetTransport(base))
+}
+
+func NewTFramedTransport(transport TTransport) *TFramedTransport {
+  writeBuf := make([]byte, 0, 1024)
+  readBuf := make([]byte, 0, 1024)
+  return &TFramedTransport{transport: transport, writeBuffer: bytes.NewBuffer(writeBuf), readBuffer: bytes.NewBuffer(readBuf)}
+}
+
+func (p *TFramedTransport) Open() os.Error {
+  return p.transport.Open()
+}
+
+func (p *TFramedTransport) IsOpen() bool {
+  return p.transport.IsOpen()
+}
+
+func (p *TFramedTransport) Peek() bool {
+  return p.transport.Peek()
+}
+
+func (p *TFramedTransport) Close() os.Error {
+  return p.transport.Close()
+}
+
+func (p *TFramedTransport) Read(buf []byte) (int, os.Error) {
+  if p.readBuffer.Len() > 0 {
+    got, err := p.readBuffer.Read(buf)
+    if got > 0 {
+      return got, NewTTransportExceptionFromOsError(err)
+    }
+  }
+
+  // Read another frame of data
+  p.readFrame()
+
+  got, err := p.readBuffer.Read(buf)
+  return got, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TFramedTransport) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *TFramedTransport) Write(buf []byte) (int, os.Error) {
+  n, err := p.writeBuffer.Write(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TFramedTransport) Flush() os.Error {
+  size := p.writeBuffer.Len()
+  buf := []byte{0, 0, 0, 0}
+  binary.BigEndian.PutUint32(buf, uint32(size))
+  _, err := p.transport.Write(buf)
+  if err != nil {
+    return NewTTransportExceptionFromOsError(err)
+  }
+  if size > 0 {
+    n, err := p.writeBuffer.WriteTo(p.transport)
+    if err != nil {
+      print("Error while flushing write buffer of size ", size, " to transport, only wrote ", n, " bytes: ", err.String(), "\n")
+      return NewTTransportExceptionFromOsError(err)
+    }
+  }
+  err = p.transport.Flush()
+  return NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TFramedTransport) readFrame() (int, os.Error) {
+  buf := []byte{0, 0, 0, 0}
+  _, err := p.transport.ReadAll(buf)
+  if err != nil {
+    return 0, err
+  }
+  size := int(binary.BigEndian.Uint32(buf))
+  if size < 0 {
+    // TODO(pomack) log error
+    return 0, NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "Read a negative frame size ("+string(size)+")")
+  }
+  if size == 0 {
+    return 0, nil
+  }
+  buf2 := make([]byte, size)
+  n, err := p.transport.ReadAll(buf2)
+  if err != nil {
+    return n, err
+  }
+  p.readBuffer = bytes.NewBuffer(buf2)
+  return size, nil
+}

Added: thrift/trunk/lib/go/thrift/tframed_transport_test.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tframed_transport_test.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tframed_transport_test.go (added)
+++ thrift/trunk/lib/go/thrift/tframed_transport_test.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+)
+
+func TestFramedTransport(t *testing.T) {
+  trans := NewTFramedTransport(NewTMemoryBuffer())
+  TransportTest(t, trans, trans)
+}

Added: thrift/trunk/lib/go/thrift/thttp_client.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/thttp_client.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/thttp_client.go (added)
+++ thrift/trunk/lib/go/thrift/thttp_client.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "bytes"
+  "http"
+  "os"
+)
+
+
+type THttpClient struct {
+  response           *http.Response
+  url                *http.URL
+  requestBuffer      *bytes.Buffer
+  nsecConnectTimeout int64
+  nsecReadTimeout    int64
+}
+
+type THttpClientTransportFactory struct {
+  url    string
+  isPost bool
+}
+
+func (p *THttpClientTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*THttpClient)
+    if ok && t.url != nil {
+      if t.requestBuffer != nil {
+        t2, _ := NewTHttpPostClient(t.url.String())
+        return t2
+      }
+      t2, _ := NewTHttpClient(t.url.String())
+      return t2
+    }
+  }
+  if p.isPost {
+    s, _ := NewTHttpPostClient(p.url)
+    return s
+  }
+  s, _ := NewTHttpClient(p.url)
+  return s
+}
+
+func NewTHttpClientTransportFactory(url string) *THttpClientTransportFactory {
+  return &THttpClientTransportFactory{url: url, isPost: false}
+}
+
+func NewTHttpPostClientTransportFactory(url string) *THttpClientTransportFactory {
+  return &THttpClientTransportFactory{url: url, isPost: true}
+}
+
+
+func NewTHttpClient(url string) (TTransport, os.Error) {
+  response, finalUrl, err := http.Get(url)
+  if err != nil {
+    return nil, err
+  }
+  parsedURL, err := http.ParseURL(finalUrl)
+  if err != nil {
+    return nil, err
+  }
+  return &THttpClient{response: response, url: parsedURL}, nil
+}
+
+func NewTHttpPostClient(url string) (TTransport, os.Error) {
+  parsedURL, err := http.ParseURL(url)
+  if err != nil {
+    return nil, err
+  }
+  buf := make([]byte, 0, 1024)
+  return &THttpClient{url: parsedURL, requestBuffer: bytes.NewBuffer(buf)}, nil
+}
+
+func (p *THttpClient) Open() os.Error {
+  // do nothing
+  return nil
+}
+
+func (p *THttpClient) IsOpen() bool {
+  return p.response != nil || p.requestBuffer != nil
+}
+
+func (p *THttpClient) Peek() bool {
+  return p.IsOpen()
+}
+
+func (p *THttpClient) Close() os.Error {
+  if p.response != nil && p.response.Body != nil {
+    err := p.response.Body.Close()
+    p.response = nil
+    return err
+  }
+  if p.requestBuffer != nil {
+    p.requestBuffer.Reset()
+    p.requestBuffer = nil
+  }
+  return nil
+}
+
+func (p *THttpClient) Read(buf []byte) (int, os.Error) {
+  if p.response == nil {
+    return 0, NewTTransportException(NOT_OPEN, "Response buffer is empty, no request.")
+  }
+  n, err := p.response.Body.Read(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *THttpClient) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *THttpClient) Write(buf []byte) (int, os.Error) {
+  n, err := p.requestBuffer.Write(buf)
+  return n, err
+}
+
+func (p *THttpClient) Flush() os.Error {
+  response, err := http.Post(p.url.String(), "application/x-thrift", p.requestBuffer)
+  if err != nil {
+    return NewTTransportExceptionFromOsError(err)
+  }
+  if response.StatusCode != http.StatusOK {
+    // TODO(pomack) log bad response
+    return NewTTransportException(UNKNOWN_TRANSPORT_EXCEPTION, "HTTP Response code: "+string(response.StatusCode))
+  }
+  p.response = response
+  return nil
+}

Added: thrift/trunk/lib/go/thrift/thttp_client_test.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/thttp_client_test.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/thttp_client_test.go (added)
+++ thrift/trunk/lib/go/thrift/thttp_client_test.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "http"
+  "net"
+)
+
+func TestHttpClient(t *testing.T) {
+  addr, err := FindAvailableTCPServerPort(40000)
+  if err != nil {
+    t.Fatalf("Unable to find available tcp port addr: %s", err)
+  }
+  l, err := net.Listen(addr.Network(), addr.String())
+  if err != nil {
+    t.Fatalf("Unable to setup tcp listener on %s: %s", addr.String(), err)
+  }
+  go http.Serve(l, &HTTPEchoServer{})
+  trans, err := NewTHttpPostClient("http://" + addr.String())
+  if err != nil {
+    l.Close()
+    t.Fatalf("Unable to connect to %s: %s", addr.String(), err)
+  }
+  TransportTest(t, trans, trans)
+}

Added: thrift/trunk/lib/go/thrift/tiostream_transport.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tiostream_transport.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tiostream_transport.go (added)
+++ thrift/trunk/lib/go/thrift/tiostream_transport.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "bufio"
+  "io"
+  "os"
+)
+
+/**
+ * This is the most commonly used base transport. It takes an InputStream
+ * and an OutputStream and uses those to perform all transport operations.
+ * This allows for compatibility with all the nice constructs Java already
+ * has to provide a variety of types of streams.
+ *
+ */
+type TIOStreamTransport struct {
+  Reader       io.Reader
+  Writer       io.Writer
+  IsReadWriter bool
+}
+
+type TIOStreamTransportFactory struct {
+  Reader       io.Reader
+  Writer       io.Writer
+  IsReadWriter bool
+}
+
+func (p *TIOStreamTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TIOStreamTransport)
+    if ok {
+      if t.IsReadWriter {
+        return NewTIOStreamTransportRW(t.Reader.(io.ReadWriter))
+      }
+      if t.Reader != nil && t.Writer != nil {
+        return NewTIOStreamTransportRAndW(t.Reader, t.Writer)
+      }
+      if t.Reader != nil && t.Writer == nil {
+        return NewTIOStreamTransportR(t.Reader)
+      }
+      if t.Reader == nil && t.Writer != nil {
+        return NewTIOStreamTransportW(t.Writer)
+      }
+      return NewTIOStreamTransportDefault()
+    }
+  }
+  if p.IsReadWriter {
+    return NewTIOStreamTransportRW(p.Reader.(io.ReadWriter))
+  }
+  if p.Reader != nil && p.Writer != nil {
+    return NewTIOStreamTransportRAndW(p.Reader, p.Writer)
+  }
+  if p.Reader != nil && p.Writer == nil {
+    return NewTIOStreamTransportR(p.Reader)
+  }
+  if p.Reader == nil && p.Writer != nil {
+    return NewTIOStreamTransportW(p.Writer)
+  }
+  return NewTIOStreamTransportDefault()
+}
+
+func NewTIOStreamTransportFactory(reader io.Reader, writer io.Writer, isReadWriter bool) *TIOStreamTransportFactory {
+  return &TIOStreamTransportFactory{Reader: reader, Writer: writer, IsReadWriter: isReadWriter}
+}
+
+
+/**
+ * Subclasses can invoke the default constructor and then assign the input
+ * streams in the open method.
+ */
+func NewTIOStreamTransportDefault() *TIOStreamTransport {
+  return &TIOStreamTransport{}
+}
+
+/**
+ * Input stream constructor.
+ *
+ * @param is Input stream to read from
+ */
+func NewTIOStreamTransportR(r io.Reader) *TIOStreamTransport {
+  return &TIOStreamTransport{Reader: bufio.NewReader(r)}
+}
+
+/**
+ * Output stream constructor.
+ *
+ * @param os Output stream to read from
+ */
+func NewTIOStreamTransportW(w io.Writer) *TIOStreamTransport {
+  return &TIOStreamTransport{Writer: bufio.NewWriter(w)}
+}
+
+/**
+ * Two-way stream constructor.
+ *
+ * @param is Input stream to read from
+ * @param os Output stream to read from
+ */
+func NewTIOStreamTransportRAndW(r io.Reader, w io.Writer) *TIOStreamTransport {
+  return &TIOStreamTransport{Reader: bufio.NewReader(r), Writer: bufio.NewWriter(w)}
+}
+
+/**
+ * Two-way stream constructor.
+ *
+ * @param is Input stream to read from
+ * @param os Output stream to read from
+ */
+func NewTIOStreamTransportRW(rw io.ReadWriter) *TIOStreamTransport {
+  // bufio has a bug where once a Reader hits EOF, a new Write never brings the reader out of EOF
+  // even if reader and writer use the same underlier
+  //bufrw := bufio.NewReadWriter(bufio.NewReader(rw), bufio.NewWriter(rw));
+  return &TIOStreamTransport{Reader: rw, Writer: rw, IsReadWriter: true}
+}
+
+/**
+ * The streams must already be open at construction time, so this should
+ * always return true.
+ *
+ * @return true
+ */
+func (p *TIOStreamTransport) IsOpen() bool {
+  return true
+}
+
+/**
+ * The streams must already be open. This method does nothing.
+ */
+func (p *TIOStreamTransport) Open() os.Error {
+  return nil
+}
+
+func (p *TIOStreamTransport) Peek() bool {
+  return p.IsOpen()
+}
+
+/**
+ * Closes both the input and output streams.
+ */
+func (p *TIOStreamTransport) Close() os.Error {
+  closedReader := false
+  if p.Reader != nil {
+    c, ok := p.Reader.(io.Closer)
+    if ok {
+      e := c.Close()
+      closedReader = true
+      if e != nil {
+        LOGGER.Print("Error closing input stream.", e)
+      }
+    }
+    p.Reader = nil
+  }
+  if p.Writer != nil && (!closedReader || !p.IsReadWriter) {
+    c, ok := p.Writer.(io.Closer)
+    if ok {
+      e := c.Close()
+      if e != nil {
+        LOGGER.Print("Error closing output stream.", e)
+      }
+    }
+    p.Writer = nil
+  }
+  return nil
+}
+
+/**
+ * Reads from the underlying input stream if not null.
+ */
+func (p *TIOStreamTransport) Read(buf []byte) (int, os.Error) {
+  if p.Reader == nil {
+    return 0, NewTTransportException(NOT_OPEN, "Cannot read from null inputStream")
+  }
+  n, err := p.Reader.Read(buf)
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+func (p *TIOStreamTransport) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+
+/**
+ * Writes to the underlying output stream if not null.
+ */
+func (p *TIOStreamTransport) Write(buf []byte) (int, os.Error) {
+  if p.Writer == nil {
+    LOGGER.Print("Could not write to iostream as Writer is null\n")
+    return 0, NewTTransportException(NOT_OPEN, "Cannot write to null outputStream")
+  }
+  n, err := p.Writer.Write(buf)
+  if n == 0 || err != nil {
+    LOGGER.Print("Error writing to iostream, only wrote ", n, " bytes: ", err.String(), "\n")
+  }
+  return n, NewTTransportExceptionFromOsError(err)
+}
+
+/**
+ * Flushes the underlying output stream if not null.
+ */
+func (p *TIOStreamTransport) Flush() os.Error {
+  if p.Writer == nil {
+    return NewTTransportException(NOT_OPEN, "Cannot flush null outputStream")
+  }
+  f, ok := p.Writer.(Flusher)
+  if ok {
+    err := f.Flush()
+    if err != nil {
+      return NewTTransportExceptionFromOsError(err)
+    }
+  }
+  return nil
+}

Added: thrift/trunk/lib/go/thrift/tiostream_transport_test.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tiostream_transport_test.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tiostream_transport_test.go (added)
+++ thrift/trunk/lib/go/thrift/tiostream_transport_test.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+  "bytes"
+)
+
+func TestIOStreamTransport(t *testing.T) {
+  trans := NewTIOStreamTransportRW(bytes.NewBuffer(make([]byte, 0, 1024)))
+  TransportTest(t, trans, trans)
+}

Added: thrift/trunk/lib/go/thrift/tjson_protocol.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tjson_protocol.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tjson_protocol.go (added)
+++ thrift/trunk/lib/go/thrift/tjson_protocol.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,537 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "encoding/base64"
+  "fmt"
+)
+
+const (
+  THRIFT_JSON_PROTOCOL_VERSION = 1
+)
+
+// for references to _ParseContext see tsimplejson_protocol.go
+
+/**
+ * JSON protocol implementation for thrift.
+ *
+ * This protocol produces/consumes a simple output format
+ * suitable for parsing by scripting languages.  It should not be
+ * confused with the full-featured TJSONProtocol.
+ *
+ */
+type TJSONProtocol struct {
+  *TSimpleJSONProtocol
+}
+
+/**
+ * Constructor
+ */
+func NewTJSONProtocol(t TTransport) *TJSONProtocol {
+  v := &TJSONProtocol{TSimpleJSONProtocol: NewTSimpleJSONProtocol(t)}
+  v.parseContextStack.Push(int(_CONTEXT_IN_TOPLEVEL))
+  v.dumpContext.Push(int(_CONTEXT_IN_TOPLEVEL))
+  return v
+}
+
+/**
+ * Factory
+ */
+type TJSONProtocolFactory struct{}
+
+func (p *TJSONProtocolFactory) GetProtocol(trans TTransport) TProtocol {
+  return NewTJSONProtocol(trans)
+}
+
+func NewTJSONProtocolFactory() *TJSONProtocolFactory {
+  return &TJSONProtocolFactory{}
+}
+
+
+func (p *TJSONProtocol) WriteMessageBegin(name string, typeId TMessageType, seqId int32) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteI32(THRIFT_JSON_PROTOCOL_VERSION); e != nil {
+    return e
+  }
+  if e := p.WriteString(name); e != nil {
+    return e
+  }
+  if e := p.WriteByte(byte(typeId)); e != nil {
+    return e
+  }
+  if e := p.WriteI32(seqId); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) WriteMessageEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteStructBegin(name string) TProtocolException {
+  if e := p.OutputObjectBegin(); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) WriteStructEnd() TProtocolException {
+  return p.OutputObjectEnd()
+}
+
+func (p *TJSONProtocol) WriteFieldBegin(name string, typeId TType, id int16) TProtocolException {
+  if e := p.WriteI16(id); e != nil {
+    return e
+  }
+  if e := p.OutputObjectBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteString(p.TypeIdToString(typeId)); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) WriteFieldEnd() TProtocolException {
+  return p.OutputObjectEnd()
+}
+
+func (p *TJSONProtocol) WriteFieldStop() TProtocolException { return nil }
+
+func (p *TJSONProtocol) WriteMapBegin(keyType TType, valueType TType, size int) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.WriteString(p.TypeIdToString(keyType)); e != nil {
+    return e
+  }
+  if e := p.WriteString(p.TypeIdToString(valueType)); e != nil {
+    return e
+  }
+  return p.WriteI64(int64(size))
+}
+
+func (p *TJSONProtocol) WriteMapEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteListBegin(elemType TType, size int) TProtocolException {
+  return p.OutputElemListBegin(elemType, size)
+}
+
+func (p *TJSONProtocol) WriteListEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteSetBegin(elemType TType, size int) TProtocolException {
+  return p.OutputElemListBegin(elemType, size)
+}
+
+func (p *TJSONProtocol) WriteSetEnd() TProtocolException {
+  return p.OutputListEnd()
+}
+
+func (p *TJSONProtocol) WriteBool(b bool) TProtocolException {
+  return p.OutputBool(b)
+}
+
+func (p *TJSONProtocol) WriteByte(b byte) TProtocolException {
+  return p.WriteI32(int32(b))
+}
+
+func (p *TJSONProtocol) WriteI16(v int16) TProtocolException {
+  return p.WriteI32(int32(v))
+}
+
+func (p *TJSONProtocol) WriteI32(v int32) TProtocolException {
+  return p.OutputI64(int64(v))
+}
+
+func (p *TJSONProtocol) WriteI64(v int64) TProtocolException {
+  return p.OutputI64(int64(v))
+}
+
+func (p *TJSONProtocol) WriteDouble(v float64) TProtocolException {
+  return p.OutputF64(v)
+}
+
+func (p *TJSONProtocol) WriteString(v string) TProtocolException {
+  return p.OutputString(v)
+}
+
+func (p *TJSONProtocol) WriteBinary(v []byte) TProtocolException {
+  // JSON library only takes in a string, 
+  // not an arbitrary byte array, to ensure bytes are transmitted
+  // efficiently we must convert this into a valid JSON string
+  // therefore we use base64 encoding to avoid excessive escaping/quoting
+  if e := p.OutputPreValue(); e != nil {
+    return e
+  }
+  p.writer.Write(JSON_QUOTE_BYTES)
+  writer := base64.NewEncoder(base64.StdEncoding, p.writer)
+  if _, e := writer.Write(v); e != nil {
+    return NewTProtocolExceptionFromOsError(e)
+  }
+  writer.Close()
+  p.writer.Write(JSON_QUOTE_BYTES)
+  return p.OutputPostValue()
+}
+
+/**
+ * Reading methods.
+ */
+
+func (p *TJSONProtocol) ReadMessageBegin() (name string, typeId TMessageType, seqId int32, err TProtocolException) {
+  if isNull, err := p.ParseListBegin(); isNull || err != nil {
+    return name, typeId, seqId, err
+  }
+  version, err := p.ReadI32()
+  if err != nil {
+    return name, typeId, seqId, err
+  }
+  if version != THRIFT_JSON_PROTOCOL_VERSION {
+    return name, typeId, seqId, NewTProtocolException(INVALID_DATA, fmt.Sprint("Unknown Protocol version ", version, ", expected version ", THRIFT_JSON_PROTOCOL_VERSION, "\n"))
+  }
+  if name, err = p.ReadString(); err != nil {
+    return name, typeId, seqId, err
+  }
+  bTypeId, err := p.ReadByte()
+  typeId = TMessageType(bTypeId)
+  if err != nil {
+    return name, typeId, seqId, err
+  }
+  if seqId, err = p.ReadI32(); err != nil {
+    return name, typeId, seqId, err
+  }
+  return name, typeId, seqId, nil
+}
+
+func (p *TJSONProtocol) ReadMessageEnd() TProtocolException {
+  err := p.ParseListEnd()
+  return err
+}
+
+func (p *TJSONProtocol) ReadStructBegin() (name string, err TProtocolException) {
+  _, err = p.ParseObjectStart()
+  return "", err
+}
+
+func (p *TJSONProtocol) ReadStructEnd() TProtocolException {
+  return p.ParseObjectEnd()
+}
+
+func (p *TJSONProtocol) ReadFieldBegin() (string, TType, int16, TProtocolException) {
+  if p.reader.Buffered() < 1 {
+    return "", STOP, -1, nil
+  }
+  b, _ := p.reader.Peek(1)
+  if len(b) < 1 || b[0] == JSON_RBRACE[0] || b[0] == JSON_RBRACKET[0] {
+    return "", STOP, -1, nil
+  }
+  fieldId, err := p.ReadI16()
+  if err != nil {
+    return "", STOP, fieldId, err
+  }
+  if _, err = p.ParseObjectStart(); err != nil {
+    return "", STOP, fieldId, err
+  }
+  sType, err := p.ReadString()
+  fType := p.StringToTypeId(sType)
+  return "", fType, fieldId, err
+}
+
+func (p *TJSONProtocol) ReadFieldEnd() TProtocolException {
+  return p.ParseObjectEnd()
+}
+
+func (p *TJSONProtocol) ReadMapBegin() (keyType TType, valueType TType, size int, e TProtocolException) {
+  if isNull, e := p.ParseListBegin(); isNull || e != nil {
+    return VOID, VOID, 0, e
+  }
+
+  // read keyType
+  sKeyType, e := p.ReadString()
+  keyType = p.StringToTypeId(sKeyType)
+  if e != nil {
+    return keyType, valueType, size, e
+  }
+
+  // read valueType
+  sValueType, e := p.ReadString()
+  valueType = p.StringToTypeId(sValueType)
+  if e != nil {
+    return keyType, valueType, size, e
+  }
+
+  // read size
+  iSize, err := p.ReadI64()
+  size = int(iSize)
+  return keyType, valueType, size, err
+}
+
+func (p *TJSONProtocol) ReadMapEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TJSONProtocol) ReadListBegin() (elemType TType, size int, e TProtocolException) {
+  return p.ParseElemListBegin()
+}
+
+func (p *TJSONProtocol) ReadListEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TJSONProtocol) ReadSetBegin() (elemType TType, size int, e TProtocolException) {
+  return p.ParseElemListBegin()
+}
+
+func (p *TJSONProtocol) ReadSetEnd() TProtocolException {
+  return p.ParseListEnd()
+}
+
+func (p *TJSONProtocol) ReadBool() (bool, TProtocolException) {
+  var value bool
+  if err := p.ParsePreValue(); err != nil {
+    return value, err
+  }
+  b, _ := p.reader.Peek(len(JSON_FALSE))
+  if len(b) > 0 {
+    switch b[0] {
+    case JSON_TRUE[0]:
+      if string(b[0:len(JSON_TRUE)]) == string(JSON_TRUE) {
+        p.reader.Read(b[0:len(JSON_TRUE)])
+        value = true
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"true\" but found: "+string(b))
+      }
+      break
+    case JSON_FALSE[0]:
+      if string(b[0:len(JSON_FALSE)]) == string(JSON_FALSE) {
+        p.reader.Read(b[0:len(JSON_FALSE)])
+        value = false
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"false\" but found: "+string(b))
+      }
+      break
+    case JSON_NULL[0]:
+      if string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+        p.reader.Read(b[0:len(JSON_NULL)])
+        value = false
+      } else {
+        return value, NewTProtocolException(INVALID_DATA, "Expected \"null\" but found: "+string(b))
+      }
+    default:
+      return value, NewTProtocolException(INVALID_DATA, "Expected \"true\", \"false\", or \"null\" but found: "+string(b))
+    }
+  }
+  return value, p.ParsePostValue()
+}
+
+func (p *TJSONProtocol) ReadByte() (byte, TProtocolException) {
+  v, err := p.ReadI64()
+  return byte(v), err
+}
+
+func (p *TJSONProtocol) ReadI16() (int16, TProtocolException) {
+  v, err := p.ReadI64()
+  return int16(v), err
+}
+
+func (p *TJSONProtocol) ReadI32() (int32, TProtocolException) {
+  v, err := p.ReadI64()
+  return int32(v), err
+}
+
+func (p *TJSONProtocol) ReadI64() (int64, TProtocolException) {
+  v, _, err := p.ParseI64()
+  return v, err
+}
+
+func (p *TJSONProtocol) ReadDouble() (float64, TProtocolException) {
+  v, _, err := p.ParseF64()
+  return v, err
+}
+
+func (p *TJSONProtocol) ReadString() (string, TProtocolException) {
+  var v string
+  if err := p.ParsePreValue(); err != nil {
+    return v, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+    value, err := p.ParseStringBody()
+    v = value
+    if err != nil {
+      return v, err
+    }
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    _, err := p.reader.Read(b[0:len(JSON_NULL)])
+    if err != nil {
+      return v, NewTProtocolExceptionFromOsError(err)
+    }
+  } else {
+    return v, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected a JSON string, found ", string(b)))
+  }
+  return v, p.ParsePostValue()
+}
+
+func (p *TJSONProtocol) ReadBinary() ([]byte, TProtocolException) {
+  var v []byte
+  if err := p.ParsePreValue(); err != nil {
+    return nil, err
+  }
+  b, _ := p.reader.Peek(len(JSON_NULL))
+  if len(b) > 0 && b[0] == JSON_QUOTE {
+    p.reader.ReadByte()
+    value, err := p.ParseBase64EncodedBody()
+    v = value
+    if err != nil {
+      return v, err
+    }
+  } else if len(b) >= len(JSON_NULL) && string(b[0:len(JSON_NULL)]) == string(JSON_NULL) {
+    _, err := p.reader.Read(b[0:len(JSON_NULL)])
+    if err != nil {
+      return v, NewTProtocolExceptionFromOsError(err)
+    }
+  } else {
+    return v, NewTProtocolException(INVALID_DATA, fmt.Sprint("Expected a JSON string, found ", string(b)))
+  }
+  return v, p.ParsePostValue()
+}
+
+func (p *TJSONProtocol) Flush() (err TProtocolException) {
+  return NewTProtocolExceptionFromOsError(p.writer.Flush())
+}
+
+func (p *TJSONProtocol) Skip(fieldType TType) (err TProtocolException) {
+  return SkipDefaultDepth(p, fieldType)
+}
+
+func (p *TJSONProtocol) Transport() TTransport {
+  return p.trans
+}
+
+func (p *TJSONProtocol) readElemListBegin() (elemType TType, size int, e TProtocolException) {
+  if isNull, e := p.ParseListBegin(); isNull || e != nil {
+    return VOID, 0, e
+  }
+  sElemType, err := p.ReadString()
+  elemType = p.StringToTypeId(sElemType)
+  if err != nil {
+    return elemType, size, err
+  }
+  nSize, err2 := p.ReadI64()
+  size = int(nSize)
+  return elemType, size, err2
+}
+
+func (p *TJSONProtocol) writeElemListBegin(elemType TType, size int) TProtocolException {
+  if e := p.OutputListBegin(); e != nil {
+    return e
+  }
+  if e := p.OutputString(p.TypeIdToString(elemType)); e != nil {
+    return e
+  }
+  if e := p.OutputI64(int64(size)); e != nil {
+    return e
+  }
+  return nil
+}
+
+func (p *TJSONProtocol) TypeIdToString(fieldType TType) string {
+  switch byte(fieldType) {
+  case STOP:
+    return "stp"
+  case VOID:
+    return "v"
+  case BOOL:
+    return "tf"
+  case BYTE:
+    return "i8"
+  case DOUBLE:
+    return "dbl"
+  case I16:
+    return "i16"
+  case I32:
+    return "i32"
+  case I64:
+    return "i64"
+  case STRING:
+    return "str"
+  case STRUCT:
+    return "rec"
+  case MAP:
+    return "map"
+  case SET:
+    return "set"
+  case LIST:
+    return "lst"
+  case ENUM:
+    return "i32"
+  case UTF16:
+    return "str"
+  case GENERIC:
+    return "gen"
+  }
+  return ""
+}
+
+func (p *TJSONProtocol) StringToTypeId(fieldType string) TType {
+  switch fieldType {
+  case "stp":
+    return TType(STOP)
+  case "v":
+    return TType(VOID)
+  case "tf":
+    return TType(BOOL)
+  case "i8":
+    return TType(BYTE)
+  case "dbl":
+    return TType(DOUBLE)
+  case "16":
+    return TType(I16)
+  case "i32":
+    return TType(I32)
+  case "i64":
+    return TType(I64)
+  case "str":
+    return TType(STRING)
+  case "rec":
+    return TType(STRUCT)
+  case "map":
+    return TType(MAP)
+  case "set":
+    return TType(SET)
+  case "lst":
+    return TType(LIST)
+  case "enm":
+    return TType(ENUM)
+  case "u16":
+    return TType(UTF16)
+  case "gen":
+    return TType(GENERIC)
+  }
+  return TType(STOP)
+}

Added: thrift/trunk/lib/go/thrift/tjson_protocol_test.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tjson_protocol_test.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tjson_protocol_test.go (added)
+++ thrift/trunk/lib/go/thrift/tjson_protocol_test.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,674 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "encoding/base64"
+  "fmt"
+  "json"
+  "math"
+  "strconv"
+  "testing"
+)
+
+func TestWriteJSONProtocolBool(t *testing.T) {
+  thetype := "boolean"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range BOOL_VALUES {
+    if e := p.WriteBool(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := false
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolBool(t *testing.T) {
+  thetype := "boolean"
+  for _, value := range BOOL_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    if value {
+      trans.Write(JSON_TRUE)
+    } else {
+      trans.Write(JSON_FALSE)
+    }
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadBool()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolByte(t *testing.T) {
+  thetype := "byte"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range BYTE_VALUES {
+    if e := p.WriteByte(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := byte(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolByte(t *testing.T) {
+  thetype := "byte"
+  for _, value := range BYTE_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadByte()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolI16(t *testing.T) {
+  thetype := "int16"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range INT16_VALUES {
+    if e := p.WriteI16(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int16(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolI16(t *testing.T) {
+  thetype := "int16"
+  for _, value := range INT16_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI16()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolI32(t *testing.T) {
+  thetype := "int32"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range INT32_VALUES {
+    if e := p.WriteI32(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int32(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolI32(t *testing.T) {
+  thetype := "int32"
+  for _, value := range INT32_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa(int(value)))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI32()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolI64(t *testing.T) {
+  thetype := "int64"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range INT64_VALUES {
+    if e := p.WriteI64(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s != fmt.Sprint(value) {
+      t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+    }
+    v := int64(0)
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolI64(t *testing.T) {
+  thetype := "int64"
+  for _, value := range INT64_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(strconv.Itoa64(value))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadI64()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolDouble(t *testing.T) {
+  thetype := "double"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if math.IsInf(value, 1) {
+      if s != JsonQuote(JSON_INFINITY) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_INFINITY))
+      }
+    } else if math.IsInf(value, -1) {
+      if s != JsonQuote(JSON_NEGATIVE_INFINITY) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_NEGATIVE_INFINITY))
+      }
+    } else if math.IsNaN(value) {
+      if s != JsonQuote(JSON_NAN) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, expected: %v", thetype, value, s, JsonQuote(JSON_NAN))
+      }
+    } else {
+      if s != fmt.Sprint(value) {
+        t.Fatalf("Bad value for %s %v: %s", thetype, value, s)
+      }
+      v := float64(0)
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolDouble(t *testing.T) {
+  thetype := "double"
+  for _, value := range DOUBLE_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    n := NewNumericFromDouble(value)
+    trans.WriteString(n.String())
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadDouble()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if math.IsInf(value, 1) {
+      if !math.IsInf(v, 1) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else if math.IsInf(value, -1) {
+      if !math.IsInf(v, -1) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else if math.IsNaN(value) {
+      if !math.IsNaN(v) {
+        t.Fatalf("Bad value for %s %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+    } else {
+      if v != value {
+        t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+      }
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolString(t *testing.T) {
+  thetype := "string"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  for _, value := range STRING_VALUES {
+    if e := p.WriteString(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if e := p.Flush(); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+    }
+    s := trans.String()
+    if s[0] != '"' || s[len(s)-1] != '"' {
+      t.Fatalf("Bad value for %s '%v', wrote '%v', expected: %v", thetype, value, s, fmt.Sprint("\"", value, "\""))
+    }
+    v := new(string)
+    if err := json.Unmarshal([]byte(s), v); err != nil || *v != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v)
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolString(t *testing.T) {
+  thetype := "string"
+  for _, value := range STRING_VALUES {
+    trans := NewTMemoryBuffer()
+    p := NewTJSONProtocol(trans)
+    trans.WriteString(JsonQuote(value))
+    trans.Flush()
+    s := trans.String()
+    v, e := p.ReadString()
+    if e != nil {
+      t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+    }
+    if v != value {
+      t.Fatalf("Bad value for %s value %v, wrote: %v, received: %v", thetype, value, s, v)
+    }
+    v1 := new(string)
+    if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != value {
+      t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+    }
+    trans.Reset()
+    trans.Close()
+  }
+}
+
+func TestWriteJSONProtocolBinary(t *testing.T) {
+  thetype := "binary"
+  value := protocol_bdata
+  b64value := make([]byte, base64.StdEncoding.EncodedLen(len(protocol_bdata)))
+  base64.StdEncoding.Encode(b64value, value)
+  b64String := string(b64value)
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  if e := p.WriteBinary(value); e != nil {
+    t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+  }
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s value %v due to error flushing: %s", thetype, value, e.String())
+  }
+  s := trans.String()
+  expectedString := fmt.Sprint("\"", b64String, "\"")
+  if s != expectedString {
+    t.Fatalf("Bad value for %s %v\n  wrote:  \"%v\"\nexpected: \"%v\"", thetype, value, s, expectedString)
+  }
+  v1, err := p.ReadBinary()
+  if err != nil {
+    t.Fatalf("Unable to read binary: %s", err.String())
+  }
+  if len(v1) != len(value) {
+    t.Fatalf("Invalid value for binary\nexpected: \"%v\"\n   read: \"%v\"", value, v1)
+  }
+  for k, v := range value {
+    if v1[k] != v {
+      t.Fatalf("Invalid value for binary at %v\nexpected: \"%v\"\n   read: \"%v\"", k, v, v1[k])
+    }
+  }
+  trans.Close()
+}
+
+func TestReadJSONProtocolBinary(t *testing.T) {
+  thetype := "binary"
+  value := protocol_bdata
+  b64value := make([]byte, base64.StdEncoding.EncodedLen(len(protocol_bdata)))
+  base64.StdEncoding.Encode(b64value, value)
+  b64String := string(b64value)
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  trans.WriteString(JsonQuote(b64String))
+  trans.Flush()
+  s := trans.String()
+  v, e := p.ReadBinary()
+  if e != nil {
+    t.Fatalf("Unable to read %s value %v due to error: %s", thetype, value, e.String())
+  }
+  if len(v) != len(value) {
+    t.Fatalf("Bad value for %s value length %v, wrote: %v, received length: %v", thetype, len(value), s, len(v))
+  }
+  for i := 0; i < len(v); i++ {
+    if v[i] != value[i] {
+      t.Fatalf("Bad value for %s at index %d value %v, wrote: %v, received: %v", thetype, i, value[i], s, v[i])
+    }
+  }
+  v1 := new(string)
+  if err := json.Unmarshal([]byte(s), v1); err != nil || *v1 != b64String {
+    t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, *v1)
+  }
+  trans.Reset()
+  trans.Close()
+}
+
+func TestWriteJSONProtocolList(t *testing.T) {
+  thetype := "list"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  p.WriteListBegin(TType(DOUBLE), len(DOUBLE_VALUES))
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteListEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  str1 := new([]interface{})
+  err := json.Unmarshal([]byte(str), str1)
+  if err != nil {
+    t.Fatalf("Unable to decode %s, wrote: %s", thetype, str)
+  }
+  l := *str1
+  if len(l) < 2 {
+    t.Fatalf("List must be at least of length two to include metadata")
+  }
+  if int(l[0].(float64)) != DOUBLE {
+    t.Fatal("Invalid type for list, expected: ", DOUBLE, ", but was: ", l[0])
+  }
+  if int(l[1].(float64)) != len(DOUBLE_VALUES) {
+    t.Fatal("Invalid length for list, expected: ", len(DOUBLE_VALUES), ", but was: ", l[1])
+  }
+  for k, value := range DOUBLE_VALUES {
+    s := l[k+2]
+    if math.IsInf(value, 1) {
+      if s.(string) != JSON_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_INFINITY), str)
+      }
+    } else if math.IsInf(value, 0) {
+      if s.(string) != JSON_NEGATIVE_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY), str)
+      }
+    } else if math.IsNaN(value) {
+      if s.(string) != JSON_NAN {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NAN), str)
+      }
+    } else {
+      if s.(float64) != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s'", thetype, value, s)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestWriteJSONProtocolSet(t *testing.T) {
+  thetype := "set"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  p.WriteSetBegin(TType(DOUBLE), len(DOUBLE_VALUES))
+  for _, value := range DOUBLE_VALUES {
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteSetEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  str1 := new([]interface{})
+  err := json.Unmarshal([]byte(str), str1)
+  if err != nil {
+    t.Fatalf("Unable to decode %s, wrote: %s", thetype, str)
+  }
+  l := *str1
+  if len(l) < 2 {
+    t.Fatalf("Set must be at least of length two to include metadata")
+  }
+  if int(l[0].(float64)) != DOUBLE {
+    t.Fatal("Invalid type for set, expected: ", DOUBLE, ", but was: ", l[0])
+  }
+  if int(l[1].(float64)) != len(DOUBLE_VALUES) {
+    t.Fatal("Invalid length for set, expected: ", len(DOUBLE_VALUES), ", but was: ", l[1])
+  }
+  for k, value := range DOUBLE_VALUES {
+    s := l[k+2]
+    if math.IsInf(value, 1) {
+      if s.(string) != JSON_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_INFINITY), str)
+      }
+    } else if math.IsInf(value, 0) {
+      if s.(string) != JSON_NEGATIVE_INFINITY {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY), str)
+      }
+    } else if math.IsNaN(value) {
+      if s.(string) != JSON_NAN {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %q, expected: %q, originally wrote: %q", thetype, k, value, s, JsonQuote(JSON_NAN), str)
+      }
+    } else {
+      if s.(float64) != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s'", thetype, value, s)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+func TestWriteJSONProtocolMap(t *testing.T) {
+  thetype := "map"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  p.WriteMapBegin(TType(I32), TType(DOUBLE), len(DOUBLE_VALUES))
+  for k, value := range DOUBLE_VALUES {
+    if e := p.WriteI32(int32(k)); e != nil {
+      t.Fatalf("Unable to write %s key int32 value %v due to error: %s", thetype, k, e.String())
+    }
+    if e := p.WriteDouble(value); e != nil {
+      t.Fatalf("Unable to write %s value float64 value %v due to error: %s", thetype, value, e.String())
+    }
+  }
+  p.WriteMapEnd()
+  if e := p.Flush(); e != nil {
+    t.Fatalf("Unable to write %s due to error flushing: %s", thetype, e.String())
+  }
+  str := trans.String()
+  if str[0] != '[' || str[len(str)-1] != ']' {
+    t.Fatalf("Bad value for %s, wrote: %q, in go: %q", thetype, str, DOUBLE_VALUES)
+  }
+  expectedKeyType, expectedValueType, expectedSize, err := p.ReadMapBegin()
+  if err != nil {
+    t.Fatalf("Error while reading map begin: %s", err.String())
+  }
+  if expectedKeyType != I32 {
+    t.Fatal("Expected map key type ", I32, ", but was ", expectedKeyType)
+  }
+  if expectedValueType != DOUBLE {
+    t.Fatal("Expected map value type ", DOUBLE, ", but was ", expectedValueType)
+  }
+  if expectedSize != len(DOUBLE_VALUES) {
+    t.Fatal("Expected map size of ", len(DOUBLE_VALUES), ", but was ", expectedSize)
+  }
+  for k, value := range DOUBLE_VALUES {
+    ik, err := p.ReadI32()
+    if err != nil {
+      t.Fatalf("Bad key for %s index %v, wrote: %v, expected: %v, error: %s", thetype, k, ik, string(k), err.String())
+    }
+    if int(ik) != k {
+      t.Fatalf("Bad key for %s index %v, wrote: %v, expected: %v", thetype, k, ik, k)
+    }
+    dv, err := p.ReadDouble()
+    if err != nil {
+      t.Fatalf("Bad value for %s index %v, wrote: %v, expected: %v, error: %s", thetype, k, dv, value, err.String())
+    }
+    s := strconv.Ftoa64(dv, 'g', 10)
+    if math.IsInf(value, 1) {
+      if !math.IsInf(dv, 1) {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_INFINITY))
+      }
+    } else if math.IsInf(value, 0) {
+      if !math.IsInf(dv, 0) {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_NEGATIVE_INFINITY))
+      }
+    } else if math.IsNaN(value) {
+      if !math.IsNaN(dv) {
+        t.Fatalf("Bad value for %s at index %v  %v, wrote: %v, expected: %v", thetype, k, value, s, JsonQuote(JSON_NAN))
+      }
+    } else {
+      expected := strconv.Ftoa64(value, 'g', 10)
+      if s != expected {
+        t.Fatalf("Bad value for %s at index %v %v, wrote: %v, expected %v", thetype, k, value, s, expected)
+      }
+      v := float64(0)
+      if err := json.Unmarshal([]byte(s), &v); err != nil || v != value {
+        t.Fatalf("Bad json-decoded value for %s %v, wrote: '%s', expected: '%v'", thetype, value, s, v)
+      }
+    }
+    trans.Reset()
+  }
+  trans.Close()
+}
+
+
+func TestReadWriteJSONStruct(t *testing.T) {
+  thetype := "struct"
+  trans := NewTMemoryBuffer()
+  p := NewTJSONProtocol(trans)
+  orig := NewWork()
+  orig.Num1 = 25
+  orig.Num2 = 102
+  orig.Op = ADD
+  orig.Comment = "Add: 25 + 102"
+  if e := orig.Write(p); e != nil {
+    t.Fatalf("Unable to write %s value %#v due to error: %s", thetype, orig, e.String())
+  }
+  p.Flush()
+  t.Log("Memory buffer contents: ", trans.String())
+  expectedString := "{\"1\":{\"i32\":25},\"2\":{\"i32\":102},\"3\":{\"i32\":1},\"4\":{\"str\":\"Add: 25 + 102\"}}"
+  if expectedString != trans.String() {
+    t.Fatalf("Expected JSON Struct with value %#v but have %#v", expectedString, trans.String())
+  }
+  read := NewWork()
+  e := read.Read(p)
+  t.Logf("Read %s value: %#v", thetype, read)
+  if e != nil {
+    t.Fatalf("Unable to read %s due to error: %s", thetype, e.String())
+  }
+  if !orig.Equals(read) {
+    t.Fatalf("Original Write != Read: %#v != %#v ", orig, read)
+  }
+}
+
+func TestReadWriteJSONProtocol(t *testing.T) {
+  ReadWriteProtocolTest(t, NewTJSONProtocolFactory())
+}

Added: thrift/trunk/lib/go/thrift/tlist.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tlist.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tlist.go (added)
+++ thrift/trunk/lib/go/thrift/tlist.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "container/vector"
+)
+
+/**
+ * Helper class that encapsulates list metadata.
+ *
+ */
+type TList interface {
+  TContainer
+  ElemType() TType
+  At(i int) interface{}
+  Set(i int, data interface{})
+  Push(data interface{})
+  Pop() interface{}
+  Swap(i, j int)
+  Insert(i int, data interface{})
+  Delete(i int)
+  Less(i, j int) bool
+  Iter() <-chan interface{}
+}
+
+type tList struct {
+  elemType TType
+  l        *vector.Vector
+}
+
+func NewTList(t TType, s int) TList {
+  var v vector.Vector
+  return &tList{elemType: t, l: v.Resize(s, s)}
+}
+
+func NewTListDefault() TList {
+  var v vector.Vector
+  return &tList{elemType: TType(STOP), l: &v}
+}
+
+func (p *tList) ElemType() TType {
+  return p.elemType
+}
+
+func (p *tList) Len() int {
+  return p.l.Len()
+}
+
+func (p *tList) At(i int) interface{} {
+  return p.l.At(i)
+}
+
+func (p *tList) Set(i int, data interface{}) {
+  if p.elemType.IsEmptyType() {
+    p.elemType = TypeFromValue(data)
+  }
+  if data, ok := p.elemType.CoerceData(data); ok {
+    p.l.Set(i, data)
+  }
+}
+
+func (p *tList) Push(data interface{}) {
+  if p.elemType.IsEmptyType() {
+    p.elemType = TypeFromValue(data)
+  }
+  data, ok := p.elemType.CoerceData(data)
+  if ok {
+    p.l.Push(data)
+  }
+}
+
+func (p *tList) Pop() interface{} {
+  return p.l.Pop()
+}
+
+func (p *tList) Swap(i, j int) {
+  p.l.Swap(i, j)
+}
+
+func (p *tList) Insert(i int, data interface{}) {
+  p.l.Insert(i, data)
+}
+
+func (p *tList) Delete(i int) {
+  p.l.Delete(i)
+}
+
+func (p *tList) Contains(data interface{}) bool {
+  return p.indexOf(data) >= 0
+}
+
+func (p *tList) Less(i, j int) bool {
+  return p.l.Less(i, j)
+}
+
+func (p *tList) Iter() <-chan interface{} {
+  c := make(chan interface{})
+  go p.iterate(c)
+  return c
+}
+
+func (p *tList) iterate(c chan<- interface{}) {
+  for _, elem := range *p.l {
+    c <- elem
+  }
+  close(c)
+}
+
+func (p *tList) indexOf(data interface{}) int {
+  if data == nil {
+    size := p.l.Len()
+    for i := 0; i < size; i++ {
+      if p.l.At(i) == nil {
+        return i
+      }
+    }
+    return -1
+  }
+  data, ok := p.elemType.CoerceData(data)
+  if data == nil || !ok {
+    return -1
+  }
+  size := p.l.Len()
+  if p.elemType.IsBaseType() || p.elemType.IsEnum() {
+    for i := 0; i < size; i++ {
+      if data == p.l.At(i) {
+        return i
+      }
+    }
+    return -1
+  }
+  if cmp, ok := data.(EqualsOtherInterface); ok {
+    for i := 0; i < size; i++ {
+      if cmp.Equals(p.l.At(i)) {
+        return i
+      }
+    }
+    return -1
+  }
+  switch p.elemType {
+  case MAP:
+    if cmp, ok := data.(EqualsMap); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TMap)) {
+          return i
+        }
+      }
+      return -1
+    }
+  case SET:
+    if cmp, ok := data.(EqualsSet); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TSet)) {
+          return i
+        }
+      }
+      return -1
+    }
+  case LIST:
+    if cmp, ok := data.(EqualsList); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TList)) {
+          return i
+        }
+      }
+      return -1
+    }
+  case STRUCT:
+    if cmp, ok := data.(EqualsStruct); ok {
+      for i := 0; i < size; i++ {
+        v := p.l.At(i)
+        if v == nil {
+          continue
+        }
+        if cmp.Equals(v.(TStruct)) {
+          return i
+        }
+      }
+      return -1
+    }
+  }
+  return -1
+}
+
+func (p *tList) Equals(other interface{}) bool {
+  c, cok := p.CompareTo(other)
+  return cok && c == 0
+}
+
+func (p *tList) CompareTo(other interface{}) (int, bool) {
+  return TType(LIST).Compare(p, other)
+}

Added: thrift/trunk/lib/go/thrift/tmap.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tmap.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tmap.go (added)
+++ thrift/trunk/lib/go/thrift/tmap.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,763 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "container/list"
+  "reflect"
+)
+
+/**
+ * Helper class that encapsulates map metadata.
+ *
+ */
+type TMap interface {
+  KeyType() TType
+  ValueType() TType
+  Len() int
+  Set(key, value interface{})
+  Get(key interface{}) (interface{}, bool)
+  Contains(key interface{}) bool
+  Iter() <-chan TMapElem
+  KeyIter() <-chan interface{}
+  ValueIter() <-chan interface{}
+  Keys() []interface{}
+  Values() []interface{}
+  Less(other interface{}) bool
+  Equals(other interface{}) bool
+  CompareTo(other interface{}) (int, bool)
+}
+
+type TMapElem interface {
+  Key() interface{}
+  Value() interface{}
+}
+
+type tMap struct {
+  keyType   TType
+  valueType TType
+  size      int
+  l         *list.List
+  b         map[bool]interface{}
+  i08       map[byte]interface{}
+  i16       map[int16]interface{}
+  i32       map[int32]interface{}
+  i64       map[int64]interface{}
+  f64       map[float64]interface{}
+  s         map[string]interface{}
+}
+
+type tMapElem struct {
+  key   interface{}
+  value interface{}
+}
+
+func (p *tMapElem) Key() interface{} {
+  return p.key
+}
+
+func (p *tMapElem) Value() interface{} {
+  return p.value
+}
+
+func NewTMapElem(k, v interface{}) TMapElem {
+  return &tMapElem{key: k, value: v}
+}
+
+func NewTMap(k, v TType, s int) TMap {
+  return &tMap{keyType: k, valueType: v, size: s, l: list.New()}
+}
+
+func NewTMapDefault() TMap {
+  return NewTMap(STOP, STOP, 0)
+}
+
+func (p *tMap) KeyType() TType {
+  return p.keyType
+}
+
+func (p *tMap) ValueType() TType {
+  return p.valueType
+}
+
+func (p *tMap) Len() int {
+  if p.l.Len() != 0 {
+    return p.l.Len()
+  }
+  switch p.KeyType() {
+  case STOP, VOID:
+    return 0
+  case BOOL:
+    return len(p.b)
+  case BYTE:
+    return len(p.i08)
+  case I16:
+    return len(p.i16)
+  case I32:
+    return len(p.i32)
+  case I64:
+    return len(p.i64)
+  case DOUBLE:
+    return len(p.f64)
+  case STRING, UTF8, UTF16:
+    return len(p.s)
+  default:
+    return p.size
+  }
+  return p.size
+}
+
+func (p *tMap) Get(key interface{}) (interface{}, bool) {
+  if p.KeyType().IsEmptyType() {
+    return nil, false
+  }
+  if key == nil {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  }
+  useKey, ok := p.KeyType().CoerceData(key)
+  if !ok {
+    return nil, false
+  }
+  switch p.KeyType() {
+  case STOP, VOID:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return nil, false
+  case BOOL:
+    m := p.b
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(bool)]; ok {
+      return v, true
+    }
+    return nil, true
+  case BYTE:
+    m := p.i08
+    if v, ok := m[useKey.(byte)]; ok {
+      return v, true
+    }
+    return nil, false
+  case DOUBLE:
+    m := p.f64
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(float64)]; ok {
+      return v, true
+    }
+    return nil, false
+  case I16:
+    m := p.i16
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(int16)]; ok {
+      return v, true
+    }
+    return nil, false
+  case I32:
+    m := p.i32
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(int32)]; ok {
+      return v, true
+    }
+    return nil, false
+  case I64:
+    m := p.i64
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(int64)]; ok {
+      return v, true
+    }
+    return nil, false
+  case STRING, UTF8, UTF16:
+    // TODO(pomack) properly handle ENUM
+    m := p.s
+    if m == nil {
+      return nil, false
+    }
+    if v, ok := m[useKey.(string)]; ok {
+      return v, true
+    }
+    return nil, false
+  case STRUCT:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      structkey, ok := k.(TStruct)
+      if ok {
+        if structkey.Equals(useKey.(TStruct)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  case MAP:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      mapkey, ok := k.(TMap)
+      if ok {
+        if mapkey.Equals(useKey.(TMap)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  case SET:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      setkey, ok := k.(TSet)
+      if ok {
+        if setkey.Equals(useKey.(TSet)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  case LIST:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      listkey, ok := k.(TList)
+      if ok {
+        if listkey.Equals(useKey.(TList)) {
+          return e.Value(), true
+        }
+        continue
+      }
+      if reflect.DeepEqual(useKey, k) {
+        return e.Value(), true
+      }
+    }
+    return nil, false
+  default:
+    panic("Invalid Thrift element type")
+  }
+  return nil, false
+}
+
+
+func (p *tMap) Set(key, value interface{}) {
+  if p.KeyType() == STOP || p.KeyType() == VOID {
+    p.keyType = TypeFromValue(key)
+  }
+  coercedKey, ok := p.KeyType().CoerceData(key)
+  if !ok {
+    return
+  }
+  if p.ValueType() == STOP || p.ValueType() == VOID {
+    p.valueType = TypeFromValue(value)
+  }
+  coercedValue, ok := p.ValueType().CoerceData(value)
+  if !ok {
+    return
+  }
+  newElem := NewTMapElem(coercedKey, coercedValue)
+  if !p.KeyType().IsBaseType() {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      k := elem.Value.(TMapElem).Key()
+      if cmp, ok := p.KeyType().Compare(coercedKey, k); ok && cmp >= 0 {
+        if cmp == 0 {
+          p.l.InsertAfter(newElem, elem)
+          p.l.Remove(elem)
+          return
+        }
+        p.l.InsertBefore(newElem, elem)
+        return
+      }
+    }
+    p.l.PushBack(newElem)
+    return
+  }
+  if key == nil {
+    return
+  }
+  switch p.KeyType() {
+  case STOP, VOID:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return
+  case BOOL:
+    if p.b == nil {
+      p.b = make(map[bool]interface{})
+    }
+    b := coercedKey.(bool)
+    p.b[b] = value
+  case BYTE:
+    if p.i08 == nil {
+      p.i08 = make(map[byte]interface{})
+    }
+    b := coercedKey.(byte)
+    p.i08[b] = value
+  case DOUBLE:
+    if p.f64 == nil {
+      p.f64 = make(map[float64]interface{})
+    }
+    b := coercedKey.(float64)
+    p.f64[b] = value
+  case I16:
+    if p.i16 == nil {
+      p.i16 = make(map[int16]interface{})
+    }
+    b := coercedKey.(int16)
+    p.i16[b] = value
+  case I32:
+    if p.i32 == nil {
+      p.i32 = make(map[int32]interface{})
+    }
+    b := coercedKey.(int32)
+    p.i32[b] = value
+  case I64:
+    if p.i64 == nil {
+      p.i64 = make(map[int64]interface{})
+    }
+    b := coercedKey.(int64)
+    p.i64[b] = value
+  case STRING, UTF8, UTF16:
+    if p.s == nil {
+      p.s = make(map[string]interface{})
+    }
+    b := coercedKey.(string)
+    p.s[b] = value
+  case STRUCT, MAP, SET, LIST:
+    panic("Should never be here")
+  default:
+    panic("Should never be here")
+  }
+}
+
+func (p *tMap) Contains(key interface{}) bool {
+  coercedKey, ok := p.KeyType().CoerceData(key)
+  if !ok {
+    return false
+  }
+  if coercedKey == nil {
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      k := elem.Value.(TMapElem).Key()
+      if k == nil {
+        return true
+      }
+    }
+    return false
+  }
+  if !ok {
+    return false
+  }
+  switch p.KeyType() {
+  case STOP:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return false
+  case VOID:
+    // if here, then we don't have a key type yet and key is not nil
+    // so this is pretty much an empty map
+    return false
+  case BOOL:
+    m := p.b
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(bool)]
+    return ok
+  case BYTE:
+    m := p.i08
+    _, ok := m[coercedKey.(byte)]
+    return ok
+  case DOUBLE:
+    m := p.f64
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(float64)]
+    return ok
+  case I16:
+    m := p.i16
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(int16)]
+    return ok
+  case I32:
+    m := p.i32
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(int32)]
+    return ok
+  case I64:
+    m := p.i64
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(int64)]
+    return ok
+  case STRING, UTF8, UTF16:
+    // TODO(pomack) properly handle ENUM
+    m := p.s
+    if m == nil {
+      return false
+    }
+    _, ok := m[coercedKey.(string)]
+    return ok
+  case STRUCT:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      structkey, ok := k.(TStruct)
+      if ok {
+        if structkey.Equals(coercedKey.(TStruct)) {
+          return true
+        }
+        continue
+      }
+      if reflect.DeepEqual(coercedKey, k) {
+        return true
+      }
+    }
+    return false
+  case MAP:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      mapkey, ok := k.(TMap)
+      if ok {
+        if mapkey.Equals(coercedKey.(TMap)) {
+          return true
+        }
+        continue
+      }
+    }
+    return false
+  case SET:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      setkey, ok := k.(TSet)
+      if ok {
+        if setkey.Equals(coercedKey.(TSet)) {
+          return true
+        }
+        continue
+      }
+    }
+    return false
+  case LIST:
+    for elem := p.l.Front(); elem != nil; elem = elem.Next() {
+      e := elem.Value.(TMapElem)
+      k := e.Key()
+      if k == nil {
+        continue
+      }
+      listkey, ok := k.(TList)
+      if ok {
+        if listkey.Equals(coercedKey.(TList)) {
+          return true
+        }
+        continue
+      }
+    }
+    return false
+  default:
+    panic("Invalid Thrift element type")
+  }
+  return false
+}
+
+// Iterate over all elements; driver for range
+func (p *tMap) iterate(c chan<- TMapElem) {
+  switch p.KeyType() {
+  case STOP, VOID:
+    close(c)
+  case BOOL:
+    for k, v := range p.b {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case BYTE:
+    for k, v := range p.i08 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case I16:
+    for k, v := range p.i16 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case I32:
+    for k, v := range p.i32 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case I64:
+    for k, v := range p.i64 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case DOUBLE:
+    for k, v := range p.f64 {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case STRING, UTF8, UTF16:
+    for k, v := range p.s {
+      c <- NewTMapElem(k, v)
+    }
+    close(c)
+  case STRUCT:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem)
+    }
+    close(c)
+  case LIST:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem)
+    }
+    close(c)
+  case SET:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem)
+    }
+    close(c)
+  default:
+    panic("Invalid Thrift type")
+  }
+}
+
+// Channel iterator for range.
+func (p *tMap) Iter() <-chan TMapElem {
+  c := make(chan TMapElem)
+  go p.iterate(c)
+  return c
+}
+
+// Iterate over all keys; driver for range
+func (p *tMap) iterateKeys(c chan<- interface{}) {
+  switch p.KeyType() {
+  case STOP, VOID:
+    close(c)
+  case BOOL:
+    for k, _ := range p.b {
+      c <- k
+    }
+    close(c)
+  case BYTE:
+    for k, _ := range p.i08 {
+      c <- k
+    }
+    close(c)
+  case I16:
+    for k, _ := range p.i16 {
+      c <- k
+    }
+    close(c)
+  case I32:
+    for k, _ := range p.i32 {
+      c <- k
+    }
+    close(c)
+  case I64:
+    for k, _ := range p.i64 {
+      c <- k
+    }
+    close(c)
+  case DOUBLE:
+    for k, _ := range p.f64 {
+      c <- k
+    }
+    close(c)
+  case STRING, UTF8, UTF16:
+    for k, _ := range p.s {
+      c <- k
+    }
+    close(c)
+  case STRUCT:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Key()
+    }
+    close(c)
+  case LIST:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Key()
+    }
+    close(c)
+  case SET:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Key()
+    }
+    close(c)
+  default:
+    panic("Invalid Thrift type")
+  }
+}
+
+func (p *tMap) KeyIter() <-chan interface{} {
+  c := make(chan interface{})
+  go p.iterateKeys(c)
+  return c
+}
+
+// Iterate over all values; driver for range
+func (p *tMap) iterateValues(c chan<- interface{}) {
+  switch p.KeyType() {
+  case STOP, VOID:
+    close(c)
+  case BOOL:
+    for _, v := range p.b {
+      c <- v
+    }
+    close(c)
+  case BYTE:
+    for _, v := range p.i08 {
+      c <- v
+    }
+    close(c)
+  case I16:
+    for _, v := range p.i16 {
+      c <- v
+    }
+    close(c)
+  case I32:
+    for _, v := range p.i32 {
+      c <- v
+    }
+    close(c)
+  case I64:
+    for _, v := range p.i64 {
+      c <- v
+    }
+    close(c)
+  case DOUBLE:
+    for _, v := range p.f64 {
+      c <- v
+    }
+    close(c)
+  case STRING, UTF8, UTF16:
+    for _, v := range p.s {
+      c <- v
+    }
+    close(c)
+  case STRUCT:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Value()
+    }
+    close(c)
+  case LIST:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Value()
+    }
+    close(c)
+  case SET:
+    for v := p.l.Front(); v != nil; v = v.Next() {
+      c <- v.Value.(TMapElem).Value()
+    }
+    close(c)
+  default:
+    panic("Invalid Thrift type")
+  }
+}
+
+func (p *tMap) ValueIter() <-chan interface{} {
+  c := make(chan interface{})
+  go p.iterateValues(c)
+  return c
+}
+
+
+func (p *tMap) Less(other interface{}) bool {
+  cmp, ok := p.CompareTo(other)
+  return ok && cmp > 0
+}
+
+func (p *tMap) Equals(other interface{}) bool {
+  c, cok := p.CompareTo(other)
+  return cok && c == 0
+}
+
+func (p *tMap) CompareTo(other interface{}) (int, bool) {
+  return TType(MAP).Compare(p, other)
+}
+
+func (p *tMap) Keys() []interface{} {
+  size := p.Len()
+  values := make([]interface{}, size, size)
+  i := 0
+  for k := range p.KeyIter() {
+    values[i] = k
+    i++
+  }
+  return values
+}
+
+func (p *tMap) Values() []interface{} {
+  size := p.Len()
+  values := make([]interface{}, size, size)
+  i := 0
+  for v := range p.ValueIter() {
+    values[i] = v
+    i++
+  }
+  return values
+}

Added: thrift/trunk/lib/go/thrift/tmemory_buffer.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tmemory_buffer.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tmemory_buffer.go (added)
+++ thrift/trunk/lib/go/thrift/tmemory_buffer.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+import (
+  "bytes"
+  "io"
+  "os"
+)
+
+/**
+ * Memory buffer-based implementation of the TTransport interface.
+ *
+ */
+type TMemoryBuffer struct {
+  buf  *bytes.Buffer
+  size int
+}
+
+type TMemoryBufferTransportFactory struct {
+  size int
+}
+
+func (p *TMemoryBufferTransportFactory) GetTransport(trans TTransport) TTransport {
+  if trans != nil {
+    t, ok := trans.(*TMemoryBuffer)
+    if ok && t.size > 0 {
+      return NewTMemoryBufferLen(t.size)
+    }
+  }
+  return NewTMemoryBufferLen(p.size)
+}
+
+func NewTMemoryBufferTransportFactory(size int) *TMemoryBufferTransportFactory {
+  return &TMemoryBufferTransportFactory{size: size}
+}
+
+func NewTMemoryBuffer() *TMemoryBuffer {
+  return &TMemoryBuffer{buf: &bytes.Buffer{}, size: 0}
+}
+
+func NewTMemoryBufferLen(size int) *TMemoryBuffer {
+  buf := make([]byte, 0, size)
+  return &TMemoryBuffer{buf: bytes.NewBuffer(buf), size: size}
+}
+
+func (p *TMemoryBuffer) IsOpen() bool {
+  return true
+}
+
+func (p *TMemoryBuffer) Open() os.Error {
+  return nil
+}
+
+func (p *TMemoryBuffer) Peek() bool {
+  return p.IsOpen()
+}
+
+func (p *TMemoryBuffer) Close() os.Error {
+  p.buf.Reset()
+  return nil
+}
+
+func (p *TMemoryBuffer) Read(buf []byte) (int, os.Error) {
+  return p.buf.Read(buf)
+}
+
+func (p *TMemoryBuffer) ReadAll(buf []byte) (int, os.Error) {
+  return ReadAllTransport(p, buf)
+}
+
+func (p *TMemoryBuffer) ReadByte() (byte, os.Error) {
+  return p.buf.ReadByte()
+}
+
+func (p *TMemoryBuffer) ReadFrom(r io.Reader) (int64, os.Error) {
+  return p.buf.ReadFrom(r)
+}
+
+func (p *TMemoryBuffer) Write(buf []byte) (int, os.Error) {
+  return p.buf.Write(buf)
+}
+
+func (p *TMemoryBuffer) WriteString(buf string) (int, os.Error) {
+  return p.buf.WriteString(buf)
+}
+
+func (p *TMemoryBuffer) WriteTo(w io.Writer) (int64, os.Error) {
+  return p.buf.WriteTo(w)
+}
+
+func (p *TMemoryBuffer) Flush() os.Error {
+  return nil
+}
+
+func (p *TMemoryBuffer) Reset() {
+  p.buf.Reset()
+}
+
+func (p *TMemoryBuffer) Bytes() []byte {
+  return p.buf.Bytes()
+}
+
+func (p *TMemoryBuffer) Len() int {
+  return p.buf.Len()
+}
+
+func (p *TMemoryBuffer) String() string {
+  return p.buf.String()
+}

Added: thrift/trunk/lib/go/thrift/tmemory_buffer_test.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tmemory_buffer_test.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tmemory_buffer_test.go (added)
+++ thrift/trunk/lib/go/thrift/tmemory_buffer_test.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift_test
+
+import (
+  . "thrift"
+  "testing"
+)
+
+func TestMemoryBuffer(t *testing.T) {
+  trans := NewTMemoryBufferLen(1024)
+  TransportTest(t, trans, trans)
+}

Added: thrift/trunk/lib/go/thrift/tmessage.go
URL: http://svn.apache.org/viewvc/thrift/trunk/lib/go/thrift/tmessage.go?rev=1072478&view=auto
==============================================================================
--- thrift/trunk/lib/go/thrift/tmessage.go (added)
+++ thrift/trunk/lib/go/thrift/tmessage.go Sun Feb 20 02:39:19 2011
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package thrift
+
+/**
+ * Helper class that encapsulates struct metadata.
+ *
+ */
+type TMessage interface {
+  Name() string
+  TypeId() TMessageType
+  SeqId() int
+  Equals(other TMessage) bool
+}
+type tMessage struct {
+  name   string
+  typeId TMessageType
+  seqid  int
+}
+
+func NewTMessageDefault() TMessage {
+  return NewTMessage("", STOP, 0)
+}
+
+func NewTMessage(n string, t TMessageType, s int) TMessage {
+  return &tMessage{name: n, typeId: t, seqid: s}
+}
+
+func (p *tMessage) Name() string {
+  return p.name
+}
+
+func (p *tMessage) TypeId() TMessageType {
+  return p.typeId
+}
+
+func (p *tMessage) SeqId() int {
+  return p.seqid
+}
+
+func (p *tMessage) String() string {
+  return "<TMessage name:'" + p.name + "' type: " + string(p.typeId) + " seqid:" + string(p.seqid) + ">"
+}
+
+func (p *tMessage) Equals(other TMessage) bool {
+  return p.name == other.Name() && p.typeId == other.TypeId() && p.seqid == other.SeqId()
+}
+
+var EMPTY_MESSAGE TMessage
+
+func init() {
+  EMPTY_MESSAGE = NewTMessageDefault()
+}