Documentation
¶
Overview ¶
Package edn implements encoding and decoding of EDN values as defined in https://github.com/edn-format/edn. For a full introduction on how to use go-edn, see https://github.com/go-edn/edn/blob/v1/docs/introduction.md. Fully self-contained examples of go-edn can be found at https://github.com/go-edn/edn/tree/v1/examples.
Note that the small examples in this package is not checking errors as persively as you should do when you use this package. This is done because I'd like the examples to be easily readable and understandable. The bigger examples provide proper error handling.
Example (ArbitraryKeys) ¶
EDN, in contrast to JSON, supports arbitrary values as keys.
package main import ( "fmt" "olympos.io/encoding/edn" ) type Point3 struct { X, Y, Z int64 } type Unit struct { Type edn.Keyword HP int } // EDN, in contrast to JSON, supports arbitrary values as keys. func main() { input := `{{:x 1 :y 2 :z 3} "Greybeard" {:y 10 :x 1 :z -10} "Blackwind"}` var locStarships map[Point3]string err := edn.UnmarshalString(input, &locStarships) if err != nil { panic(err) } p := Point3{1, 10, -10} fmt.Printf("Starship at location %v is %s\n", p, locStarships[p]) input = `{[0 2] {:type :scout :hp 55} [-3 10] {:type :villager :hp 25} [5 5] {:type :bowman :hp 32} [5 6] {:type :bowman :hp 29}}` var locUnits map[[2]int]Unit err = edn.UnmarshalString(input, &locUnits) if err != nil { panic(err) } loc := [2]int{5, 5} fmt.Printf("Unit at location %v is %+v\n", loc, locUnits[loc]) }
Output: Starship at location {1 10 -10} is Blackwind Unit at location [5 5] is {Type::bowman HP:32}
Example (EnumsAndSets) ¶
This example shows how one can implement enums and sets, and how to support multiple different forms for a specific value type. The set implemented here supports the notation `:all` for all values.
package main import ( "fmt" "olympos.io/encoding/edn" ) type UserOption edn.Keyword type UnknownUserOptionError UserOption func (err UnknownUserOptionError) Error() string { return fmt.Sprintf("Unknown user option %s", edn.Keyword(err)) } const ( UnknownOption = UserOption("") ShowEmail = UserOption("show-email") Notifications = UserOption("notifications") DailyEmail = UserOption("daily-email") RememberMe = UserOption("remember-me") ) func ListUserOptions() []UserOption { return []UserOption{ ShowEmail, Notifications, DailyEmail, RememberMe, } } func (uo *UserOption) UnmarshalEDN(bs []byte) error { var kw edn.Keyword err := edn.Unmarshal(bs, &kw) if err != nil { return err } opt := UserOption(kw) switch opt { case ShowEmail, Notifications, DailyEmail, RememberMe: *uo = opt return nil default: return UnknownUserOptionError(opt) } } type UserOptions map[UserOption]bool func (opts *UserOptions) UnmarshalEDN(bs []byte) error { var kw edn.Keyword // try to decode into keyword first err := edn.Unmarshal(bs, &kw) if err == nil && kw == edn.Keyword("all") { // Put all options into the user option map *opts = UserOptions(make(map[UserOption]bool)) for _, opt := range ListUserOptions() { (*opts)[opt] = true } return nil } // then try to decode into user map var rawOpts map[UserOption]bool err = edn.Unmarshal(bs, &rawOpts) *opts = UserOptions(rawOpts) return err } // This example shows how one can implement enums and sets, and how to support // multiple different forms for a specific value type. The set implemented here // supports the notation `:all` for all values. func main() { inputs := []string{ "#{:show-email :notifications}", "#{:notifications :show-email :remember-me}", ":all", "#{:doot-doot}", ":none", "#{} ;; no options", } for _, input := range inputs { var opts UserOptions err := edn.UnmarshalString(input, &opts) if err != nil { fmt.Println(err) // Do proper error handling here if something fails continue } // Cannot print out a map, as its ordering is nondeterministic. fmt.Printf("show email? %t, notifications? %t, daily email? %t, remember me? %t\n", opts[ShowEmail], opts[Notifications], opts[DailyEmail], opts[RememberMe]) } }
Output: show email? true, notifications? true, daily email? false, remember me? false show email? true, notifications? true, daily email? false, remember me? true show email? true, notifications? true, daily email? true, remember me? true Unknown user option :doot-doot edn: cannot unmarshal keyword into Go value of type map[edn_test.UserOption]bool show email? false, notifications? false, daily email? false, remember me? false
Example (PolymorphicTags) ¶
This example shows how to read and write basic EDN tags, and how this can be utilised: In contrast to encoding/json, you can read in data where you only know that the input satisfies some sort of interface, provided the value is tagged.
package main import ( "fmt" "strings" "olympos.io/encoding/edn" ) type Notifiable interface { Notify() } type User struct { Username string } func (u User) MarshalEDN() ([]byte, error) { return edn.Marshal(edn.Tag{"myapp/user", u.Username}) } func (u *User) Notify() { fmt.Printf("Notified user %s.\n", u.Username) } type Group struct { GroupID int } func (g Group) MarshalEDN() ([]byte, error) { return edn.Marshal(edn.Tag{"myapp/group", g.GroupID}) } func (g *Group) Notify() { fmt.Printf("Notified group with id %d.\n", g.GroupID) } var notifyTagMap edn.TagMap // We use a tagMap to avoid adding these values to the entire system. func init() { err := notifyTagMap.AddTagFn("myapp/user", func(s string) (*User, error) { return &User{s}, nil }) if err != nil { panic(err) } err = notifyTagMap.AddTagFn("myapp/group", func(id int) (*Group, error) { return &Group{id}, nil }) if err != nil { panic(err) } } // This example shows how to read and write basic EDN tags, and how this can be // utilised: In contrast to encoding/json, you can read in data where you only // know that the input satisfies some sort of interface, provided the value is // tagged. func main() { input := `[#myapp/user "eugeness" #myapp/group 10 #myapp/user "jeannikl" #myapp/user "jeremiah" #myapp/group 100]` rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) dec.UseTagMap(¬ifyTagMap) var toNotify []Notifiable err := dec.Decode(&toNotify) if err != nil { panic(err) } for _, notify := range toNotify { notify.Notify() } // Print out the values as well out, err := edn.Marshal(toNotify) if err != nil { panic(err) } fmt.Println(string(out)) }
Output: Notified user eugeness. Notified group with id 10. Notified user jeannikl. Notified user jeremiah. Notified group with id 100. [#myapp/user"eugeness" #myapp/group 10 #myapp/user"jeannikl" #myapp/user"jeremiah" #myapp/group 100]
Example (Streaming) ¶
This example shows how one can do streaming with the decoder, and how to properly know when the stream has no elements left.
package main import ( "fmt" "io" "strings" "olympos.io/encoding/edn" ) // Typically, you'd also include timestamps here. Imagine that they are here. type LogEntry struct { Level edn.Keyword Message string `edn:"msg"` Environment string `edn:"env"` Service string } // This example shows how one can do streaming with the decoder, and how to // properly know when the stream has no elements left. func main() { const input = ` {:level :debug :msg "1 < 2 ? true" :env "dev" :service "comparer"} {:level :warn :msg "slow response time from 127.0.1.39" :env "prod" :service "worker 10"} {:level :warn :msg "worker 8 has been unavailable for 30s" :env "prod" :service "gateway"} {:level :info :msg "new processing request: what.png" :env "prod" :service "gateway"} {:level :debug :msg "1 < nil? error" :env "dev" :service "comparer"} {:level :warn :msg "comparison failed: 1 < nil" :env "dev" :service "comparer"} {:level :info :msg "received new processing request: what.png" :env "prod" :service "worker 3"} {:level :warn :msg "bad configuration value :timeout, using 3h" :env "staging" :service "worker 3"} ` rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) var err error for { var entry LogEntry err = dec.Decode(&entry) if err != nil { break } if entry.Level == edn.Keyword("warn") && entry.Environment != "dev" { fmt.Println(entry.Message) } } if err != nil && err != io.EOF { // Something bad happened to our reader fmt.Println(err) return } // If err == io.EOF then we've reached end of stream fmt.Println("End of stream!") }
Output: slow response time from 127.0.1.39 worker 8 has been unavailable for 30s bad configuration value :timeout, using 3h End of stream!
Index ¶
- Variables
- func AddTagFn(tagname string, fn interface{}) error
- func AddTagStruct(tagname string, val interface{}) error
- func Compact(dst *bytes.Buffer, src []byte) error
- func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error
- func IndentStream(dst io.Writer, src io.Reader, prefix, indent string) error
- func Marshal(v interface{}) ([]byte, error)
- func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
- func MarshalPPrint(v interface{}, opts *PPrintOpts) ([]byte, error)
- func MustAddTagFn(tagname string, fn interface{})
- func PPrint(dst *bytes.Buffer, src []byte, opt *PPrintOpts) error
- func PPrintStream(dst io.Writer, src io.Reader, opt *PPrintOpts) error
- func Unmarshal(data []byte, v interface{}) error
- func UnmarshalString(data string, v interface{}) error
- func UseJSONAsFallback(val bool)
- type Decoder
- func (d *Decoder) AddTagFn(tagname string, fn interface{}) error
- func (d *Decoder) AddTagStruct(tagname string, example interface{}) error
- func (d *Decoder) Buffered() *bufio.Reader
- func (d *Decoder) Decode(val interface{}) (err error)
- func (d *Decoder) DisallowUnknownFields()
- func (d *Decoder) MustAddTagFn(tagname string, fn interface{})
- func (d *Decoder) UseMathContext(mc MathContext)
- func (d *Decoder) UseTagMap(tm *TagMap)
- type Encoder
- type InvalidUnmarshalError
- type Keyword
- type Marshaler
- type MarshalerError
- type MathContext
- type PPrintOpts
- type RawMessage
- type Rune
- type Symbol
- type SyntaxError
- type Tag
- type TagMap
- type UnhashableError
- type UnknownFieldError
- type UnknownTagError
- type UnmarshalTypeError
- type Unmarshaler
- type UnsupportedTypeError
- type UnsupportedValueError
Examples ¶
- Package (ArbitraryKeys)
- Package (EnumsAndSets)
- Package (PolymorphicTags)
- Package (Streaming)
- Decoder.AddTagFn (Complex)
- Decoder.AddTagFn (Duration)
- Decoder.AddTagStruct (IntoInterface)
- Decoder.AddTagStruct (Nested)
- Decoder.UseMathContext
- Keyword
- Marshal (Set)
- Marshal (SetOverride)
- MathContext (Global)
- Rune
- Tag (Reading)
- Unmarshal (Set)
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotFunc = errors.New("Value is not a function") ErrMismatchArities = errors.New("Function does not have single argument in, two argument out") ErrNotConcrete = errors.New("Value is not a concrete non-function type") ErrTagOverwritten = errors.New("Previous tag implementation was overwritten") )
var GlobalMathContext = MathContext{ Mode: big.ToNearestEven, Precision: 192, }
The GlobalMathContext is the global MathContext. It is used if no other context is provided. See MathContext for example usage.
Functions ¶
func AddTagFn ¶
AddTagFn adds fn as a converter function for tagname tags to the global TagMap. fn must have the signature func(T) (U, error), where T is the expected input type and U is the output type. See Decoder.AddTagFn for examples.
func AddTagStruct ¶
AddTagStructs adds the struct as a matching struct for tagname tags to the global TagMap. val can not be a channel, function, interface or an unsafe pointer. See Decoder.AddTagStruct for examples.
func Compact ¶
Compact appends to dst a compacted form of the EDN-encoded src. It does not remove discard values.
func Indent ¶
Indent writes to dst an indented form of the EDN-encoded src. Each EDN collection begins on a new, indented line beginning with prefix followed by one or more copies of indent according to the indentation nesting. The data written to dst does not begin with the prefix nor any indentation, and has no trailing newline, to make it easier to embed inside other formatted EDN data.
Indent filters away whitespace, including comments and discards.
func IndentStream ¶
IndentStream is an implementation of PPrint for generic readers and writers
func Marshal ¶
Marshal returns the EDN encoding of v.
Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalEDN method to produce EDN. The nil pointer exception is not strictly necessary but mimics a similar, necessary exception in the behavior of UnmarshalEDN.
Otherwise, Marshal uses the following type-dependent default encodings:
Boolean values encode as EDN booleans.
Integers encode as EDN integers.
Floating point values encode as EDN floats.
String values encode as EDN strings coerced to valid UTF-8, replacing invalid bytes with the Unicode replacement rune. The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" to keep some browsers from misinterpreting EDN output as HTML. Ampersand "&" is also escaped to "\u0026" for the same reason.
Array and slice values encode as EDN arrays, except that []byte encodes as a base64-encoded string, and a nil slice encodes as the nil EDN value.
Struct values encode as EDN maps. Each exported struct field becomes a member of the map unless
- the field's tag is "-", or
- the field is empty and its tag specifies the "omitempty" option.
The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. The map's default key is the struct field name as a keyword, but can be specified in the struct field's tag value. The "edn" key in the struct field's tag value is the key name, followed by an optional comma and options. Examples:
// Field is ignored by this package. Field int `edn:"-"` // Field appears in EDN as key :my-name. Field int `edn:"myName"` // Field appears in EDN as key :my-name and // the field is omitted from the object if its value is empty, // as defined above. Field int `edn:"my-name,omitempty"` // Field appears in EDN as key :field (the default), but // the field is skipped if empty. // Note the leading comma. Field int `edn:",omitempty"`
The "str", "key" and "sym" options signals that a field name should be written as a string, keyword or symbol, respectively. If none are specified, then the default behaviour is to emit them as keywords. Examples:
// Default behaviour: field name will be encoded as :foo Foo int // Encode Foo as string with name "string-foo" Foo int `edn:"string-foo,str"` // Encode Foo as symbol with name sym-foo Foo int `edn:"sym-foo,sym"`
Anonymous struct fields are usually marshaled as if their inner exported fields were fields in the outer struct, subject to the usual Go visibility rules amended as described in the next paragraph. An anonymous struct field with a name given in its EDN tag is treated as having that name, rather than being anonymous. An anonymous struct field of interface type is treated the same as having that type as its name, rather than being anonymous.
The Go visibility rules for struct fields are amended for EDN when deciding which field to marshal or unmarshal. If there are multiple fields at the same level, and that level is the least nested (and would therefore be the nesting level selected by the usual Go rules), the following extra rules apply:
1) Of those fields, if any are EDN-tagged, only tagged fields are considered, even if there are multiple untagged fields that would otherwise conflict. 2) If there is exactly one field (tagged or not according to the first rule), that is selected. 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
To force ignoring of an anonymous struct field in both current and earlier versions, give the field a EDN tag of "-".
Map values usually encode as EDN maps. There are no limitations on the keys or values -- as long as they can be encoded to EDN, anything goes. Map values will be encoded as sets if their value type is either a bool or a struct with no fields.
If you want to ensure that a value is encoded as a map, you can specify that as follows:
// Encode Foo as a map, instead of the default set Foo map[int]bool `edn:",map"`
Arrays and slices are encoded as vectors by default. As with maps and sets, you can specify that a field should be encoded as a list instead, by using the option "list":
// Encode Foo as a list, instead of the default vector Foo []int `edn:",list"`
Pointer values encode as the value pointed to. A nil pointer encodes as the nil EDN object.
Interface values encode as the value contained in the interface. A nil interface value encodes as the nil EDN value.
Channel, complex, and function values cannot be encoded in EDN. Attempting to encode such a value causes Marshal to return an UnsupportedTypeError.
EDN cannot represent cyclic data structures and Marshal does not handle them. Passing cyclic structures to Marshal will result in an infinite recursion.
Example (Set) ¶
package main import ( "fmt" "olympos.io/encoding/edn" ) func main() { // values of type map[T]bool and map[T]struct{} are encoded as EDN sets by // default val := map[int]bool{42: true} bs, _ := edn.Marshal(val) fmt.Println(string(bs)) // => #{42} val2 := map[string]struct{}{"hiccup": {}} bs, _ = edn.Marshal(val2) fmt.Println(string(bs)) // => #{"hiccup"} }
Output: #{42} #{"hiccup"}
Example (SetOverride) ¶
package main import ( "fmt" "olympos.io/encoding/edn" ) func main() { // You can specify that map[T]bool/struct{} are printed as EDN maps by using // the `map` keyword in the EDN struct tag: type Value struct { BoolMap map[int]bool `edn:"bool-map,map,omitempty"` StructMap map[string]struct{} `edn:"struct-map,map,omitempty"` } var val Value val.BoolMap = map[int]bool{2: false} bs, _ := edn.Marshal(val) fmt.Println(string(bs)) // => {:bool-map{2 false}} val.BoolMap = nil val.StructMap = map[string]struct{}{"foo": {}} bs, _ = edn.Marshal(val) fmt.Println(string(bs)) // => {:struct-map{"foo"{}}} }
Output: {:bool-map{2 false}} {:struct-map{"foo"{}}}
func MarshalIndent ¶
MarshalIndent is like Marshal but applies Indent to format the output.
func MarshalPPrint ¶
func MarshalPPrint(v interface{}, opts *PPrintOpts) ([]byte, error)
MarshalPPrint is like Marshal but applies PPrint to format the output.
func MustAddTagFn ¶
func MustAddTagFn(tagname string, fn interface{})
MustAddTagFn adds fn as a converter function for tagname tags to the global TagMap like AddTagFn, except this function panics if the tag could not be added.
func PPrint ¶
func PPrint(dst *bytes.Buffer, src []byte, opt *PPrintOpts) error
PPrint writes to dst an indented form of the EDN-encoded src. This implementation attempts to write idiomatic/readable EDN values, in a fashion close to (but not quite equal to) clojure.pprint/pprint.
PPrint filters away whitespace, including comments and discards.
func PPrintStream ¶
PPrintStream is an implementation of PPrint for generic readers and writers
func Unmarshal ¶
Unmarshal parses the EDN-encoded data and stores the result in the value pointed to by v.
Unmarshal uses the inverse of the encodings that Marshal uses, allocating maps, slices, and pointers as necessary, with the following additional rules:
First, if the value to store the result into implements edn.Unmarshaler, it is called.
If the value is tagged and the tag is known, the EDN value is translated into the input of the tag convert function. If no error happens during converting, the result of the conversion is then coerced into v if possible.
To unmarshal EDN into a pointer, Unmarshal first handles the case of the EDN being the EDN literal nil. In that case, Unmarshal sets the pointer to nil. Otherwise, Unmarshal unmarshals the EDN into the value pointed at by the pointer. If the pointer is nil, Unmarshal allocates a new value for it to point to.
To unmarshal EDN into a struct, Unmarshal matches incoming object keys to the keys used by Marshal (either the struct field name or its tag), preferring an exact match but also accepting a case-insensitive match.
To unmarshal EDN into an interface value, Unmarshal stores one of these in the interface value:
bool, for EDN booleans float64, for EDN floats int64, for EDN integers int32, for EDN characters string, for EDN strings []interface{}, for EDN vectors and lists map[interface{}]interface{}, for EDN maps map[interface{}]bool, for EDN sets nil for EDN nil edn.Tag for unknown EDN tagged elements T for known EDN tagged elements, where T is the result of the converter function
To unmarshal an EDN vector/list into a slice, Unmarshal resets the slice to nil and then appends each element to the slice.
To unmarshal an EDN map into a Go map, Unmarshal replaces the map with an empty map and then adds key-value pairs from the object to the map.
If a EDN value is not appropriate for a given target type, or if a EDN number overflows the target type, Unmarshal skips that field and completes the unmarshalling as best it can. If no more serious errors are encountered, Unmarshal returns an UnmarshalTypeError describing the earliest such error.
The EDN nil value unmarshals into an interface, map, pointer, or slice by setting that Go value to nil.
When unmarshaling strings, invalid UTF-8 or invalid UTF-16 surrogate pairs are not treated as an error. Instead, they are replaced by the Unicode replacement character U+FFFD.
Example (Set) ¶
package main import ( "fmt" "olympos.io/encoding/edn" ) func main() { // map[T]bool is considered as sets as well as maps var val map[int]bool edn.UnmarshalString("#{1 -5 42}", &val) fmt.Println(val[42], val[123]) // => true false edn.UnmarshalString("{1 false 2 true}", &val) fmt.Println(val[1], val[2]) // => false true }
Output: true false false true
func UnmarshalString ¶
UnmarshalString works like Unmarshal, but accepts a string as input instead of a byte slice.
func UseJSONAsFallback ¶
func UseJSONAsFallback(val bool)
UseJSONAsFallback can be set to true to let go-edn parse structs with information from the `json` tag for encoding and decoding type fields if not the `edn` tag field is set. This is not threadsafe: Encoding and decoding happening while this is called may return results that mix json and non-json tag reading. Preferably you call this in an init() function to ensure it is either set or unset.
Types ¶
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
A Decoder reads and decodes EDN objects from an input stream.
func NewDecoder ¶
NewDecoder returns a new decoder that reads from r.
The decoder introduces its own buffering and may read data from r beyond the EDN values requested.
func (*Decoder) AddTagFn ¶
AddTagFn adds a tag function to the decoder's TagMap. Note that TagMaps are mutable: If Decoder A and B share TagMap, then adding a tag function to one may modify both.
Example (Complex) ¶
package main import ( "fmt" "strings" "olympos.io/encoding/edn" ) func main() { input := `#complex [14.5 15.5]` rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) intoComplex := func(v [2]float64) (complex128, error) { return complex(v[0], v[1]), nil } err := dec.AddTagFn("complex", intoComplex) if err != nil { panic(err) } var cmplx complex128 err = dec.Decode(&cmplx) if err != nil { panic(err) } fmt.Println(cmplx) }
Output: (14.5+15.5i)
Example (Duration) ¶
package main import ( "fmt" "strings" "time" "olympos.io/encoding/edn" ) func main() { input := `#com.myapp/duration "2h30m"` rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) dec.AddTagFn("com.myapp/duration", time.ParseDuration) var d time.Duration dec.Decode(&d) fmt.Println(d) input = `#com.myapp/duration "1moment"` rdr = strings.NewReader(input) dec = edn.NewDecoder(rdr) dec.AddTagFn("com.myapp/duration", time.ParseDuration) err := dec.Decode(&d) if err != nil { fmt.Println(err) } }
Output: 2h30m0s time: unknown unit moment in duration 1moment
func (*Decoder) AddTagStruct ¶
AddTagStruct adds a tag struct to the decoder's TagMap. Note that TagMaps are mutable: If Decoder A and B share TagMap, then adding a tag struct to one may modify both.
Example (IntoInterface) ¶
package main import ( "fmt" "strings" "olympos.io/encoding/edn" ) type Length interface { ToMetres() float64 } type Foot float64 func (f Foot) ToMetres() float64 { return float64(f) * 0.3048 } type Yard float64 func (y Yard) ToMetres() float64 { return float64(y) * 0.9144 } type Metre float64 func (m Metre) ToMetres() float64 { return float64(m) } func main() { // We can insert things into interfaces with tagged literals. // Let's assume we have // type Length interface { ToMetres() float64 } // and Foot, Yard and Metre which satisfy the Length interface input := `[#foot 14.5, #yard 2, #metre 3.0]` rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) dec.AddTagStruct("foot", Foot(0)) dec.AddTagStruct("yard", Yard(0)) dec.AddTagStruct("metre", Metre(0)) var lengths []Length dec.Decode(&lengths) for _, len := range lengths { fmt.Printf("%.2f\n", len.ToMetres()) } }
Output: 4.42 1.83 3.00
Example (Nested) ¶
package main import ( "fmt" "strings" "olympos.io/encoding/edn" ) func main() { // Tag structs and tag functions can nest arbitrarily. type Node struct { Left *Node Val int Right *Node } // function for finding the total sum of a tree var sumTree func(n Node) int sumTree = func(root Node) (val int) { if root.Left != nil { val += sumTree(*root.Left) } val += root.Val if root.Right != nil { val += sumTree(*root.Right) } return } input := `#node {:left #node {:val 1} :val 2 :right #node {:left #node {:val 5} :val 8 :right #node {:val 12}}}` rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) dec.AddTagStruct("node", Node{}) var node Node dec.Decode(&node) fmt.Println(sumTree(node)) }
Output: 28
func (*Decoder) Buffered ¶
Buffered returns a reader of the data remaining in the Decoder's buffer. The reader is valid until the next call to Decode.
func (*Decoder) Decode ¶
Decode reads the next EDN-encoded value from its input and stores it in the value pointed to by v.
See the documentation for Unmarshal for details about the conversion of EDN into a Go value.
func (*Decoder) DisallowUnknownFields ¶
func (d *Decoder) DisallowUnknownFields()
DisallowUnknownFields causes the Decoder to return an error when the destination is a struct and the input contains keys which do not match any non-ignored, exported fields in the destination.
func (*Decoder) MustAddTagFn ¶
MustAddTagFn adds a tag function to the decoder's TagMap like AddTagFn, except this function also panics if the tag could not be added.
func (*Decoder) UseMathContext ¶
func (d *Decoder) UseMathContext(mc MathContext)
UseMathContext sets the given math context as default math context for this decoder.
Example ¶
package main import ( "fmt" "math/big" "strings" "olympos.io/encoding/edn" ) func main() { input := "3.14159265358979323846264338327950288419716939937510M" rdr := strings.NewReader(input) dec := edn.NewDecoder(rdr) mathContext := edn.GlobalMathContext // use global math context (does nothing) dec.UseMathContext(mathContext) var val *big.Float dec.Decode(&val) fmt.Printf("%.50f\n", val) // reread with smaller precision and rounding towards zero rdr = strings.NewReader(input) dec = edn.NewDecoder(rdr) mathContext.Precision = 30 mathContext.Mode = big.ToZero dec.UseMathContext(mathContext) dec.Decode(&val) fmt.Printf("%.50f\n", val) }
Output: 3.14159265358979323846264338327950288419716939937510 3.14159265160560607910156250000000000000000000000000
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
An Encoder writes EDN values to an output stream.
func NewEncoder ¶
NewEncoder returns a new encoder that writes to w.
func (*Encoder) Encode ¶
Encode writes the EDN encoding of v to the stream, followed by a newline character.
See the documentation for Marshal for details about the conversion of Go values to EDN.
func (*Encoder) EncodeIndent ¶
EncodeIndent writes the indented EDN encoding of v to the stream, followed by a newline character.
See the documentation for MarshalIndent for details about the conversion of Go values to EDN.
func (*Encoder) EncodePPrint ¶
func (e *Encoder) EncodePPrint(v interface{}, opts *PPrintOpts) error
EncodePPrint writes the pretty-printed EDN encoding of v to the stream, followed by a newline character.
See the documentation for MarshalPPrint for details about the conversion of Go values to EDN.
type InvalidUnmarshalError ¶
An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. (The argument to Unmarshal must be a non-nil pointer.)
func (*InvalidUnmarshalError) Error ¶
func (e *InvalidUnmarshalError) Error() string
type Keyword ¶
type Keyword string
A Keyword is an EDN keyword without : prepended in front.
Example ¶
package main import ( "fmt" "olympos.io/encoding/edn" ) func main() { const Friday = edn.Keyword("friday") fmt.Println(Friday) input := `:friday` var weekday edn.Keyword edn.UnmarshalString(input, &weekday) if weekday == Friday { fmt.Println("It is friday!") } }
Output: :friday It is friday!
func (Keyword) MarshalEDN ¶
type Marshaler ¶
Marshaler is the interface implemented by objects that can marshal themselves into valid EDN.
type MarshalerError ¶
A MarshalerError is returned by Marshal when encoding a type with a MarshalEDN function fails.
func (*MarshalerError) Error ¶
func (e *MarshalerError) Error() string
type MathContext ¶
type MathContext struct { Precision uint Mode big.RoundingMode }
A MathContext specifies the precision and rounding mode for `math/big.Float`s when decoding.
Example (Global) ¶
package main import ( "fmt" "math/big" "olympos.io/encoding/edn" ) func main() { input := "1.12345678901234567890123456789012345678901234567890M" var val *big.Float edn.UnmarshalString(input, &val) fmt.Printf("%.50f\n", val) // override default precision mathContext := edn.GlobalMathContext edn.GlobalMathContext.Precision = 30 edn.UnmarshalString(input, &val) fmt.Printf("%.50f\n", val) // revert it back to original values edn.GlobalMathContext = mathContext }
Output: 1.12345678901234567890123456789012345678901234567890 1.12345678918063640594482421875000000000000000000000
type PPrintOpts ¶
PPrintOpts is a configuration map for PPrint. The values in this struct has no effect as of now.
type RawMessage ¶
type RawMessage []byte
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.
func (RawMessage) MarshalEDN ¶
func (m RawMessage) MarshalEDN() ([]byte, error)
MarshalEDN returns m as the EDN encoding of m.
func (*RawMessage) UnmarshalEDN ¶
func (m *RawMessage) UnmarshalEDN(data []byte) error
UnmarshalEDN sets *m to a copy of data.
type Rune ¶
type Rune rune
A Rune type is a wrapper for a rune. It can be used to encode runes as characters instead of int32 values.
Example ¶
package main import ( "fmt" "olympos.io/encoding/edn" ) func main() { runeSlice := []edn.Rune{'a', 'b', 'c', ',', ' ', '\n'} bs, _ := edn.Marshal(runeSlice) fmt.Println(string(bs)) }
Output: [\a \b \c \u002c \space \newline]
func (Rune) MarshalEDN ¶
type SyntaxError ¶
type SyntaxError struct { Offset int64 // error occurred after reading Offset bytes // contains filtered or unexported fields }
A SyntaxError is a description of an EDN syntax error.
func (*SyntaxError) Error ¶
func (e *SyntaxError) Error() string
type Tag ¶
type Tag struct { Tagname string Value interface{} }
A Tag is a tagged value. The Tagname represents the name of the tag, and the Value is the value of the element.
Example (Reading) ¶
package main import ( "fmt" "olympos.io/encoding/edn" ) func main() { input := "#unknown ???" var tag edn.Tag edn.UnmarshalString(input, &tag) fmt.Printf("Tag with name %s and value %q of type %T\n", tag.Tagname, tag.Value, tag.Value) }
Output: Tag with name unknown and value "???" of type edn.Symbol
func (Tag) MarshalEDN ¶
func (*Tag) UnmarshalEDN ¶
type TagMap ¶
A TagMap contains mappings from tag literals to functions and structs that is used when decoding.
func (*TagMap) AddTagFn ¶
AddTagFn adds fn as a converter function for tagname tags to this TagMap. fn must have the signature func(T) (U, error), where T is the expected input type and U is the output type. See Decoder.AddTagFn for examples.
func (*TagMap) AddTagStruct ¶
AddTagStructs adds the struct as a matching struct for tagname tags to this TagMap. val can not be a channel, function, interface or an unsafe pointer. See Decoder.AddTagStruct for examples.
func (*TagMap) MustAddTagFn ¶
MustAddTagFn adds fn as a converter function for tagname tags to this TagMap like AddTagFn, except this function panics if the tag could not be added.
type UnhashableError ¶
type UnhashableError struct {
Position int64
}
UnhashableError is an error which occurs when the decoder attempted to assign an unhashable key to a map or set. The position close to where value was found is provided to help debugging.
func (*UnhashableError) Error ¶
func (e *UnhashableError) Error() string
type UnknownFieldError ¶
type UnknownFieldError struct { Field string // the field name Type reflect.Type // type of Go struct with a missing field }
func (*UnknownFieldError) Error ¶
func (e *UnknownFieldError) Error() string
type UnknownTagError ¶
type UnknownTagError struct {
// contains filtered or unexported fields
}
func (UnknownTagError) Error ¶
func (ute UnknownTagError) Error() string
type UnmarshalTypeError ¶
type UnmarshalTypeError struct { Value string // description of EDN value - "bool", "array", "number -5" Type reflect.Type // type of Go value it could not be assigned to }
An UnmarshalTypeError describes a EDN value that was not appropriate for a value of a specific Go type.
func (*UnmarshalTypeError) Error ¶
func (e *UnmarshalTypeError) Error() string
type Unmarshaler ¶
Unmarshaler is the interface implemented by objects that can unmarshal an EDN description of themselves. The input can be assumed to be a valid encoding of an EDN value. UnmarshalEDN must copy the EDN data if it wishes to retain the data after returning.
type UnsupportedTypeError ¶
An UnsupportedTypeError is returned by Marshal when attempting to encode an unsupported value type.
func (*UnsupportedTypeError) Error ¶
func (e *UnsupportedTypeError) Error() string
type UnsupportedValueError ¶
An UnsupportedValueError is returned by Marshal when attempting to encode an unsupported value. Examples include the float values NaN and Infinity.
func (*UnsupportedValueError) Error ¶
func (e *UnsupportedValueError) Error() string