commit f9cc2426473a2b5619049eacdbee5fdf19c81344 from: Stephen J Day date: Thu Nov 05 05:14:16 2015 UTC fs/p9p/new: bring back type safety for message types Type safety for messages was removed to allowing message types to be anything. In particular, this was useful for error types. This introduced a few nasty bugs that wasn't worth the convenience of automatically packing errors over a server channel. Signed-off-by: Stephen J Day 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 }