add uuid support in go
diff --git a/go.sum b/go.sum
index cfde584..3f616cf 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,7 @@
 github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
 github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
diff --git a/lib/go/thrift/binary_protocol.go b/lib/go/thrift/binary_protocol.go
index c6fae0f..adbd66f 100644
--- a/lib/go/thrift/binary_protocol.go
+++ b/lib/go/thrift/binary_protocol.go
@@ -242,6 +242,11 @@
 	return p.WriteI64(ctx, int64(math.Float64bits(value)))
 }
 
+func (p *TBinaryProtocol) WriteUuid(ctx context.Context, value Uuid) error {
+	_, err := p.trans.Write(value[:])
+	return NewTProtocolException(err)
+}
+
 func (p *TBinaryProtocol) WriteString(ctx context.Context, value string) error {
 	e := p.WriteI32(ctx, int32(len(value)))
 	if e != nil {
@@ -453,6 +458,12 @@
 	return value, err
 }
 
+func (p *TBinaryProtocol) ReadUuid(ctx context.Context) (value Uuid, err error) {
+	uuid := Uuid{}
+	err = p.readAll(ctx, uuid[0:16])
+	return uuid, err
+}
+
 func (p *TBinaryProtocol) ReadString(ctx context.Context) (value string, err error) {
 	size, e := p.ReadI32(ctx)
 	if e != nil {
diff --git a/lib/go/thrift/compact_protocol.go b/lib/go/thrift/compact_protocol.go
index dc86fe6..7b96800 100644
--- a/lib/go/thrift/compact_protocol.go
+++ b/lib/go/thrift/compact_protocol.go
@@ -328,6 +328,11 @@
 	return NewTProtocolException(err)
 }
 
+func (p *TCompactProtocol) WriteUuid(ctx context.Context, value Uuid) error {
+	_, err := p.trans.Write(value[:])
+	return NewTProtocolException(err)
+}
+
 // Write a string to the wire with a varint size preceding.
 func (p *TCompactProtocol) WriteString(ctx context.Context, value string) error {
 	_, e := p.writeVarint32(int32(len(value)))
@@ -621,6 +626,16 @@
 	return string(buf), NewTProtocolException(e)
 }
 
+func (p *TCompactProtocol) ReadUuid(ctx context.Context) (value Uuid, err error) {
+	if buf, e := safeReadBytes(16, p.trans); e != nil {
+		return Uuid{}, NewTProtocolException(e)
+	} else {
+		var uuid Uuid
+		copy(uuid[:], buf)
+		return uuid, nil
+	}
+}
+
 // Read a []byte from the wire.
 func (p *TCompactProtocol) ReadBinary(ctx context.Context) (value []byte, err error) {
 	length, e := p.readVarint32()
diff --git a/lib/go/thrift/debug_protocol.go b/lib/go/thrift/debug_protocol.go
index c1f4fab..be071f4 100644
--- a/lib/go/thrift/debug_protocol.go
+++ b/lib/go/thrift/debug_protocol.go
@@ -234,6 +234,16 @@
 	}
 	return err
 }
+
+func (tdp *TDebugProtocol) WriteUuid(ctx context.Context, value Uuid) error {
+	err := tdp.Delegate.WriteUuid(ctx, value)
+	tdp.logf("%sWriteUuid(value=%#v) => %#v", tdp.LogPrefix, value, err)
+	if tdp.DuplicateTo != nil {
+		tdp.DuplicateTo.WriteUuid(ctx, value)
+	}
+	return err
+}
+
 func (tdp *TDebugProtocol) WriteDouble(ctx context.Context, value float64) error {
 	err := tdp.Delegate.WriteDouble(ctx, value)
 	tdp.logf("%sWriteDouble(value=%#v) => %#v", tdp.LogPrefix, value, err)
@@ -411,6 +421,16 @@
 	}
 	return
 }
+
+func (tdp *TDebugProtocol) ReadUuid(ctx context.Context) (value Uuid, err error) {
+	value, err = tdp.Delegate.ReadUuid(ctx)
+	tdp.logf("%sReadUuid() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
+	if tdp.DuplicateTo != nil {
+		tdp.DuplicateTo.WriteUuid(ctx, value)
+	}
+	return
+}
+
 func (tdp *TDebugProtocol) ReadBinary(ctx context.Context) (value []byte, err error) {
 	value, err = tdp.Delegate.ReadBinary(ctx)
 	tdp.logf("%sReadBinary() (value=%#v, err=%#v)", tdp.LogPrefix, value, err)
diff --git a/lib/go/thrift/header_protocol.go b/lib/go/thrift/header_protocol.go
index 878041f..9a31b52 100644
--- a/lib/go/thrift/header_protocol.go
+++ b/lib/go/thrift/header_protocol.go
@@ -213,6 +213,10 @@
 	return p.protocol.WriteDouble(ctx, value)
 }
 
+func (p *THeaderProtocol) WriteUuid(ctx context.Context, value Uuid) error {
+	return p.protocol.WriteUuid(ctx, value)
+}
+
 func (p *THeaderProtocol) WriteString(ctx context.Context, value string) error {
 	return p.protocol.WriteString(ctx, value)
 }
@@ -326,6 +330,10 @@
 	return p.protocol.ReadDouble(ctx)
 }
 
+func (p *THeaderProtocol) ReadUuid(ctx context.Context) (value Uuid, err error) {
+	return p.protocol.ReadUuid(ctx)
+}
+
 func (p *THeaderProtocol) ReadString(ctx context.Context) (value string, err error) {
 	return p.protocol.ReadString(ctx)
 }
diff --git a/lib/go/thrift/json_protocol.go b/lib/go/thrift/json_protocol.go
index d248ecf..0867f3b 100644
--- a/lib/go/thrift/json_protocol.go
+++ b/lib/go/thrift/json_protocol.go
@@ -33,7 +33,6 @@
 
 // JSON protocol implementation for thrift.
 // Utilizes Simple JSON protocol
-//
 type TJSONProtocol struct {
 	*TSimpleJSONProtocol
 }
@@ -189,6 +188,10 @@
 	return p.OutputF64(v)
 }
 
+func (p *TJSONProtocol) WriteUuid(ctx context.Context, uuid Uuid) error {
+	return p.WriteString(ctx, uuid.String())
+}
+
 func (p *TJSONProtocol) WriteString(ctx context.Context, v string) error {
 	return p.OutputString(v)
 }
@@ -379,6 +382,14 @@
 	return v, err
 }
 
+func (p *TJSONProtocol) ReadUuid(ctx context.Context) (Uuid, error) {
+	if s, err := p.ReadString(ctx); err != nil {
+		return Uuid{}, err
+	} else {
+		return NewUuidFromString(s)
+	}
+}
+
 func (p *TJSONProtocol) ReadString(ctx context.Context) (string, error) {
 	var v string
 	if err := p.ParsePreValue(); err != nil {
diff --git a/lib/go/thrift/protocol.go b/lib/go/thrift/protocol.go
index 647c0bd..afe35d7 100644
--- a/lib/go/thrift/protocol.go
+++ b/lib/go/thrift/protocol.go
@@ -51,6 +51,7 @@
 	WriteI64(ctx context.Context, value int64) error
 	WriteDouble(ctx context.Context, value float64) error
 	WriteString(ctx context.Context, value string) error
+	WriteUuid(ctx context.Context, value Uuid) error
 	WriteBinary(ctx context.Context, value []byte) error
 
 	ReadMessageBegin(ctx context.Context) (name string, typeId TMessageType, seqid int32, err error)
@@ -71,6 +72,7 @@
 	ReadI32(ctx context.Context) (value int32, err error)
 	ReadI64(ctx context.Context) (value int64, err error)
 	ReadDouble(ctx context.Context) (value float64, err error)
+	ReadUuid(ctx context.Context) (value Uuid, err error)
 	ReadString(ctx context.Context) (value string, err error)
 	ReadBinary(ctx context.Context) (value []byte, err error)
 
diff --git a/lib/go/thrift/simple_json_protocol.go b/lib/go/thrift/simple_json_protocol.go
index 5cefb60..8bb31a9 100644
--- a/lib/go/thrift/simple_json_protocol.go
+++ b/lib/go/thrift/simple_json_protocol.go
@@ -93,7 +93,6 @@
 // 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 TSimpleJSONProtocol struct {
 	trans TTransport
 
@@ -316,6 +315,10 @@
 	return p.OutputString(v)
 }
 
+func (p *TSimpleJSONProtocol) WriteUuid(ctx context.Context, v Uuid) error {
+	return p.WriteString(ctx, v.String())
+}
+
 func (p *TSimpleJSONProtocol) WriteBinary(ctx context.Context, v []byte) error {
 	// JSON library only takes in a string,
 	// not an arbitrary byte array, to ensure bytes are transmitted
@@ -534,6 +537,14 @@
 	return v, err
 }
 
+func (p *TSimpleJSONProtocol) ReadUuid(ctx context.Context) (Uuid, error) {
+	if s, err := p.ReadString(ctx); err != nil {
+		return Uuid{}, err
+	} else {
+		return NewUuidFromString(s)
+	}
+}
+
 func (p *TSimpleJSONProtocol) ReadString(ctx context.Context) (string, error) {
 	var v string
 	if err := p.ParsePreValue(); err != nil {
diff --git a/lib/go/thrift/type.go b/lib/go/thrift/type.go
index 4292ffc..8c9046d 100644
--- a/lib/go/thrift/type.go
+++ b/lib/go/thrift/type.go
@@ -39,8 +39,9 @@
 	SET    = 14
 	LIST   = 15
 	UTF8   = 16
-	UTF16  = 17
-	//BINARY = 18   wrong and unusued
+	UUID   = 17
+	//UTF16  = 17   wrong and unused
+	//BINARY = 18   wrong and unused
 )
 
 var typeNames = map[int]string{
@@ -58,7 +59,7 @@
 	SET:    "SET",
 	LIST:   "LIST",
 	UTF8:   "UTF8",
-	UTF16:  "UTF16",
+	UUID:   "UUID",
 }
 
 func (p TType) String() string {
diff --git a/lib/go/thrift/uuid.go b/lib/go/thrift/uuid.go
new file mode 100644
index 0000000..2065ba8
--- /dev/null
+++ b/lib/go/thrift/uuid.go
@@ -0,0 +1,102 @@
+/*
+ * 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/hex"
+	"errors"
+)
+
+// most of the code is copied from https://github.com/google/uuid in order to reduce dependency on
+// external libraries
+
+type Uuid [16]byte
+
+// from https://github.com/google/uuid/blob/512b657a42880af87e9f0d863aa6dccf3540d4ba/util.go#L18
+// xvalues returns the value of a byte as a hexadecimal digit or 255.
+var xvalues = [256]byte{
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
+	255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+}
+
+// from https://github.com/google/uuid/blob/512b657a42880af87e9f0d863aa6dccf3540d4ba/util.go#L39
+// xtob converts hex characters x1 and x2 into a byte.
+func xtob(x1, x2 byte) (byte, bool) {
+	b1 := xvalues[x1]
+	b2 := xvalues[x2]
+	return (b1 << 4) | b2, b1 != 255 && b2 != 255
+}
+
+func (uuid *Uuid) String() string {
+	var buf [36]byte
+	encodeHex(buf[:], uuid)
+	return string(buf[:])
+}
+
+// copied from https://github.com/google/uuid/blob/44b5fee7c49cf3bcdf723f106b36d56ef13ccc88/uuid.go#L200
+func encodeHex(dst []byte, uuid *Uuid) {
+	hex.Encode(dst, uuid[:4])
+	dst[8] = '-'
+	hex.Encode(dst[9:13], uuid[4:6])
+	dst[13] = '-'
+	hex.Encode(dst[14:18], uuid[6:8])
+	dst[18] = '-'
+	hex.Encode(dst[19:23], uuid[8:10])
+	dst[23] = '-'
+	hex.Encode(dst[24:], uuid[10:])
+}
+
+// from https://github.com/google/uuid/blob/44b5fee7c49cf3bcdf723f106b36d56ef13ccc88/uuid.go#L64
+func NewUuidFromString(s string) (Uuid, error) {
+	var uuid Uuid
+	if len(s) != 36 {
+		return uuid, errors.New("invalid uuid string")
+	}
+	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
+		return uuid, errors.New("invalid UUID format")
+	}
+	for i, x := range [16]int{
+		0, 2, 4, 6,
+		9, 11,
+		14, 16,
+		19, 21,
+		24, 26, 28, 30, 32, 34} {
+		v, ok := xtob(s[x], s[x+1])
+		if !ok {
+			return uuid, errors.New("invalid UUID format")
+		}
+		uuid[i] = v
+	}
+	return uuid, nil
+}
diff --git a/lib/go/thrift/uuid_test.go b/lib/go/thrift/uuid_test.go
new file mode 100644
index 0000000..bef9b41
--- /dev/null
+++ b/lib/go/thrift/uuid_test.go
@@ -0,0 +1,56 @@
+/*
+ * 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 "testing"
+
+func TestUuidString(t *testing.T) {
+	uuid, err := NewUuidFromString("12345678-1234-1234-1234-123456789012")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if uuid.String() != "12345678-1234-1234-1234-123456789012" {
+		t.Fatal("String() returned wrong value")
+	}
+}
+
+func TestUuidFromString(t *testing.T) {
+	uuid, err := NewUuidFromString("12345678-1234-1234-1234-123456789012")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if uuid != [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12} {
+		t.Fatal("NewUuidFromString returned wrong value")
+	}
+}
+
+func TestUuidFromStringShortCase(t *testing.T) {
+	_, err := NewUuidFromString("12345678-1234-1234-1234-12345678901")
+	if err == nil {
+		t.Fatal("NewUuidFromString should have returned an error")
+	}
+}
+
+func TestUuidFromStringLongCase(t *testing.T) {
+	_, err := NewUuidFromString("12345678-1234-1234-1234-1234567890123")
+	if err == nil {
+		t.Fatal("NewUuidFromString should have returned an error")
+	}
+}