Commit 06476df7 authored by Larz Conwell's avatar Larz Conwell

Return errors rather than doing panics.

This makes it simpler to handle errors in code importing this package.
parent b555ed17
......@@ -8,6 +8,14 @@ import (
"reflect"
)
type TypeError struct {
typ string
}
func (te *TypeError) Error() string {
return fmt.Sprintf("no support for type '%s'", te.typ)
}
// An Encoder encodes Go data structures into pickle byte stream
type Encoder struct {
w io.Writer
......@@ -79,7 +87,7 @@ func (e *Encoder) encode(rv reflect.Value) error {
e.w.Write([]byte{opNone})
default:
panic(fmt.Sprintf("no support for type '%s'", rk.String()))
return &TypeError{typ: rk.String()}
}
return nil
......
......@@ -80,6 +80,7 @@ const (
var errNotImplemented = errors.New("unimplemented opcode")
var ErrInvalidPickleVersion = errors.New("invalid pickle version")
var ErrNoMarker = errors.New("no marker in stack")
type OpcodeError struct {
Key byte
......@@ -243,15 +244,15 @@ func (d *Decoder) mark() {
}
// Return the position of the topmost marker
func (d *Decoder) marker() int {
func (d *Decoder) marker() (int, error) {
m := mark{}
var k int
for k = len(d.stack) - 1; d.stack[k] != m && k > 0; k-- {
}
if k >= 0 {
return k
return k, nil
}
panic("no marker in stack")
return 0, ErrNoMarker
}
// Append a new value
......@@ -553,7 +554,11 @@ func (d *Decoder) global() error {
}
func (d *Decoder) loadDict() error {
k := d.marker()
k, err := d.marker()
if err != nil {
return err
}
m := make(map[interface{}]interface{}, 0)
items := d.stack[k+1:]
for i := 0; i < len(items); i += 2 {
......@@ -570,7 +575,11 @@ func (d *Decoder) loadEmptyDict() error {
}
func (d *Decoder) loadAppends() error {
k := d.marker()
k, err := d.marker()
if err != nil {
return err
}
l := d.stack[k-1]
switch l.(type) {
case []interface{}:
......@@ -621,14 +630,22 @@ func (d *Decoder) loadBool(b bool) error {
}
func (d *Decoder) loadList() error {
k := d.marker()
k, err := d.marker()
if err != nil {
return err
}
v := append([]interface{}{}, d.stack[k+1:]...)
d.stack = append(d.stack[:k], v)
return nil
}
func (d *Decoder) loadTuple() error {
k := d.marker()
k, err := d.marker()
if err != nil {
return err
}
v := append([]interface{}{}, d.stack[k+1:]...)
d.stack = append(d.stack[:k], v)
return nil
......@@ -700,7 +717,11 @@ func (d *Decoder) loadSetItem() error {
}
func (d *Decoder) loadSetItems() error {
k := d.marker()
k, err := d.marker()
if err != nil {
return err
}
l := d.stack[k-1]
switch m := l.(type) {
case map[interface{}]interface{}:
......
......@@ -18,7 +18,11 @@ func TestMarker(t *testing.T) {
buf := bytes.Buffer{}
dec := NewDecoder(&buf)
dec.mark()
if dec.marker() != 0 {
k, err := dec.marker()
if err != nil {
t.Error(err)
}
if k != 0 {
t.Error("no marker found")
}
}
......@@ -50,7 +54,7 @@ func TestDecode(t *testing.T) {
{"unicode", "V\\u65e5\\u672c\\u8a9e\np0\n.", string("日本語")},
{"empty dict", "(dp0\n.", make(map[interface{}]interface{})},
{"dict with strings", "(dp0\nS'a'\np1\nS'1'\np2\nsS'b'\np3\nS'2'\np4\ns.", map[interface{}]interface{}{"a": "1", "b": "2"}},
{"GLOBAL and REDUCE opcodes", "cfoo\nbar\nS'bing'\n\x85R.", Call{Callable: Class{Module: "foo", Name: "bar"}, Args: []interface{} {"bing"}}},
{"GLOBAL and REDUCE opcodes", "cfoo\nbar\nS'bing'\n\x85R.", Call{Callable: Class{Module: "foo", Name: "bar"}, Args: []interface{}{"bing"}}},
{"LONG_BINPUT opcode", "(lr0000I17\na.", []interface{}{int64(17)}},
{"graphite message1", string(graphitePickle1), []interface{}{map[interface{}]interface{}{"values": []interface{}{float64(473), float64(497), float64(540), float64(1497), float64(1808), float64(1890), float64(2013), float64(1821), float64(1847), float64(2176), float64(2156), float64(1250), float64(2055), float64(1570), None{}, None{}}, "start": int64(1383782400), "step": int64(86400), "end": int64(1385164800), "name": "ZZZZ.UUUUUUUU.CCCCCCCC.MMMMMMMM.XXXXXXXXX.TTT"}}},
{"graphite message2", string(graphitePickle2), []interface{}{map[interface{}]interface{}{"values": []interface{}{float64(473), float64(497), float64(540), float64(1497), float64(1808), float64(1890), float64(2013), float64(1821), float64(1847), float64(2176), float64(2156), float64(1250), float64(2055), float64(1570), None{}, None{}}, "start": int64(1383782400), "step": int64(86400), "end": int64(1385164800), "name": "user.login.area.machine.metric.minute"}}},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment