diff --git a/api.go b/api.go index 0c8aa79..a3dba54 100644 --- a/api.go +++ b/api.go @@ -18,6 +18,8 @@ package sonic import ( `io` + + `github.com/bytedance/sonic/ast` ) // Config is a combination of sonic/encoder.Options and sonic/decoder.Options @@ -161,3 +163,19 @@ func Unmarshal(buf []byte, val interface{}) error { func UnmarshalString(buf string, val interface{}) error { return ConfigDefault.UnmarshalFromString(buf, val) } + +// Get searches the given path json, +// and returns its representing ast.Node. +// +// Each path arg must be integer or string: +// - Integer means searching current node as array +// - String means searching current node as object +func Get(src []byte, path ...interface{}) (ast.Node, error) { + return GetFromString(string(src), path...) +} + +// GetFromString is same with Get except src is string, +// which can reduce unnecessary memory copy. +func GetFromString(src string, path ...interface{}) (ast.Node, error) { + return ast.NewSearcher(src).GetByPath(path...) +} \ No newline at end of file diff --git a/compat.go b/compat.go index 48a1717..11733ba 100644 --- a/compat.go +++ b/compat.go @@ -38,7 +38,7 @@ func (cfg Config) Froze() API { return api } -func (cfg *frozenConfig) marshalOptions(val interface{}, prefix, indent string) ([]byte, error) { +func (cfg frozenConfig) marshalOptions(val interface{}, prefix, indent string) ([]byte, error) { w := bytes.NewBuffer([]byte{}) enc := json.NewEncoder(w) enc.SetEscapeHTML(cfg.EscapeHTML) @@ -55,7 +55,7 @@ func (cfg *frozenConfig) marshalOptions(val interface{}, prefix, indent string) } // Marshal is implemented by sonic -func (cfg *frozenConfig) Marshal(val interface{}) ([]byte, error) { +func (cfg frozenConfig) Marshal(val interface{}) ([]byte, error) { if !cfg.EscapeHTML { return cfg.marshalOptions(val, "", "") } @@ -63,13 +63,13 @@ func (cfg *frozenConfig) Marshal(val interface{}) ([]byte, error) { } // MarshalToString is implemented by sonic -func (cfg *frozenConfig) MarshalToString(val interface{}) (string, error) { +func (cfg frozenConfig) MarshalToString(val interface{}) (string, error) { out, err := cfg.Marshal(val) return string(out), err } // MarshalIndent is implemented by sonic -func (cfg *frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ([]byte, error) { +func (cfg frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ([]byte, error) { if !cfg.EscapeHTML { return cfg.marshalOptions(val, prefix, indent) } @@ -77,7 +77,7 @@ func (cfg *frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ( } // UnmarshalFromString is implemented by sonic -func (cfg *frozenConfig) UnmarshalFromString(buf string, val interface{}) error { +func (cfg frozenConfig) UnmarshalFromString(buf string, val interface{}) error { r := bytes.NewBufferString(buf) dec := json.NewDecoder(r) if cfg.UseNumber { @@ -90,12 +90,12 @@ func (cfg *frozenConfig) UnmarshalFromString(buf string, val interface{}) error } // Unmarshal is implemented by sonic -func (cfg *frozenConfig) Unmarshal(buf []byte, val interface{}) error { +func (cfg frozenConfig) Unmarshal(buf []byte, val interface{}) error { return cfg.UnmarshalFromString(string(buf), val) } // NewEncoder is implemented by sonic -func (cfg *frozenConfig) NewEncoder(writer io.Writer) Encoder { +func (cfg frozenConfig) NewEncoder(writer io.Writer) Encoder { enc := json.NewEncoder(writer) if !cfg.EscapeHTML { enc.SetEscapeHTML(cfg.EscapeHTML) @@ -104,7 +104,7 @@ func (cfg *frozenConfig) NewEncoder(writer io.Writer) Encoder { } // NewDecoder is implemented by sonic -func (cfg *frozenConfig) NewDecoder(reader io.Reader) Decoder { +func (cfg frozenConfig) NewDecoder(reader io.Reader) Decoder { dec := json.NewDecoder(reader) if cfg.UseNumber { dec.UseNumber() @@ -116,7 +116,7 @@ func (cfg *frozenConfig) NewDecoder(reader io.Reader) Decoder { } // Valid is implemented by sonic -func (cfg *frozenConfig) Valid(data []byte) bool { +func (cfg frozenConfig) Valid(data []byte) bool { return json.Valid(data) } diff --git a/compat_test.go b/compat_test.go index 697bcbe..1ce0429 100644 --- a/compat_test.go +++ b/compat_test.go @@ -40,3 +40,18 @@ func TestPretouch(t *testing.T) { } } +func TestGet(t *testing.T) { + var data = `{"a":"b"}` + r, err := GetFromString(data, "a") + if err != nil { + t.Fatal(err) + } + v, err := r.String() + if err != nil { + t.Fatal(err) + } + if v != "b" { + t.Fatal(v) + } +} + diff --git a/sonic.go b/sonic.go index 99b1dad..829e461 100644 --- a/sonic.go +++ b/sonic.go @@ -23,7 +23,6 @@ import ( `io` `reflect` - `github.com/bytedance/sonic/ast` `github.com/bytedance/sonic/decoder` `github.com/bytedance/sonic/encoder` `github.com/bytedance/sonic/option` @@ -99,23 +98,23 @@ func (cfg Config) Froze() API { } // Marshal is implemented by sonic -func (cfg *frozenConfig) Marshal(val interface{}) ([]byte, error) { +func (cfg frozenConfig) Marshal(val interface{}) ([]byte, error) { return encoder.Encode(val, cfg.encoderOpts) } // MarshalToString is implemented by sonic -func (cfg *frozenConfig) MarshalToString(val interface{}) (string, error) { +func (cfg frozenConfig) MarshalToString(val interface{}) (string, error) { buf, err := encoder.Encode(val, cfg.encoderOpts) return rt.Mem2Str(buf), err } // MarshalIndent is implemented by sonic -func (cfg *frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ([]byte, error) { +func (cfg frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ([]byte, error) { return encoder.EncodeIndented(val, prefix, indent, cfg.encoderOpts) } // UnmarshalFromString is implemented by sonic -func (cfg *frozenConfig) UnmarshalFromString(buf string, val interface{}) error { +func (cfg frozenConfig) UnmarshalFromString(buf string, val interface{}) error { dec := decoder.NewDecoder(buf) dec.SetOptions(cfg.decoderOpts) err := dec.Decode(val) @@ -129,26 +128,26 @@ func (cfg *frozenConfig) UnmarshalFromString(buf string, val interface{}) error } // Unmarshal is implemented by sonic -func (cfg *frozenConfig) Unmarshal(buf []byte, val interface{}) error { +func (cfg frozenConfig) Unmarshal(buf []byte, val interface{}) error { return cfg.UnmarshalFromString(string(buf), val) } // NewEncoder is implemented by sonic -func (cfg *frozenConfig) NewEncoder(writer io.Writer) Encoder { +func (cfg frozenConfig) NewEncoder(writer io.Writer) Encoder { enc := encoder.NewStreamEncoder(writer) enc.Opts = cfg.encoderOpts return enc } // NewDecoder is implemented by sonic -func (cfg *frozenConfig) NewDecoder(reader io.Reader) Decoder { +func (cfg frozenConfig) NewDecoder(reader io.Reader) Decoder { dec := decoder.NewStreamDecoder(reader) dec.SetOptions(cfg.decoderOpts) return dec } // Valid is implemented by sonic -func (cfg *frozenConfig) Valid(data []byte) bool { +func (cfg frozenConfig) Valid(data []byte) bool { ok, _ := encoder.Valid(data) return ok } @@ -179,19 +178,3 @@ func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { } return nil } - -// Get searches the given path json, -// and returns its representing ast.Node. -// -// Each path arg must be integer or string: -// - Integer means searching current node as array -// - String means searching current node as object -func Get(src []byte, path ...interface{}) (ast.Node, error) { - return GetFromString(string(src), path...) -} - -// GetFromString is same with Get except src is string, -// which can reduce unnecessary memory copy. -func GetFromString(src string, path ...interface{}) (ast.Node, error) { - return ast.NewSearcher(src).GetByPath(path...) -} \ No newline at end of file