status-go/vendor/olympos.io/encoding/edn/types.go

150 lines
3.1 KiB
Go

// Copyright 2015-2017 Jean Niklas L'orange. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package edn
import (
"bufio"
"bytes"
"errors"
"fmt"
)
// RawMessage is a raw encoded, but valid, EDN value. It implements Marshaler
// and Unmarshaler and can be used to delay EDN decoding or precompute an EDN
// encoding.
type RawMessage []byte
// MarshalEDN returns m as the EDN encoding of m.
func (m RawMessage) MarshalEDN() ([]byte, error) {
if m == nil {
return []byte("nil"), nil
}
return m, nil
}
// UnmarshalEDN sets *m to a copy of data.
func (m *RawMessage) UnmarshalEDN(data []byte) error {
if m == nil {
return errors.New("edn.RawMessage: UnmarshalEDN on nil pointer")
}
*m = append((*m)[0:0], data...)
return nil
}
// A Keyword is an EDN keyword without : prepended in front.
type Keyword string
func (k Keyword) String() string {
return fmt.Sprintf(":%s", string(k))
}
func (k Keyword) MarshalEDN() ([]byte, error) {
return []byte(k.String()), nil
}
// A Symbol is an EDN symbol.
type Symbol string
func (s Symbol) String() string {
return string(s)
}
func (s Symbol) MarshalEDN() ([]byte, error) {
return []byte(s), nil
}
// A Tag is a tagged value. The Tagname represents the name of the tag, and the
// Value is the value of the element.
type Tag struct {
Tagname string
Value interface{}
}
func (t Tag) String() string {
return fmt.Sprintf("#%s %v", t.Tagname, t.Value)
}
func (t Tag) MarshalEDN() ([]byte, error) {
str := []byte(fmt.Sprintf(`#%s `, t.Tagname))
b, err := Marshal(t.Value)
if err != nil {
return nil, err
}
return append(str, b...), nil
}
func (t *Tag) UnmarshalEDN(bs []byte) error {
// read actual tag, using the lexer.
var lex lexer
lex.reset()
buf := bufio.NewReader(bytes.NewBuffer(bs))
start := 0
endTag := 0
tag:
for {
r, rlen, err := buf.ReadRune()
if err != nil {
return err
}
ls := lex.state(r)
switch ls {
case lexIgnore:
start += rlen
endTag += rlen
case lexError:
return lex.err
case lexEndPrev:
break tag
case lexEnd: // unexpected, assuming tag which is not ending with lexEnd
return errUnexpected
case lexCont:
endTag += rlen
}
}
t.Tagname = string(bs[start+1 : endTag])
return Unmarshal(bs[endTag:], &t.Value)
}
// A Rune type is a wrapper for a rune. It can be used to encode runes as
// characters instead of int32 values.
type Rune rune
func (r Rune) MarshalEDN() ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0, 10))
encodeRune(buf, rune(r))
return buf.Bytes(), nil
}
func encodeRune(buf *bytes.Buffer, r rune) {
const hex = "0123456789abcdef"
if !isWhitespace(r) {
buf.WriteByte('\\')
buf.WriteRune(r)
} else {
switch r {
case '\b':
buf.WriteString(`\backspace`)
case '\f':
buf.WriteString(`\formfeed`)
case '\n':
buf.WriteString(`\newline`)
case '\r':
buf.WriteString(`\return`)
case '\t':
buf.WriteString(`\tab`)
case ' ':
buf.WriteString(`\space`)
default:
buf.WriteByte('\\')
buf.WriteByte('u')
buf.WriteByte(hex[r>>12&0xF])
buf.WriteByte(hex[r>>8&0xF])
buf.WriteByte(hex[r>>4&0xF])
buf.WriteByte(hex[r&0xF])
}
}
}