Commit c87dde78 authored by Luke Champine's avatar Luke Champine

MarshalSia now takes an io.Writer

This makes sense, symmetry-wise, and it also means that we can
encode large objects (e.g. blocks) to streams without having to
hold the entire byte slice in memory.
parent fe3120a9
......@@ -12,12 +12,21 @@ import (
"reflect"
)
// A SiaMarshaler can encode itself as a byte slice.
const (
maxDecodeLen = 10 * 1024 * 1024 // 10 MB
maxSliceLen = 4 * 1024 * 1024 // 4 MB
)
var (
errBadPointer = errors.New("cannot decode into invalid pointer")
)
// A SiaMarshaler can encode and write itself to a stream.
type SiaMarshaler interface {
MarshalSia() []byte
MarshalSia(io.Writer) error
}
// A SiaUnmarshaler can decode itself from a reader.
// A SiaUnmarshaler can read and decode itself from a stream.
type SiaUnmarshaler interface {
UnmarshalSia(io.Reader) error
}
......@@ -27,15 +36,6 @@ type Encoder struct {
w io.Writer
}
const (
maxDecodeLen = 10 * 1024 * 1024 // 10 MB
maxSliceLen = 4 * 1024 * 1024 // 4 MB
)
var (
errBadPointer = errors.New("cannot decode into invalid pointer")
)
// Encode writes the encoding of v to the stream. For encoding details, see
// the package docstring.
func (e *Encoder) Encode(v interface{}) error {
......@@ -45,7 +45,7 @@ func (e *Encoder) Encode(v interface{}) error {
// write catches instances where short writes do not return an error.
func (e *Encoder) write(p []byte) error {
n, err := e.w.Write(p)
if n != len(p) {
if n != len(p) && err == nil {
return io.ErrShortWrite
}
return err
......@@ -56,7 +56,7 @@ func (e *Encoder) write(p []byte) error {
func (e *Encoder) encode(val reflect.Value) error {
// check for MarshalSia interface first
if m, ok := val.Interface().(SiaMarshaler); ok {
return e.write(m.MarshalSia())
return m.MarshalSia(e.w)
}
switch val.Kind() {
......
......@@ -48,8 +48,8 @@ type (
}
)
func (t test5) MarshalSia() []byte {
return AddPrefix([]byte(t.s))
func (t test5) MarshalSia(w io.Writer) error {
return WritePrefix(w, []byte(t.s))
}
func (t *test5) UnmarshalSia(r io.Reader) error {
......@@ -58,9 +58,9 @@ func (t *test5) UnmarshalSia(r io.Reader) error {
return err
}
// reuse above methods, but with a pointer receiver
func (t *test6) MarshalSia() []byte {
return AddPrefix([]byte(t.s))
// same as above methods, but with a pointer receiver
func (t *test6) MarshalSia(w io.Writer) error {
return WritePrefix(w, []byte(t.s))
}
func (t *test6) UnmarshalSia(r io.Reader) error {
......@@ -107,7 +107,7 @@ func TestEncode(t *testing.T) {
for i := range testStructs {
err := enc.Encode(testStructs[i])
if err != io.ErrShortWrite {
t.Error("expected ErrShortWrite, got", err)
t.Errorf("testStructs[%d]: expected ErrShortWrite, got %v", i, err)
}
}
// special case, not covered by testStructs
......
......@@ -48,7 +48,7 @@ func AddPrefix(b []byte) []byte {
// WritePrefix writes a length-prefixed byte slice to w.
func WritePrefix(w io.Writer, data []byte) error {
n, err := w.Write(AddPrefix(data))
if n != len(data)+8 {
if n != len(data)+8 && err == nil {
return io.ErrShortWrite
}
return err
......
......@@ -183,12 +183,12 @@ func (c *Currency) UnmarshalJSON(b []byte) error {
return nil
}
// MarshalSia implements the encoding.SiaMarshaler interface. It returns the
// byte-slice representation of the Currency's internal big.Int. Note that as
// the bytes of the big.Int correspond to the absolute value of the integer,
// there is no way to marshal a negative Currency.
func (c Currency) MarshalSia() []byte {
return encoding.AddPrefix(c.i.Bytes())
// MarshalSia implements the encoding.SiaMarshaler interface. It writes the
// byte-slice representation of the Currency's internal big.Int to w. Note
// that as the bytes of the big.Int correspond to the absolute value of the
// integer, there is no way to marshal a negative Currency.
func (c Currency) MarshalSia(w io.Writer) error {
return encoding.WritePrefix(w, c.i.Bytes())
}
// UnmarshalSia implements the encoding.SiaUnmarshaler interface.
......
......@@ -166,9 +166,13 @@ func TestCurrencyMarshalJSON(t *testing.T) {
// the currency type.
func TestCurrencyMarshalSia(t *testing.T) {
c := NewCurrency64(1656)
cMar := c.MarshalSia()
buf := new(bytes.Buffer)
err := c.MarshalSia(buf)
if err != nil {
t.Fatal(err)
}
var cUmar Currency
cUmar.UnmarshalSia(bytes.NewReader(cMar))
cUmar.UnmarshalSia(buf)
if c.Cmp(cUmar) != 0 {
t.Error("marshal and unmarshal mismatch for currency type")
}
......
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