Commit Diff


commit - deb98ab43c4d46aadb8214e05c8178b2eceb1fae
commit + f9cc2426473a2b5619049eacdbee5fdf19c81344
blob - 326a180bfe49d872d8cbfae19d0b2e3f5e0d92fb
blob + 98abc3492b799689a4048e7b16dc42365a661d27
--- encoding.go
+++ encoding.go
@@ -349,7 +349,7 @@ func (d *decoder) decode(vs ...interface{}) error {
 				return err
 			}
 
-			v.Message = rv.Elem().Interface()
+			v.Message = rv.Elem().Interface().(Message)
 		case Message:
 			elements, err := fields9p(v)
 			if err != nil {
@@ -491,7 +491,8 @@ func fields9p(v interface{}) ([]interface{}, error) {
 		f := rv.Field(i)
 
 		if !f.CanInterface() {
-			return nil, fmt.Errorf("can't interface: %v", f)
+			// unexported field, skip it.
+			continue
 		}
 
 		if f.CanAddr() {
blob - 4229e6c22b31eaa77298b5daf75173d338d778aa
blob + 698be68e38a3cb680f70c490e783313e8f2398fe
--- encoding_test.go
+++ encoding_test.go
@@ -202,6 +202,10 @@ func TestEncodeDecode(t *testing.T) {
 			fatalf("unexpected bytes for fcall: \n%#v != \n%#v", p, testcase.marshaled)
 		}
 
+		if size9p(testcase.target) == 0 {
+			fatalf("size of target should never be zero")
+		}
+
 		// check that size9p is working correctly
 		if int(size9p(testcase.target)) != len(testcase.marshaled) {
 			fatalf("size not correct: %v != %v", int(size9p(testcase.target)), len(testcase.marshaled))
blob - 5ce3d9ce659404d591a1c55302d4c95a0e675ef9
blob + ba7e8afaf8519d8105ffc64584a83ef84983882e
--- fcall.go
+++ fcall.go
@@ -108,15 +108,14 @@ type Fcall struct {
 
 func newFcall(msg Message) *Fcall {
 	var tag Tag
-	mtype := messageType(msg)
 
-	switch mtype {
+	switch msg.Type() {
 	case Tversion, Rversion:
 		tag = NOTAG
 	}
 
 	return &Fcall{
-		Type:    mtype,
+		Type:    msg.Type(),
 		Tag:     tag,
 		Message: msg,
 	}
blob - 259e3bf04f20fa65449c543557ecd1a4ac6d0363
blob + 5df491e879d897817f19b55450fa6072ca331d95
--- messages.go
+++ messages.go
@@ -3,7 +3,10 @@ package p9pnew
 import "fmt"
 
 // Message represents the target of an fcall.
-type Message interface{}
+type Message interface {
+	// Type returns the type of call for the target message.
+	Type() FcallType
+}
 
 // newMessage returns a new instance of the message based on the Fcall type.
 func newMessage(typ FcallType) (Message, error) {
@@ -67,70 +70,6 @@ func newMessage(typ FcallType) (Message, error) {
 	return nil, fmt.Errorf("unknown message type")
 }
 
-func messageType(m Message) FcallType {
-	switch v := m.(type) {
-	case MessageTversion:
-		return Tversion
-	case MessageRversion:
-		return Rversion
-	case MessageTauth:
-		return Tauth
-	case MessageRauth:
-		return Rauth
-	case MessageTflush:
-		return Tflush
-	case MessageRflush:
-		return Rflush
-	case MessageRerror:
-		return Rerror
-	case MessageTattach:
-		return Tattach
-	case MessageRattach:
-		return Rattach
-	case MessageTwalk:
-		return Twalk
-	case MessageRwalk:
-		return Rwalk
-	case MessageTopen:
-		return Topen
-	case MessageRopen:
-		return Ropen
-	case MessageTcreate:
-		return Tcreate
-	case MessageRcreate:
-		return Rcreate
-	case MessageTread:
-		return Tread
-	case MessageRread:
-		return Rread
-	case MessageTwrite:
-		return Twrite
-	case MessageRwrite:
-		return Rwrite
-	case MessageTclunk:
-		return Tclunk
-	case MessageRclunk:
-		return Rclunk
-	case MessageTremove:
-		return Tremove
-	case MessageRremove:
-		return Rremove
-	case MessageTstat:
-		return Tstat
-	case MessageRstat:
-		return Rstat
-	case MessageTwstat:
-		return Twstat
-	case MessageRwstat:
-		return Rwstat
-	case error:
-		return Rerror
-	default:
-		// NOTE(stevvooe): This is considered a programming error.
-		panic(fmt.Sprintf("unsupported message type: %T", v))
-	}
-}
-
 // MessageVersion encodes the message body for Tversion and Rversion RPC
 // calls. The body is identical in both directions.
 type MessageTversion struct {
@@ -256,3 +195,31 @@ type MessageTwstat struct {
 }
 
 type MessageRwstat struct{}
+
+func (MessageTversion) Type() FcallType { return Tversion }
+func (MessageRversion) Type() FcallType { return Rversion }
+func (MessageTauth) Type() FcallType    { return Tauth }
+func (MessageRauth) Type() FcallType    { return Rauth }
+func (MessageRerror) Type() FcallType   { return Rerror }
+func (MessageTflush) Type() FcallType   { return Tflush }
+func (MessageRflush) Type() FcallType   { return Rflush }
+func (MessageTattach) Type() FcallType  { return Tattach }
+func (MessageRattach) Type() FcallType  { return Rattach }
+func (MessageTwalk) Type() FcallType    { return Twalk }
+func (MessageRwalk) Type() FcallType    { return Rwalk }
+func (MessageTopen) Type() FcallType    { return Topen }
+func (MessageRopen) Type() FcallType    { return Ropen }
+func (MessageTcreate) Type() FcallType  { return Tcreate }
+func (MessageRcreate) Type() FcallType  { return Rcreate }
+func (MessageTread) Type() FcallType    { return Tread }
+func (MessageRread) Type() FcallType    { return Rread }
+func (MessageTwrite) Type() FcallType   { return Twrite }
+func (MessageRwrite) Type() FcallType   { return Rwrite }
+func (MessageTclunk) Type() FcallType   { return Tclunk }
+func (MessageRclunk) Type() FcallType   { return Rclunk }
+func (MessageTremove) Type() FcallType  { return Tremove }
+func (MessageRremove) Type() FcallType  { return Rremove }
+func (MessageTstat) Type() FcallType    { return Tstat }
+func (MessageRstat) Type() FcallType    { return Rstat }
+func (MessageTwstat) Type() FcallType   { return Twstat }
+func (MessageRwstat) Type() FcallType   { return Rwstat }