├── template ├── img │ ├── ribbon.png │ ├── tip.png │ ├── geek.gif │ ├── geek.png │ ├── grass.png │ ├── logo.png │ ├── moon.jpg │ ├── olaf.png │ ├── phone.jpg │ ├── batman.png │ ├── bg │ │ ├── black.jpg │ │ ├── blue.jpg │ │ ├── gray.jpg │ │ ├── green.jpg │ │ ├── pink.jpg │ │ ├── white.jpg │ │ ├── orange.jpg │ │ ├── purple.jpg │ │ └── yellow.jpg │ ├── dataflow.png │ ├── design.png │ ├── einstein.png │ ├── friday.gif │ ├── lovelace.jpg │ ├── pencils.jpg │ ├── quotes.jpg │ ├── snowman.gif │ ├── thanks.jpg │ ├── contact-1.png │ ├── contact-2.png │ ├── developer.jpg │ ├── headphones.jpg │ ├── questions2.png │ ├── spotlight.png │ ├── profile │ │ ├── abby.jpg │ │ ├── berry.jpg │ │ ├── ronny.jpg │ │ └── wendy.jpg │ ├── questions-1.png │ ├── questions-2.png │ ├── questions-3.png │ └── questions-4.png ├── src │ └── go │ │ └── server.go └── md │ ├── announcement │ └── PITCHME.md │ ├── quotation │ └── PITCHME.md │ ├── about │ └── PITCHME.md │ ├── sidebox │ └── PITCHME.md │ ├── sidebar │ └── PITCHME.md │ ├── image │ └── PITCHME.md │ ├── header-footer │ └── PITCHME.md │ ├── list-content │ └── PITCHME.md │ ├── code-presenting │ └── PITCHME.md │ ├── split-screen │ └── PITCHME.md │ └── wrap-up │ └── PITCHME.md ├── cmd ├── example.cbor ├── example.coll ├── example.json ├── sort.sh ├── non1ql.go ├── Makefile ├── n1ql.go ├── transforms.sh ├── mprof.sh ├── README.md └── cmd_test.go ├── docs ├── collate.pdf ├── transforms.png ├── transforms.dot ├── collate-perf-20142107 ├── gettingstarted.md └── references ├── .gitignore ├── testdata ├── code.cbor.gz ├── code.json.gz ├── code.collate.gz ├── collate │ ├── sortorder │ ├── sortorder.ref │ ├── objects │ ├── objects.ref │ ├── arrays │ ├── numbers │ ├── numbers.ref │ ├── arrays.ref │ ├── strings │ ├── strings.ref │ ├── basics │ └── basics.ref ├── smartnum ├── scan_invalid ├── map ├── items ├── typical_pointers ├── scan_valid ├── pallValueIndent ├── typical.json └── allValueIndent ├── AUTHORS ├── precision_test.go ├── bench_test.go ├── buffpool.go ├── Makefile ├── .travis.yml ├── json_test.go ├── sortedkeys_test.go ├── collate_string.go ├── LICENSE.md ├── collate_string_test.go ├── bignum_test.go ├── cbor_appendix_a_test.go ├── keyspool.go ├── PITCHME.yaml ├── kvpool.go ├── RELEASE.md ├── doc.go ├── clone_cbor_test.go ├── json.go ├── json_string.go ├── collate_json.go ├── collate_value.go ├── collate.go ├── json_cbor_test.go ├── json_collate_test.go ├── value_collate.go ├── collate_cbor.go ├── cbor_collate_test.go ├── json_scanner.go ├── json_value.go ├── value_json.go ├── lookup_value.go ├── jptr_test.go ├── json_cbor.go ├── value_test.go ├── value_collate_test.go ├── json_collate.go ├── example_test.go ├── util_test.go ├── collate_test.go ├── jptr.go ├── cbor_test.go ├── lookup_cbor.go └── bench └── msgpack_test.go /template/img/ribbon.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cmd/example.cbor: -------------------------------------------------------------------------------- 1 | khello world -------------------------------------------------------------------------------- /cmd/example.coll: -------------------------------------------------------------------------------- 1 | Zhello world -------------------------------------------------------------------------------- /cmd/example.json: -------------------------------------------------------------------------------- 1 | "hello world" 2 | -------------------------------------------------------------------------------- /docs/collate.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/docs/collate.pdf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | .vimsession 4 | cmd/gson 5 | cmd/gsonn1ql 6 | cmd/cmd 7 | -------------------------------------------------------------------------------- /docs/transforms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/docs/transforms.png -------------------------------------------------------------------------------- /template/img/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/tip.png -------------------------------------------------------------------------------- /template/img/geek.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/geek.gif -------------------------------------------------------------------------------- /template/img/geek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/geek.png -------------------------------------------------------------------------------- /template/img/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/grass.png -------------------------------------------------------------------------------- /template/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/logo.png -------------------------------------------------------------------------------- /template/img/moon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/moon.jpg -------------------------------------------------------------------------------- /template/img/olaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/olaf.png -------------------------------------------------------------------------------- /template/img/phone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/phone.jpg -------------------------------------------------------------------------------- /testdata/code.cbor.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/testdata/code.cbor.gz -------------------------------------------------------------------------------- /testdata/code.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/testdata/code.json.gz -------------------------------------------------------------------------------- /template/img/batman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/batman.png -------------------------------------------------------------------------------- /template/img/bg/black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/black.jpg -------------------------------------------------------------------------------- /template/img/bg/blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/blue.jpg -------------------------------------------------------------------------------- /template/img/bg/gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/gray.jpg -------------------------------------------------------------------------------- /template/img/bg/green.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/green.jpg -------------------------------------------------------------------------------- /template/img/bg/pink.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/pink.jpg -------------------------------------------------------------------------------- /template/img/bg/white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/white.jpg -------------------------------------------------------------------------------- /template/img/dataflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/dataflow.png -------------------------------------------------------------------------------- /template/img/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/design.png -------------------------------------------------------------------------------- /template/img/einstein.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/einstein.png -------------------------------------------------------------------------------- /template/img/friday.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/friday.gif -------------------------------------------------------------------------------- /template/img/lovelace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/lovelace.jpg -------------------------------------------------------------------------------- /template/img/pencils.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/pencils.jpg -------------------------------------------------------------------------------- /template/img/quotes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/quotes.jpg -------------------------------------------------------------------------------- /template/img/snowman.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/snowman.gif -------------------------------------------------------------------------------- /template/img/thanks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/thanks.jpg -------------------------------------------------------------------------------- /testdata/code.collate.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/testdata/code.collate.gz -------------------------------------------------------------------------------- /template/img/bg/orange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/orange.jpg -------------------------------------------------------------------------------- /template/img/bg/purple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/purple.jpg -------------------------------------------------------------------------------- /template/img/bg/yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/bg/yellow.jpg -------------------------------------------------------------------------------- /template/img/contact-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/contact-1.png -------------------------------------------------------------------------------- /template/img/contact-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/contact-2.png -------------------------------------------------------------------------------- /template/img/developer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/developer.jpg -------------------------------------------------------------------------------- /template/img/headphones.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/headphones.jpg -------------------------------------------------------------------------------- /template/img/questions2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/questions2.png -------------------------------------------------------------------------------- /template/img/spotlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/spotlight.png -------------------------------------------------------------------------------- /template/img/profile/abby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/profile/abby.jpg -------------------------------------------------------------------------------- /template/img/profile/berry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/profile/berry.jpg -------------------------------------------------------------------------------- /template/img/profile/ronny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/profile/ronny.jpg -------------------------------------------------------------------------------- /template/img/profile/wendy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/profile/wendy.jpg -------------------------------------------------------------------------------- /template/img/questions-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/questions-1.png -------------------------------------------------------------------------------- /template/img/questions-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/questions-2.png -------------------------------------------------------------------------------- /template/img/questions-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/questions-3.png -------------------------------------------------------------------------------- /template/img/questions-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bnclabs/gson/HEAD/template/img/questions-4.png -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of gson Authors for copyright purpose. 2 | 3 | prataprc 4 | -------------------------------------------------------------------------------- /precision_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | 5 | func TestPrecisionInt64(t *testing.T) { 6 | } 7 | -------------------------------------------------------------------------------- /cmd/sort.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | go build -o gson; 4 | ./gson -collatesort example1 > out1 5 | go build -tags n1ql -o gsonn1ql 6 | ./gsonn1ql -n1qlsort example1 > out2 7 | rm out1 out2 8 | -------------------------------------------------------------------------------- /cmd/non1ql.go: -------------------------------------------------------------------------------- 1 | // +build !n1ql 2 | 3 | package main 4 | 5 | import "fmt" 6 | 7 | func sortn1ql(filename string) []string { 8 | fmt.Println("not built with n1ql") 9 | return nil 10 | } 11 | -------------------------------------------------------------------------------- /testdata/collate/sortorder: -------------------------------------------------------------------------------- 1 | "hello world" 2 | -10 3 | 10.3 4 | 10 5 | 10.2 6 | 10.1 7 | 10.6 8 | 30 9 | [ 200, 300 ] 10 | false 11 | null 12 | true 13 | { "key1" : 10, "key2" : [ 20, 30 ] } 14 | -------------------------------------------------------------------------------- /testdata/collate/sortorder.ref: -------------------------------------------------------------------------------- 1 | null 2 | false 3 | true 4 | -10 5 | 10 6 | 10.1 7 | 10.2 8 | 10.3 9 | 10.6 10 | 30 11 | "hello world" 12 | [ 200, 300 ] 13 | { "key1" : 10, "key2" : [ 20, 30 ] } 14 | -------------------------------------------------------------------------------- /testdata/collate/objects: -------------------------------------------------------------------------------- 1 | { "python" : "good", "perl" : "ugly", "php" : "bad" } 2 | { "python" : 10, "perl" : 20.2, "haskell" : [1,2] } 3 | { "python" : 10, "perl" : 20.2, "php" : [1,2] } 4 | { "perl" : "cryptic" } 5 | -------------------------------------------------------------------------------- /testdata/collate/objects.ref: -------------------------------------------------------------------------------- 1 | { "perl" : "cryptic" } 2 | { "python" : 10, "perl" : 20.2, "haskell" : [1,2] } 3 | { "python" : 10, "perl" : 20.2, "php" : [1,2] } 4 | { "python" : "good", "perl" : "ugly", "php" : "bad" } 5 | -------------------------------------------------------------------------------- /testdata/smartnum: -------------------------------------------------------------------------------- 1 | { 2 | "min_t" : 1257215120, 3 | "mean_t" : 1287847860, 4 | "max_t" : 1316.028739, 5 | "touches" : 13, 6 | "name" : "common.go", 7 | "kids" : [], 8 | "cl_weight" : 2.83449883449883 9 | } 10 | -------------------------------------------------------------------------------- /cmd/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | go build -o gson 3 | go build -tags n1ql -o gsonn1ql 4 | 5 | test: build 6 | go test -race -test.run=. -test.bench=. -test.benchmem=true 7 | ./sort.sh 8 | ./transforms.sh 9 | 10 | clean: 11 | rm -rf gson gsonn1ql cmd 12 | -------------------------------------------------------------------------------- /testdata/scan_invalid: -------------------------------------------------------------------------------- 1 | nill 2 | trre 3 | fllse 4 | " 5 | " 6 | "汉语 7 | "g-clef: \uD834\uDD1E" 8 | [, 9 | [10 10 | [10 20 11 | {10:10} 12 | {"" 10} 13 | {"10" 10} 14 | {"10": nill} 15 | {"10": null 16 | {"10": null 20 17 | <> 18 | {"X": "foo", "Y"} 19 | [1, 2, 3+] 20 | {"X":12x} 21 | tru 22 | fals 23 | nul 24 | 123e 25 | "hello 26 | [1,2,3 27 | {"key":1 28 | {"key":1 29 | -------------------------------------------------------------------------------- /testdata/map: -------------------------------------------------------------------------------- 1 | { 2 | "Level0": 1, 3 | "Level1b": 2, 4 | "Level1c": 3, 5 | "x": 4, 6 | "Level1a": 5, 7 | "LEVEL1B": 6, 8 | "e": { 9 | "Level1a": 8, 10 | "Level1b": 9, 11 | "Level1c": 10, 12 | "Level1d": 11, 13 | "x": 12 14 | }, 15 | "Loop1": 13, 16 | "Loop2": 14, 17 | "X": 15, 18 | "Y": 16, 19 | "Z": 17 20 | } 21 | -------------------------------------------------------------------------------- /testdata/collate/arrays: -------------------------------------------------------------------------------- 1 | [ 10.2 ] 2 | [ false ] 3 | [ "hello", "world", "fine" ] 4 | [ "hello", "python" ] 5 | [ 20, "hello", "perl" ] 6 | [ "hello", 10.2, "php" ] 7 | [ [20], "hello", null, "go", "next-java" ] 8 | [ { "key1" : 10, "key2" : [ 20, 30 ] } ] 9 | [ 200, 300 ] 10 | [ 20, "hello", null, "go", "next-java" ] 11 | [ null ] 12 | [ true ] 13 | [ 10 ] 14 | [ "hello", "python", "perl" ] 15 | [ "hello", "world" ] 16 | -------------------------------------------------------------------------------- /testdata/collate/numbers: -------------------------------------------------------------------------------- 1 | 0.000000000000000000001 2 | 1 3 | 10 4 | -2 5 | 5 6 | -9223372036854775808 7 | 9223372036854775807 8 | 9223372036854775809 9 | 18446744073709551615 10 | 9007199254740991 11 | 9007199254740992 12 | 9007199254740994 13 | 9007199254740993 14 | 9007199254740995 15 | 9007199254740990 16 | -9007199254740992 17 | 4 18 | -4 19 | 4.1 20 | 0.2 21 | -0.2 22 | -4.1 23 | -100.0000001 24 | 100.0000001 25 | -------------------------------------------------------------------------------- /testdata/collate/numbers.ref: -------------------------------------------------------------------------------- 1 | -9223372036854775808 2 | -9007199254740992 3 | -100.0000001 4 | -4.1 5 | -4 6 | -2 7 | -0.2 8 | 0.000000000000000000001 9 | 0.2 10 | 1 11 | 4 12 | 4.1 13 | 5 14 | 10 15 | 100.0000001 16 | 9007199254740990 17 | 9007199254740991 18 | 9007199254740992 19 | 9007199254740993 20 | 9007199254740994 21 | 9007199254740995 22 | 9223372036854775807 23 | 9223372036854775809 24 | 18446744073709551615 25 | -------------------------------------------------------------------------------- /testdata/items: -------------------------------------------------------------------------------- 1 | [true,[],86178,{"biostatical":-25.54301919647189,"eject":{}},"Porphyra"] 2 | [[],true,86178,{"biostatical":-25.54301919647189,"eject":{}},"Porphyra",{}] 3 | [-45180,{"divisorial":[],"rud":"premeditate"},71527,[],44.34246206868548] 4 | ["Tectospondyli",[],-0.11550336560432584,{"Ada":true,"P":{}},32463] 5 | ["pyosalpingitis",-87.44772337723491,null,{"enterozoan":"lassock","汉语 / 漢語 Hàn":[],"subarctic":{}},-36162] 6 | -------------------------------------------------------------------------------- /testdata/collate/arrays.ref: -------------------------------------------------------------------------------- 1 | [ null ] 2 | [ false ] 3 | [ true ] 4 | [ 10 ] 5 | [ 10.2 ] 6 | [ 20, "hello", null, "go", "next-java" ] 7 | [ 20, "hello", "perl" ] 8 | [ 200, 300 ] 9 | [ "hello", 10.2, "php" ] 10 | [ "hello", "python" ] 11 | [ "hello", "python", "perl" ] 12 | [ "hello", "world" ] 13 | [ "hello", "world", "fine" ] 14 | [ [20], "hello", null, "go", "next-java" ] 15 | [ { "key1" : 10, "key2" : [ 20, 30 ] } ] 16 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "encoding/json" 4 | import "testing" 5 | 6 | func BenchmarkMarshalJson(b *testing.B) { 7 | config := NewDefaultConfig() 8 | config = config.SetNumberKind(FloatNumber).SetSpaceKind(AnsiSpace) 9 | 10 | jsn := config.NewJson(testdataFile("testdata/typical.json")) 11 | _, val := jsn.Tovalue() 12 | b.SetBytes(int64(len(jsn.Bytes()))) 13 | b.ResetTimer() 14 | for i := 0; i < b.N; i++ { 15 | json.Marshal(val) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /testdata/collate/strings: -------------------------------------------------------------------------------- 1 | "These" 2 | "are" 3 | "universal" 4 | "data" 5 | "structures." 6 | "Virtually" 7 | "all" 8 | "modern" 9 | "programming" 10 | "languages" 11 | "support" 12 | "them" 13 | "in" 14 | "one" 15 | "form" 16 | "or" 17 | "another." 18 | "It" 19 | "makes" 20 | "sense" 21 | "that" 22 | "a data" 23 | "format" 24 | "that" 25 | "is" 26 | "interchangeable" 27 | "with" 28 | "languages" 29 | "progrbmming" 30 | "also" 31 | "be" 32 | "based" 33 | "on" 34 | "these" 35 | "structures." 36 | "prográmming" 37 | -------------------------------------------------------------------------------- /testdata/collate/strings.ref: -------------------------------------------------------------------------------- 1 | "It" 2 | "These" 3 | "Virtually" 4 | "a data" 5 | "all" 6 | "also" 7 | "another." 8 | "are" 9 | "based" 10 | "be" 11 | "data" 12 | "form" 13 | "format" 14 | "in" 15 | "interchangeable" 16 | "is" 17 | "languages" 18 | "languages" 19 | "makes" 20 | "modern" 21 | "on" 22 | "one" 23 | "or" 24 | "programming" 25 | "progrbmming" 26 | "prográmming" 27 | "sense" 28 | "structures." 29 | "structures." 30 | "support" 31 | "that" 32 | "that" 33 | "them" 34 | "these" 35 | "universal" 36 | "with" 37 | -------------------------------------------------------------------------------- /buffpool.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | type bufferhead struct { 4 | head *buffernode 5 | } 6 | 7 | func (b *bufferhead) getbuffer(size int) *buffernode { 8 | if node := b.head; node != nil { 9 | node.data = fixbuffer(node.data, int64(size)) 10 | b.head = node.next 11 | return node 12 | } 13 | node := &buffernode{data: fixbuffer(nil, int64(size)), next: nil} 14 | return node 15 | } 16 | 17 | func (b *bufferhead) putbuffer(node *buffernode) { 18 | node.next = b.head 19 | b.head = node 20 | } 21 | 22 | type buffernode struct { 23 | data []byte 24 | next *buffernode 25 | } 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | go build 3 | make -C cmd build 4 | 5 | test: build 6 | make -C cmd test 7 | go test -race -timeout 4000s -test.run=. -test.bench=xxx -test.benchmem=true 8 | go test -timeout 4000s -test.run=xxx -test.bench=. -test.benchmem=true 9 | 10 | heaptest: 11 | go test -gcflags '-m -l' -timeout 4000s -test.run=. -test.bench=. -test.benchmem=true > escapel 2>&1 12 | grep "^\.\/.*escapes to heap" escapel | tee escapelines 13 | grep panic *.go | tee -a escapelines 14 | 15 | coverage: 16 | go test -coverprofile=coverage.out 17 | go tool cover -html=coverage.out 18 | rm -rf coverage.out 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | sudo: false 4 | 5 | go: 6 | - 1.7 7 | - 1.8 8 | 9 | before_install: 10 | - go get github.com/axw/gocov/gocov 11 | - go get github.com/mattn/goveralls 12 | - go get github.com/bmizerany/assert 13 | - go get -d github.com/bnclabs/gson-tools/... 14 | - if ! go get github.com/golang/tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi 15 | 16 | script: 17 | - go get -d ./... 18 | - go get -tags n1ql -d ./... 19 | - make test 20 | - $HOME/gopath/bin/goveralls -service=travis-ci -package github.com/bnclabs/gson 21 | - cd $HOME/gopath/src/github.com/bnclabs/gson-tools 22 | - make check 23 | -------------------------------------------------------------------------------- /template/src/go/server.go: -------------------------------------------------------------------------------- 1 | package funding 2 | 3 | type FundServer struct { 4 | Commands chan interface{} 5 | fund Fund 6 | } 7 | 8 | func NewFundServer(initialBalance int) *FundServer { 9 | server := &FundServer{ 10 | // make() creates builtins like channels 11 | Commands: make(chan interface{}), 12 | fund: NewFund(initialBalance), 13 | } 14 | 15 | // Spawn off the server's main loop immediately 16 | go server.loop() 17 | return server 18 | } 19 | 20 | func (s *FundServer) loop() { 21 | // The built-in "range" clause can iterate 22 | // over channels, amongst other things 23 | for command := range s.Commands { 24 | 25 | // Handle the command 26 | 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /json_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | 5 | func TestJsonEmpty(t *testing.T) { 6 | config := NewDefaultConfig() 7 | cbr := config.NewCbor(make([]byte, 0, 128)) 8 | jsn := config.NewJson(make([]byte, 0, 128)) 9 | clt := config.NewCollate(nil) 10 | 11 | func() { 12 | defer func() { 13 | if r := recover(); r == nil { 14 | t.Errorf("expected panic") 15 | } 16 | }() 17 | jsn.Tovalue() 18 | }() 19 | func() { 20 | defer func() { 21 | if r := recover(); r == nil { 22 | t.Errorf("expected panic") 23 | } 24 | }() 25 | jsn.Tocbor(cbr) 26 | }() 27 | func() { 28 | defer func() { 29 | if r := recover(); r == nil { 30 | t.Errorf("expected panic") 31 | } 32 | }() 33 | jsn.Tocollate(clt) 34 | }() 35 | } 36 | -------------------------------------------------------------------------------- /testdata/typical_pointers: -------------------------------------------------------------------------------- 1 | 2 | /- 3 | /avatar_url 4 | /created_at 5 | /events_url 6 | /followers 7 | /followers_url 8 | /following 9 | /following_url 10 | /friends 11 | /friends/- 12 | /gists_url 13 | /gravatar_id 14 | /html_url 15 | /id 16 | /login 17 | /organizations_url 18 | /projects 19 | /projects/- 20 | /projects/Sherri 21 | /projects/Sherri/- 22 | /projects/Sherri/language 23 | /projects/Sherri/members 24 | /projects/Sherri/members/- 25 | /projects/Sherri/members/0 26 | /projects/Sherri/type 27 | /public_gists 28 | /public_repos 29 | /received_events_url 30 | /repos_url 31 | /site_admin 32 | /starred_url 33 | /subscriptions_url 34 | /team 35 | /team/- 36 | /team/0 37 | /team/1 38 | /team/2 39 | /type 40 | /updated_at 41 | /url 42 | /~0~1some~1path 43 | /汉语 ~1 漢語 44 | -------------------------------------------------------------------------------- /testdata/collate/basics: -------------------------------------------------------------------------------- 1 | 0.000000000000000000001 2 | null 3 | 1 4 | false 5 | 10 6 | -2 7 | 5 8 | true 9 | -4 10 | 4.1 11 | null 12 | 0.2 13 | -0.2 14 | true 15 | -4.1 16 | -100.0000001 17 | null 18 | 100.0000001 19 | true 20 | false 21 | null 22 | "These" 23 | "are" 24 | "universal" 25 | "data" 26 | "structures." 27 | "Virtually" 28 | true 29 | false 30 | null 31 | "all" 32 | "modern" 33 | "programming" 34 | true 35 | false 36 | null 37 | "languages" 38 | "support" 39 | "them" 40 | "in" 41 | "one" 42 | "form" 43 | "or" 44 | "another." 45 | "It" 46 | "makes" 47 | "sense" 48 | "that" 49 | "a data" 50 | "format" 51 | "that" 52 | "is" 53 | "interchangeable" 54 | "with" 55 | "programming" 56 | "languages" 57 | "also" 58 | "be" 59 | "based" 60 | "on" 61 | "these" 62 | true 63 | false 64 | null 65 | "structures." 66 | -------------------------------------------------------------------------------- /testdata/collate/basics.ref: -------------------------------------------------------------------------------- 1 | null 2 | null 3 | null 4 | null 5 | null 6 | null 7 | null 8 | false 9 | false 10 | false 11 | false 12 | false 13 | true 14 | true 15 | true 16 | true 17 | true 18 | true 19 | -100.0000001 20 | -4.1 21 | -4 22 | -2 23 | -0.2 24 | 0.000000000000000000001 25 | 0.2 26 | 1 27 | 4.1 28 | 5 29 | 10 30 | 100.0000001 31 | "It" 32 | "These" 33 | "Virtually" 34 | "a data" 35 | "all" 36 | "also" 37 | "another." 38 | "are" 39 | "based" 40 | "be" 41 | "data" 42 | "form" 43 | "format" 44 | "in" 45 | "interchangeable" 46 | "is" 47 | "languages" 48 | "languages" 49 | "makes" 50 | "modern" 51 | "on" 52 | "one" 53 | "or" 54 | "programming" 55 | "programming" 56 | "sense" 57 | "structures." 58 | "structures." 59 | "support" 60 | "that" 61 | "that" 62 | "them" 63 | "these" 64 | "universal" 65 | "with" 66 | -------------------------------------------------------------------------------- /sortedkeys_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | 5 | // test case to sort/preserv-sort map-keys when transforming from 6 | // one format to another. 7 | func TestSortedkeys(t *testing.T) { 8 | json := []byte(`{"three":10, "two":20, "one":30}`) 9 | config := NewDefaultConfig() 10 | clt := config.NewCollate(make([]byte, 0, 1024)) 11 | jsn := config.NewJson(json) 12 | 13 | ref := "xd>3\x00Zone\x00\x00P>>23-\x00Zthree\x00\x00P>>21-\x00Ztwo\x00\x00P>>22-\x00\x00" 14 | 15 | _, value := jsn.Tovalue() 16 | clt1 := config.NewValue(value).Tocollate(clt) 17 | if out := string(clt1.Bytes()); out != ref { 18 | t.Errorf("expected %s", ref) 19 | t.Errorf("got %s", out) 20 | } 21 | clt1 = jsn.Tocollate(clt.Reset(nil)) 22 | if out := string(clt1.Bytes()); out != ref { 23 | t.Errorf("expected %s", ref) 24 | t.Errorf("got %s", out) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /collate_string.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | func suffixEncodeString(s []byte, code []byte) int { 4 | n := 0 5 | for _, x := range s { 6 | code[n] = x 7 | n++ 8 | if x == Terminator { 9 | code[n] = 1 10 | n++ 11 | } 12 | } 13 | code[n] = Terminator 14 | return n + 1 15 | } 16 | 17 | func suffixDecodeString(code []byte, text []byte) (int, int) { 18 | for i, j := 0, 0; i < len(code); i++ { 19 | x := code[i] 20 | if x == Terminator { 21 | i++ 22 | switch x = code[i]; x { 23 | case 1: 24 | text[j] = 0 25 | j++ 26 | case Terminator: 27 | return i + 1, j 28 | default: 29 | panic("collate decode invalid escape sequence") 30 | } 31 | continue 32 | } 33 | text[j] = x 34 | j++ 35 | } 36 | panic("collate decode invalid string") 37 | } 38 | 39 | func encodedStringSize(code []byte) int { 40 | for i := 0; i < len(code); { 41 | if code[i] == Terminator { 42 | switch code[i+1] { 43 | case 1: 44 | i++ 45 | case Terminator: 46 | return i 47 | default: 48 | panic("collate decode invalid escape sequence") 49 | } 50 | } 51 | i++ 52 | } 53 | panic("collate decode invalid string") 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014 Gson Authors. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /template/md/announcement/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Announcement Templates] 3 | 4 | ## @color[black](Announcement
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++ 14 | @title[Big News Teaser] 15 | 16 | @snap[north announce-big-news] 17 | BIG 18 | @snapend 19 | 20 | @snap[south announce-big-news text-orange] 21 | NEWS 22 | @snapend 23 | 24 | @snap[south-west template-note text-gray] 25 | Big-news teaser template. 26 | @snapend 27 | 28 | 29 | +++ 30 | @title[New Release Teaser] 31 | 32 | ## New Release 33 | 34 | @css[text-pink](@fa[calendar] January, 2019.) 35 | 36 | @snap[south-west template-note text-gray] 37 | Upcoming-release teaser template. 38 | @snapend 39 | 40 | 41 | +++?color=linear-gradient(to top, #ffb347, #ffcc33) 42 | @title[Coming Soon Teaser] 43 | 44 | @snap[midpoint announce-coming-soon text-white] 45 | COMING 46 | @snapend 47 | 48 | @snap[south text-white] 49 | SOON ;) 50 | @snapend 51 | 52 | @snap[south-west template-note text-white] 53 | Coming-soon teaser template. 54 | @snapend 55 | -------------------------------------------------------------------------------- /docs/transforms.dot: -------------------------------------------------------------------------------- 1 | digraph value { 2 | ranksep="0.5 equally"; 3 | node [style=filled,shape=ellipse,fontsize="20",color=yellow]; 4 | edge [fontsize="16",minlen=2,weight=9]; 5 | 6 | json -> value[label=" JsonToValue ",color="red",labeldistance=20]; 7 | value -> json[label=" ValueToJson ",color="red",labeldistance=20]; 8 | value -> cbor[label=" ValueToCbor ",color="red",labeldistance=20]; 9 | cbor -> value[label=" CborToValue ",color="red",labeldistance=20]; 10 | json -> cbor[label=" JsonToCbor ",color="red",labeldistance=20]; 11 | cbor -> json[label=" CborToJson ",color="red",labeldistance=20]; 12 | collate -> value[label=" CollateToValue ",color="red",labeldistance=20]; 13 | value -> collate[label=" ValueToCollate ",color="red",labeldistance=20]; 14 | collate -> json[label=" CollateToJson ",color="red",labeldistance=20]; 15 | json -> collate[label=" JsonToCollate ",color="red",labeldistance=20]; 16 | collate -> cbor[label=" CollateToCbor ",color="red",labeldistance=20]; 17 | cbor -> collate[label=" CborToCollate ",color="red",labeldistance=20]; 18 | {rank=same; value; json}; 19 | {rank=same; cbor; collate}; 20 | } 21 | -------------------------------------------------------------------------------- /cmd/n1ql.go: -------------------------------------------------------------------------------- 1 | // +build n1ql 2 | 3 | package main 4 | 5 | import "sort" 6 | import "strings" 7 | import "io/ioutil" 8 | 9 | import qv "github.com/couchbase/query/value" 10 | 11 | func init() { 12 | n1qltag = true 13 | } 14 | 15 | func sortn1ql(filename string) []string { 16 | data, err := ioutil.ReadFile(filename) 17 | if err != nil { 18 | panic(err.Error()) 19 | } 20 | s := string(data) 21 | items := strings.Split(s, "\n") 22 | for i := 0; i < options.repeat; i++ { 23 | list := &jsonList{vals: items, compares: 0} 24 | sort.Sort(list) 25 | } 26 | list := &jsonList{vals: items, compares: 0} 27 | sort.Sort(list) 28 | return list.vals 29 | } 30 | 31 | // sort type for n1ql 32 | 33 | type jsonList struct { 34 | compares int 35 | vals []string 36 | } 37 | 38 | func (jsons *jsonList) Len() int { 39 | return len(jsons.vals) 40 | } 41 | 42 | func (jsons *jsonList) Less(i, j int) bool { 43 | key1, key2 := jsons.vals[i], jsons.vals[j] 44 | jsons.compares++ 45 | value1 := qv.NewValue([]byte(key1)) 46 | value2 := qv.NewValue([]byte(key2)) 47 | return value1.Collate(value2) < 0 48 | } 49 | 50 | func (jsons *jsonList) Swap(i, j int) { 51 | jsons.vals[i], jsons.vals[j] = jsons.vals[j], jsons.vals[i] 52 | } 53 | -------------------------------------------------------------------------------- /collate_string_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "bytes" 5 | 6 | func TestSuffixCoding(t *testing.T) { 7 | testcases := [][]byte{ 8 | []byte("hello\x00wo\xffrld\x00"), 9 | []byte("hello\x00wo\xffrld\x00ln"), 10 | } 11 | for _, bs := range testcases { 12 | code, text := make([]byte, 1024), make([]byte, 1024) 13 | n := suffixEncodeString(bs, code) 14 | code[n] = Terminator 15 | n++ 16 | x, y := suffixDecodeString(code[:n], text) 17 | if bytes.Compare(bs, text[:y]) != 0 { 18 | t.Error("Suffix coding for strings failed") 19 | } 20 | if l := len(code[x:n]); l != 0 { 21 | t.Errorf("Suffix coding for strings, residue found %v", l) 22 | } 23 | } 24 | } 25 | 26 | func BenchmarkSuffixEncode(b *testing.B) { 27 | var code [1024]byte 28 | bs := []byte("hello\x00wo\xffrld\x00") 29 | for i := 0; i < b.N; i++ { 30 | suffixEncodeString(bs, code[:]) 31 | } 32 | } 33 | 34 | func BenchmarkSuffixDecode(b *testing.B) { 35 | var code, text [1024]byte 36 | bs := []byte("hello\x00wo\xffrld\x00") 37 | n := suffixEncodeString(bs, code[:]) 38 | code[n] = Terminator 39 | n++ 40 | b.ResetTimer() 41 | for i := 0; i < b.N; i++ { 42 | suffixDecodeString(code[:n], text[:]) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bignum_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "strconv" 4 | import "testing" 5 | import "math/big" 6 | 7 | func BenchmarkAtoi(b *testing.B) { 8 | for i := 0; i < b.N; i++ { 9 | strconv.Atoi("6744073709551615") 10 | } 11 | } 12 | 13 | func BenchmarkBigParseFloat(b *testing.B) { 14 | bf := big.NewFloat(0) 15 | bf.SetPrec(64) 16 | for i := 0; i < b.N; i++ { 17 | bf.Parse("18446744073709551615", 0) 18 | } 19 | } 20 | 21 | func BenchmarkBigUint64Fmt(b *testing.B) { 22 | bf := big.NewFloat(0) 23 | out := make([]byte, 0, 1024) 24 | num := uint64(18446744073709551615) 25 | bf.SetPrec(64) 26 | bf.SetUint64(num) 27 | 28 | for i := 0; i < b.N; i++ { 29 | bf.Append(out, 'e', -1) 30 | } 31 | } 32 | 33 | func BenchmarkBigInt64Fmt(b *testing.B) { 34 | bf := big.NewFloat(0) 35 | out := make([]byte, 0, 128) 36 | num := int64(446744073709551615) 37 | bf.SetPrec(64) 38 | bf.SetInt64(num) 39 | 40 | for i := 0; i < b.N; i++ { 41 | bf.Append(out, 'e', -1) 42 | } 43 | } 44 | 45 | func BenchmarkBigFloatFmt(b *testing.B) { 46 | bf := big.NewFloat(0) 47 | out := make([]byte, 0, 128) 48 | num := float64(18446744073709551615.123) 49 | bf.SetPrec(64) 50 | bf.SetFloat64(num) 51 | 52 | for i := 0; i < b.N; i++ { 53 | bf.Append(out, 'e', -1) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cbor_appendix_a_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "reflect" 5 | import "encoding/json" 6 | import hexcodec "encoding/hex" 7 | 8 | func TestCborAppendixA(t *testing.T) { 9 | t.Skip("skipping CborAppendixA") 10 | var testcases []interface{} 11 | 12 | data := testdataFile("testdata/cbor.appendix.a.json") 13 | json.Unmarshal(data, &testcases) 14 | 15 | config := NewDefaultConfig() 16 | cbr := config.NewCbor(make([]byte, 0, 10)) 17 | 18 | for _, tcase := range testcases { 19 | tcmap := tcase.(map[string]interface{}) 20 | hexinp, refval := tcmap["hex"].(string), tcmap["decoded"].(interface{}) 21 | roundtrip := tcmap["roundtrip"].(bool) 22 | cborbuf, err := hexcodec.DecodeString(hexinp) 23 | if err != nil { 24 | t.Log(tcase) 25 | t.Error(err) 26 | } 27 | val := cbr.Reset(cborbuf).Tovalue() 28 | if reflect.DeepEqual(val, refval) == false { 29 | t.Log(tcase) 30 | t.Errorf("expected %v, got %v", refval, val) 31 | } 32 | if roundtrip { 33 | v := config.NewValue(val) 34 | cborbytes := v.Tocbor(cbr.Reset(make([]byte, 1024*1024))).Bytes() 35 | s := hexcodec.EncodeToString(cborbytes) 36 | if s != hexinp { 37 | t.Logf("roundtrip %v", tcase) 38 | t.Errorf("expected %q, got %q", hexinp, s) 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /keyspool.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | type mkeyshead struct { 4 | head *mkeysnode 5 | } 6 | 7 | func (b *mkeyshead) getmkeys(size int) *mkeysnode { 8 | if node := b.head; node != nil { 9 | if len(node.keys) < size { 10 | node.keys = make([]string, 0, size) 11 | } 12 | node.keys = node.keys[:0] 13 | b.head = node.next 14 | return node 15 | } 16 | node := &mkeysnode{keys: make([]string, 0, size), next: nil} 17 | return node 18 | } 19 | 20 | func (b *mkeyshead) putmkeys(node *mkeysnode) { 21 | node.next = b.head 22 | b.head = node 23 | } 24 | 25 | type mkeysnode struct { 26 | keys []string 27 | next *mkeysnode 28 | } 29 | 30 | // sort JSON property objects based on property names. 31 | 32 | func (m *mkeysnode) sortProps1(val map[string]interface{}) []string { 33 | for k := range val { 34 | m.keys = append(m.keys, k) 35 | } 36 | 37 | m.keys = sortStrings(m.keys) 38 | return m.keys 39 | } 40 | 41 | func (m *mkeysnode) sortProps2(val map[string]uint64) []string { 42 | for k := range val { 43 | m.keys = append(m.keys, k) 44 | } 45 | m.keys = sortStrings(m.keys) 46 | return m.keys 47 | } 48 | 49 | func (m *mkeysnode) sortProps3(val [][2]interface{}) []string { 50 | for _, item := range val { 51 | m.keys = append(m.keys, item[0].(string)) 52 | } 53 | m.keys = sortStrings(m.keys) 54 | return m.keys 55 | } 56 | -------------------------------------------------------------------------------- /PITCHME.yaml: -------------------------------------------------------------------------------- 1 | # The default settings below are optimized for this template. 2 | # Override settings with your own custom values as needed. 3 | # 4 | # For further details, see https://gitpitch.com/docs/settings. 5 | # 6 | 7 | published : true 8 | 9 | # 10 | # Theme Setting 11 | # Doc: https://gitpitch.com/docs/settings/theme 12 | # 13 | theme : white 14 | 15 | # 16 | # Theme-Override Setting 17 | # Doc: https://gitpitch.com/docs/settings/custom-theme 18 | # 19 | theme-override : template/css/PITCHME.css 20 | 21 | # 22 | # Logo Setting 23 | # https://gitpitch.com/docs/settings/logo 24 | # 25 | logo : template/img/logo.png 26 | logo-position : top-left 27 | 28 | # 29 | # Footnote Setting 30 | # Doc: https://gitpitch.com/docs/settings/footnote 31 | # 32 | footnote : "golog - basic logging with batteries" 33 | 34 | # 35 | # Highlight (Code) Setting 36 | # Doc: https://gitpitch.com/docs/settings/highlight 37 | # 38 | highlight : github 39 | 40 | # 41 | # Layout Setting 42 | # Doc: https://gitpitch.com/docs/settings/layout 43 | # 44 | layout : center 45 | 46 | # 47 | # Transition Setting 48 | # This template uses GitPitch Snap-Layouts extensively. For this 49 | # reason THIS VALUE SHOULD NOT BE MODIFIED. See: 50 | # https://gitpitch.com/docs/layout-features/snap-layout-slide-transitions 51 | # 52 | transition : fade 53 | 54 | slide-number : true 55 | vertical-center : false 56 | -------------------------------------------------------------------------------- /kvpool.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | type kvhead struct { 4 | head *kvnode 5 | } 6 | 7 | func (b *kvhead) getkv(size int) *kvnode { 8 | if node := b.head; node != nil { 9 | if cap(node.refs) < size { 10 | node.refs = make(kvrefs, 0, size) 11 | } 12 | node.refs = node.refs[:0] 13 | b.head = node.next 14 | return node 15 | } 16 | node := &kvnode{refs: make(kvrefs, 0, size), next: nil} 17 | return node 18 | } 19 | 20 | func (b *kvhead) putkv(node *kvnode) { 21 | node.next = b.head 22 | b.head = node 23 | } 24 | 25 | type kvnode struct { 26 | refs kvrefs 27 | next *kvnode 28 | } 29 | 30 | //---- data modelling to sort and collate JSON property items. 31 | 32 | type kvref struct { 33 | key string 34 | code []byte 35 | } 36 | 37 | type kvrefs []kvref 38 | 39 | func (kv kvrefs) Len() int { 40 | return len(kv) 41 | } 42 | 43 | func (kv kvrefs) Less(i, j int) bool { 44 | return kv[i].key < kv[j].key 45 | } 46 | 47 | func (kv kvrefs) Swap(i, j int) { 48 | tmp := kv[i] 49 | kv[i] = kv[j] 50 | kv[j] = tmp 51 | } 52 | 53 | // bubble sort, moving to qsort should be atleast 40% faster. 54 | func (kv kvrefs) sort() { 55 | for ln := len(kv) - 1; ; ln-- { 56 | changed := false 57 | for i := 0; i < ln; i++ { 58 | if kv[i].key > kv[i+1].key { 59 | kv[i], kv[i+1] = kv[i+1], kv[i] 60 | changed = true 61 | } 62 | } 63 | if changed == false { 64 | break 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | Build and Release Check list 2 | ============================ 3 | 4 | * Ensure coverage to be > 90%. Unit tests are not silver bullets to catch 5 | all bugs, but they can help maintain decent code-quality against 6 | future commits. 7 | * Set up with https://coveralls.io for coverage analysis. 8 | * Set up with https://travis-ci.org/ for continuous integration and 9 | enable daily CRON job. 10 | * Spell check all `.md` files. 11 | 12 | Repository structure 13 | -------------------- 14 | 15 | * README.md file that includes - 16 | * Badges. 17 | * Bullet point of why and what of this package. 18 | * Quicklinks. 19 | * Short descriptions and details about this package. 20 | * Panic and recovery. 21 | * Examples. 22 | * External references. 23 | * How to contribute. 24 | * RELEASE.md checklist. 25 | * LICENSE under which this package is released on github. 26 | * AUTHORS list of contributing authors, copyright is collectively 27 | held by authors. 28 | * PITCHME files, if any, for package presentation. 29 | 30 | Badges 31 | ------ 32 | 33 | * Talk on matrix. 34 | * CI badge 35 | * Coverage badge 36 | * Godoc reference. 37 | * Issue stats badge for response time. 38 | http://issuestats.com/github/bnclabs/gson 39 | * Sourcegraph for "used by projects" badge 40 | https://sourcegraph.com/github.com/bnclabs/gson/-/badge.svg 41 | * Report card. 42 | https://goreportcard.com/report/github.com/bnclabs/gson 43 | -------------------------------------------------------------------------------- /testdata/scan_valid: -------------------------------------------------------------------------------- 1 | null 2 | true 3 | false 4 | 1 5 | 0.1 6 | -0.1 7 | 10.1 8 | -10.1 9 | -10E-1 10 | -10e+1 11 | 10E-1 12 | 10e+1 13 | "true" 14 | "tru\"e" 15 | "tru\\e" 16 | "tru\be" 17 | "tru\fe" 18 | "tru\ne" 19 | "tru\re" 20 | "tru\te" 21 | "tru\u0123e" 22 | "汉语 / 漢語; Hàn\b \t\uef24yǔ " 23 | "a\u1234" 24 | "http:\/\/" 25 | "invalid: \uD834x\uDD1E" 26 | "\"foobar\"\u003chtml\u003e [\u2028 \u2029]" 27 | [ ] 28 | [] 29 | [ null, true, false, 10, "tru\"e" ] 30 | [{}] 31 | { "a": null, "b" : true,"c":false, "d\"":10, "e":"tru\"e" } 32 | { } 33 | {} 34 | true 35 | 1 36 | 1.2 37 | -5 38 | 2 39 | 2 40 | 2 41 | 2 42 | "null" 43 | {"X": [1,2,3], "Y": 4} 44 | {"x": 1} 45 | {"F1":1,"F2":2,"F3":3} 46 | {"F1":1,"F2":2,"F3":3} 47 | {"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}} 48 | {"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}} 49 | "\n true " 50 | "\t 1 " 51 | "\r 1.2 " 52 | "\t -5 \n" 53 | "\t \"a\\u1234\" \n" 54 | {"Y": 1, "Z": 2} 55 | {"alpha": "abc", "alphabet": "xyz"} 56 | {"alpha": "abc"} 57 | {"alphabet": "xyz"} 58 | [1, 2, 3] 59 | [1, 2, 3] 60 | [1, 2, 3] 61 | [] 62 | null 63 | {"T":[]} 64 | {"T":null} 65 | {"T":false} 66 | {"T":false} 67 | [{"T":false}] 68 | [{"T":false}] 69 | {"M":{"T":false}} 70 | "X" 71 | "X" 72 | ["X"] 73 | ["X"] 74 | {"M":"X"} 75 | {"hello": 1} 76 | {"X": 1,"Y":2} 77 | {"X": 1,"Y":2} 78 | "hello\\ud800world" 79 | "hello\\ud800\\ud800world" 80 | "hello\\ud800\\ud800world" 81 | {"2009-11-10T23:00:00Z": "hello world"} 82 | -------------------------------------------------------------------------------- /template/md/quotation/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Quotation Templates] 3 | 4 | ## @color[black](Quotation
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/einstein.png&position=left&size=60% auto 14 | @title[Quote + Image] 15 | 16 | @snap[north-east span-60] 17 | @quote[We cannot solve our problems with the same thinking we used when we created them.] 18 | @snapend 19 | 20 | @snap[south-east template-note text-gray] 21 | Simple quotation with image template. 22 | @snapend 23 | 24 | +++?image=template/img/moon.jpg&size=cover 25 | @title[Quote Attributed] 26 | 27 | @snap[east text-white span-50] 28 | @quote[Houston, Tranquillity Base here. The Eagle has landed.](Neil Armstrong) 29 | @snapend 30 | 31 | @snap[north-east template-note text-white] 32 | Quotation with attribution template. 33 | @snapend 34 | 35 | +++?image=template/img/quotes.jpg 36 | @title[Quote Cloud] 37 | 38 | @snap[south-east span-50] 39 | @quote[GitPitch Desktop with speaker notes is AMAZING!](Dave T.) 40 | @snapend 41 | 42 | @snap[north-west] 43 |
44 | @quote[GitPitch is just WONDERFUL!](Mohammed A.) 45 | @snapend 46 | 47 | @snap[south-west span-20] 48 | @quote[Just discovered GitPitch. And WOW!](Adrian K.) 49 | @snapend 50 | 51 | @snap[north-west template-note text-black] 52 | Quotation cloud template. 53 | @snapend 54 | -------------------------------------------------------------------------------- /testdata/pallValueIndent: -------------------------------------------------------------------------------- 1 | { 2 | "Bool": false, 3 | "Int": 0, 4 | "Int8": 0, 5 | "Int16": 0, 6 | "Int32": 0, 7 | "Int64": 0, 8 | "Uint": 0, 9 | "Uint8": 0, 10 | "Uint16": 0, 11 | "Uint32": 0, 12 | "Uint64": 0, 13 | "Uintptr": 0, 14 | "Float32": 0, 15 | "Float64": 0, 16 | "bar": "", 17 | "bar2": "", 18 | "IntStr": "0", 19 | "PBool": true, 20 | "PInt": 2, 21 | "PInt8": 3, 22 | "PInt16": 4, 23 | "PInt32": 5, 24 | "PInt64": 6, 25 | "PUint": 7, 26 | "PUint8": 8, 27 | "PUint16": 9, 28 | "PUint32": 10, 29 | "PUint64": 11, 30 | "PUintptr": 12, 31 | "PFloat32": 14.1, 32 | "PFloat64": 15.1, 33 | "String": "", 34 | "PString": "16", 35 | "Map": null, 36 | "MapP": null, 37 | "PMap": { 38 | "17": { 39 | "Tag": "tag17" 40 | }, 41 | "18": { 42 | "Tag": "tag18" 43 | } 44 | }, 45 | "PMapP": { 46 | "19": { 47 | "Tag": "tag19" 48 | }, 49 | "20": null 50 | }, 51 | "EmptyMap": null, 52 | "NilMap": null, 53 | "Slice": null, 54 | "SliceP": null, 55 | "PSlice": [ 56 | { 57 | "Tag": "tag20" 58 | }, 59 | { 60 | "Tag": "tag21" 61 | } 62 | ], 63 | "PSliceP": [ 64 | { 65 | "Tag": "tag22" 66 | }, 67 | null, 68 | { 69 | "Tag": "tag23" 70 | } 71 | ], 72 | "EmptySlice": null, 73 | "NilSlice": null, 74 | "StringSlice": null, 75 | "ByteSlice": null, 76 | "Small": { 77 | "Tag": "" 78 | }, 79 | "PSmall": null, 80 | "PPSmall": { 81 | "Tag": "tag31" 82 | }, 83 | "Interface": null, 84 | "PInterface": 5.2 85 | } 86 | -------------------------------------------------------------------------------- /testdata/typical.json: -------------------------------------------------------------------------------- 1 | { 2 | "gravatar_id" : "", 3 | "friends" : [], 4 | "projects" : { 5 | "Sherri" : { 6 | "members" : [ 7 | "Sangho" 8 | ], 9 | "language" : "python", 10 | "type" : "project" 11 | } 12 | }, 13 | "subscriptions_url" : "https://api.github.com/users/ExaPaw/subscriptions", 14 | "organizations_url" : "https://api.github.com/users/ExaPaw/orgs", 15 | "gists_url" : "https://api.github.com/users/ExaPaw/gists{/gist_id}", 16 | "followers_url" : "https://api.github.com/users/ExaPaw/followers", 17 | "created_at" : "2015-01-07T17:33:10Z", 18 | "site_admin" : false, 19 | "following_url" : "https://api.github.com/users/ExaPaw/following{/other_user}", 20 | "url" : "https://api.github.com/users/ExaPaw", 21 | "public_gists" : 0, 22 | "id" : 10438397, 23 | "following" : 0, 24 | "followers" : 0, 25 | "starred_url" : "https://api.github.com/users/ExaPaw/starred{/owner}{/repo}", 26 | "avatar_url" : "https://avatars.githubusercontent.com/u/10438397?v=3", 27 | "repos_url" : "https://api.github.com/users/ExaPaw/repos", 28 | "login" : "ExaPaw", 29 | "updated_at" : "2015-04-18T09:31:26Z", 30 | "html_url" : "https://github.com/ExaPaw", 31 | "events_url" : "https://api.github.com/users/ExaPaw/events{/privacy}", 32 | "received_events_url" : "https://api.github.com/users/ExaPaw/received_events", 33 | "type" : "User", 34 | "team" : [ 35 | "mkg", 36 | "mlk", 37 | "lt" 38 | ], 39 | "public_repos" : 2, 40 | "~/some/path" : null, 41 | "汉语 / 漢語" : "汉语 / 漢語; Hàn\b \t\uef24yǔ " 42 | } 43 | -------------------------------------------------------------------------------- /cmd/transforms.sh: -------------------------------------------------------------------------------- 1 | go build -o gson 2 | go build -tags n1ql -o gsonn1ql 3 | 4 | echo "list pointers ..." 5 | ./gson -pointers -inpfile ../testdata/typical.json 6 | echo 7 | 8 | echo "check collation order in directory ..." 9 | ./gson -checkdir ../testdata/collate 10 | echo 11 | 12 | echo "sort json objects in file ..." 13 | ./gsonn1ql -n1qlsort ../testdata/collate/objects.ref 14 | echo 15 | 16 | echo "compute overheads ..." 17 | ./gson -overheads 18 | echo 19 | 20 | echo "value2json ..." 21 | ./gson -value2json -inptxt '{"python":"good","perl":"ugly","php":"bad"}' 22 | echo 23 | 24 | echo "json2value ..." 25 | ./gson -json2value -inptxt '{"python":"good","perl":"ugly","php":"bad"}' 26 | echo 27 | 28 | echo "json2cbor ..." 29 | ./gson -json2cbor -inptxt '{"python":"good","perl":"ugly","php":"bad"}' 30 | echo 31 | 32 | echo "cbor2json ..." 33 | ./gson -quote -cbor2json -inptxt '"\xbffpythondgooddperlduglycphpcbad\xff"' 34 | echo 35 | 36 | echo "cbor2collate ..." 37 | ./gson -quote -cbor2collate -inptxt '"\xbffpythondgooddperlduglycphpcbad\xff"' 38 | echo 39 | 40 | echo "collate2cbor ..." 41 | ./gson -quote -collate2cbor -inptxt '"xd>3\x00Zperl\x00\x00Zugly\x00\x00Zphp\x00\x00Zbad\x00\x00Zpython\x00\x00Zgood\x00\x00\x00"' 42 | echo 43 | 44 | echo "value2cbor ..." 45 | ./gson -value2cbor -inptxt '{"python":"good","perl":"ugly","php":"bad"}' 46 | echo 47 | 48 | echo "cbor2value ..." 49 | ./gson -quote -cbor2value -inptxt '"\xbffpythondgooddperlduglycphpcbad\xff"' 50 | echo 51 | 52 | echo "json2collate ..." 53 | ./gson -json2collate -inptxt '{"python":"good","perl":"ugly","php":"bad"}' 54 | echo 55 | 56 | echo "collate2json ..." 57 | ./gson -quote -collate2json -inptxt '"xd>3\x00Zperl\x00\x00Zugly\x00\x00Zphp\x00\x00Zbad\x00\x00Zpython\x00\x00Zgood\x00\x00\x00"' 58 | echo 59 | -------------------------------------------------------------------------------- /testdata/allValueIndent: -------------------------------------------------------------------------------- 1 | { 2 | "Bool": true, 3 | "Int": 2, 4 | "Int8": 3, 5 | "Int16": 4, 6 | "Int32": 5, 7 | "Int64": 6, 8 | "Uint": 7, 9 | "Uint8": 8, 10 | "Uint16": 9, 11 | "Uint32": 10, 12 | "Uint64": 11, 13 | "Uintptr": 12, 14 | "Float32": 14.1, 15 | "Float64": 15.1, 16 | "bar": "foo", 17 | "bar2": "foo2", 18 | "IntStr": "42", 19 | "PBool": null, 20 | "PInt": null, 21 | "PInt8": null, 22 | "PInt16": null, 23 | "PInt32": null, 24 | "PInt64": null, 25 | "PUint": null, 26 | "PUint8": null, 27 | "PUint16": null, 28 | "PUint32": null, 29 | "PUint64": null, 30 | "PUintptr": null, 31 | "PFloat32": null, 32 | "PFloat64": null, 33 | "String": "16", 34 | "PString": null, 35 | "Map": { 36 | "17": { 37 | "Tag": "tag17" 38 | }, 39 | "18": { 40 | "Tag": "tag18" 41 | } 42 | }, 43 | "MapP": { 44 | "19": { 45 | "Tag": "tag19" 46 | }, 47 | "20": null 48 | }, 49 | "PMap": null, 50 | "PMapP": null, 51 | "EmptyMap": {}, 52 | "NilMap": null, 53 | "Slice": [ 54 | { 55 | "Tag": "tag20" 56 | }, 57 | { 58 | "Tag": "tag21" 59 | } 60 | ], 61 | "SliceP": [ 62 | { 63 | "Tag": "tag22" 64 | }, 65 | null, 66 | { 67 | "Tag": "tag23" 68 | } 69 | ], 70 | "PSlice": null, 71 | "PSliceP": null, 72 | "EmptySlice": [], 73 | "NilSlice": null, 74 | "StringSlice": [ 75 | "str24", 76 | "str25", 77 | "str26" 78 | ], 79 | "ByteSlice": "Gxwd", 80 | "Small": { 81 | "Tag": "tag30" 82 | }, 83 | "PSmall": { 84 | "Tag": "tag31" 85 | }, 86 | "PPSmall": null, 87 | "Interface": 5.2, 88 | "PInterface": null 89 | } 90 | -------------------------------------------------------------------------------- /template/md/about/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[About Templates] 3 | 4 | ## @color[black](About
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/bg/blue.jpg&color=white&position=top&size=100% 50% 14 | @title[Meet The Team] 15 | 16 | @snap[north text-white span-100] 17 | @size[1.5em](Meet The Team) 18 | @snapend 19 | 20 | @snap[west about-team-pic] 21 | ![WENDY](template/img/profile/wendy.jpg) 22 | @snapend 23 | 24 | @snap[south-west about-team-bio] 25 | @color[#4487F2](Wendy Sesay) 26 |

27 | @fa[twitter](wendy) 28 |
29 | Graphic Designer 30 | @snapend 31 | 32 | @snap[midpoint about-team-pic about-team-pic-center] 33 | ![ABBY](template/img/profile/abby.jpg) 34 | @snapend 35 | 36 | @snap[south about-team-bio] 37 | @color[#4487F2](Abby Bauer) 38 |

39 | @fa[github](abbycode) 40 |
41 | Lead Developer 42 | @snapend 43 | 44 | @snap[east about-team-pic] 45 | ![BERRY](template/img/profile/berry.jpg) 46 | @snapend 47 | 48 | @snap[south-east about-team-bio] 49 | @color[#4487F2](Berry Nguyen) 50 |

51 | @fa[linkedin](berryngu) 52 |
53 | Channel Marketing 54 | @snapend 55 | 56 | @snap[north-east template-note text-white] 57 | Team intro template. 58 | @snapend 59 | 60 | +++ 61 | @title[Personal Biography] 62 | 63 | @snap[north-west bio-name] 64 | Ada Lovelace 65 | @snapend 66 | 67 | @snap[east span-40] 68 | ![LOVELACE](template/img/lovelace.jpg) 69 | @snapend 70 | 71 | @snap[west about-bio-details span-60] 72 | A gifted mathematician. Born 1815. 73 |

74 | Inspired by Babbage’s Analytical Engine she imagined the modern-day, general-purpose computer back in 1843.

Ada is now recognized as the first computer programmer. 75 | @snapend 76 | 77 | @snap[south-west template-note text-gray] 78 | Simple biography template. 79 | @snapend 80 | -------------------------------------------------------------------------------- /template/md/sidebox/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Sidebox Templates] 3 | 4 | ## @color[black](Sidebox
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/bg/blue.jpg&position=left&size=30% 50% 14 | @title[Sidebox + Heading] 15 | 16 | @snap[west text-white] 17 | @size[3em](A.) 18 | @snapend 19 | 20 | @snap[east span-70] 21 |

Sunt in @css[text-pink](culpa) officia

22 | @snapend 23 | 24 | @snap[north-east template-note text-gray] 25 | Sidebox with heading body template. 26 | @snapend 27 | 28 | 29 | +++?image=template/img/bg/orange.jpg&position=left&size=30% 50% 30 | @title[Sidebox + Image Body] 31 | 32 | @snap[west text-white] 33 | @size[3em](B.) 34 | @snapend 35 | 36 | @snap[east span-70] 37 | ![FRIDAY](template/img/friday.gif) 38 | @snapend 39 | 40 | @snap[north-east template-note text-gray] 41 | Sidebox with image body template. 42 | @snapend 43 | 44 | 45 | +++?image=template/img/bg/green.jpg&position=left&size=30% 50% 46 | @title[Sidebox + Mixed Body] 47 | 48 | @snap[west text-white] 49 | @size[3em](C.) 50 | @snapend 51 | 52 | @snap[east span-70] 53 | @fa[bath fa-5x text-blue] 54 |

55 | How to write clean code. 56 | @snapend 57 | 58 | @snap[north-east template-note text-gray] 59 | Sidebox with mixed body template. 60 | @snapend 61 | 62 | 63 | +++?image=template/img/bg/pink.jpg&position=left&size=30% 50% 64 | @title[Sidebox + Text Body] 65 | 66 | @snap[west text-white] 67 | @size[3em](D.) 68 | @snapend 69 | 70 | @snap[east span-70] 71 | Ut enim ad minim veniam, quis @css[text-pink](nostrud exercitation ullamco laboris) nisi ut aliquip ex ea commodo. 72 |

73 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 74 | @snapend 75 | 76 | @snap[north-east template-note text-gray] 77 | Sidebox with text body template. 78 | @snapend 79 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package gson provide a toolkit for JSON representation, collation 2 | // and transformation. 3 | // 4 | // Package provides APIs to convert data representation from one format 5 | // to another. Supported formats are: 6 | // * JSON 7 | // * Golang value 8 | // * CBOR - Concise Binary Object Representation 9 | // * Binary-collation 10 | // 11 | // CBOR: 12 | // 13 | // Concise Binary Object Representation, CBOR, is based on RFC-7049 14 | // specification to encode golang data into machine friendly format. 15 | // Following golang native types are supported: 16 | // * nil, true, false. 17 | // * native integer types, and its alias, of all width. 18 | // * float32, float64. 19 | // * slice of bytes. 20 | // * native string. 21 | // * slice of interface - []interface{}. 22 | // * map of string to interface{} - map[string]interface{}. 23 | // 24 | // Types from golang's standard library and custom types provided 25 | // by this package that can be encoded using CBOR: 26 | // * CborTagBytes: a cbor encoded []bytes treated as value. 27 | // * CborUndefined: encode a data-item as undefined. 28 | // * CborIndefinite: encode bytes, string, array and map of unspecified length. 29 | // * CborBreakStop: to encode end of CborIndefinite length item. 30 | // * CborTagEpoch: in seconds since epoch. 31 | // * CborTagEpochMicro: in micro-seconds epoch. 32 | // * CborTagFraction: m*(10**e) 33 | // * CborTagFloat: m*(2**e) 34 | // * CborTagPrefix: to self identify a binary blog as CBOR. 35 | // 36 | // Package also provides an implementation for encoding JSON to CBOR 37 | // and vice-versa: 38 | // * Number can be encoded as integer or float. 39 | // * Arrays and maps are encoded using indefinite encoding. 40 | // * Byte-string encoding is not used. 41 | // 42 | // Json-Pointer: 43 | // 44 | // Package also provides a RFC-6901 (JSON-pointers) implementation. 45 | // 46 | // NOTE: Buffer supplied to APIs NewJson(), NewCbor(), NewCollate() 47 | // should atleast be 128 bytes in size. 48 | package gson 49 | -------------------------------------------------------------------------------- /template/md/sidebar/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Sidebar Templates] 3 | 4 | ## @color[black](Sidebar
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/bg/blue.jpg&position=left&size=30% 100% 14 | @title[Sidebar + Heading] 15 | 16 | @snap[west text-white] 17 | @size[3em](1.) 18 | @snapend 19 | 20 | @snap[east span-70] 21 |

Lorem ipsum @css[text-blue](dolor)

22 | @snapend 23 | 24 | @snap[north-east template-note text-gray] 25 | Sidebar with heading body template. 26 | @snapend 27 | 28 | 29 | +++?image=template/img/bg/orange.jpg&position=left&size=30% 100% 30 | @title[Sidebar + Image Body] 31 | 32 | @snap[west text-white] 33 | @size[3em](2.) 34 | @snapend 35 | 36 | @snap[east span-70] 37 | ![SNOWMAN](template/img/snowman.gif) 38 | @snapend 39 | 40 | @snap[north-east template-note text-gray] 41 | Sidebar with image body template. 42 | @snapend 43 | 44 | 45 | +++?image=template/img/bg/green.jpg&position=left&size=30% 100% 46 | @title[Sidebar + Mixed Body] 47 | 48 | @snap[west text-white] 49 | @size[3em](3.) 50 | @snapend 51 | 52 | @snap[east span-70] 53 | @fa[rocket fa-5x text-orange] 54 |

55 | We Have Lift Off 56 | @snapend 57 | 58 | @snap[north-east template-note text-gray] 59 | Sidebar with mixed body template. 60 | @snapend 61 | 62 | 63 | +++?image=template/img/bg/pink.jpg&position=left&size=30% 100% 64 | @title[Sidebar + Text Body] 65 | 66 | @snap[west text-white] 67 | @size[3em](4.) 68 | @snapend 69 | 70 | @snap[east span-70] 71 | Duis aute irure dolor in reprehenderit in voluptate velit @size[1.25em](esse cillum) dolore eu fugiat nulla pariatur. 72 |

73 | Excepteur sint occaecat cupidatat non proident, @css[text-pink](sunt in culpa) qui officia deserunt mollit anim id est laborum. 74 | @snapend 75 | 76 | @snap[north-east template-note text-gray] 77 | Sidebar with text body template. 78 | @snapend 79 | -------------------------------------------------------------------------------- /docs/collate-perf-20142107: -------------------------------------------------------------------------------- 1 | (before) BenchmarkEncodeInt 2000000 800 ns/op 325 B/op 2 allocs/op 2 | (now) BenchmarkEncodeInt 5000000 318 ns/op 18 B/op 1 allocs/op 3 | 4 | (before) BenchmarkDecodeInt 5000000 430 ns/op 17 B/op 1 allocs/op 5 | (now) BenchmarkDecodeInt 5000000 329 ns/op 2 B/op 0 allocs/op 6 | 7 | (before) BenchmarkEncodeFloat 1000000 2263 ns/op 543 B/op 8 allocs/op 8 | (now) BenchmarkEncodeFloat 5000000 466 ns/op 28 B/op 1 allocs/op 9 | 10 | (before) BenchmarkDecodeFloat 1000000 1069 ns/op 120 B/op 4 allocs/op 11 | (now) BenchmarkDecodeFloat 5000000 328 ns/op 121 B/op 0 allocs/op 12 | 13 | (before) BenchmarkEncodeSD 5000000 572 ns/op 65 B/op 2 allocs/op 14 | (now) BenchmarkEncodeSD 20000000 151 ns/op 0 B/op 0 allocs/op 15 | 16 | (before) BenchmarkDecodeSD 5000000 297 ns/op 18 B/op 1 allocs/op 17 | (now) BenchmarkDecodeSD 20000000 125 ns/op 0 B/op 0 allocs/op 18 | 19 | (before) BenchmarkEncodeLD 1000000 1680 ns/op 521 B/op 5 allocs/op 20 | (now) BenchmarkEncodeLD 5000000 589 ns/op 63 B/op 1 allocs/op 21 | 22 | (before) BenchmarkDecodeLD 5000000 708 ns/op 33 B/op 2 allocs/op 23 | (now) BenchmarkDecodeLD 10000000 274 ns/op 6 B/op 0 allocs/op 24 | 25 | (before) BenchmarkSuffixEncode 10000000 235 ns/op 48 B/op 2 allocs/op 26 | (now) BenchmarkSuffixEncode 50000000 71 ns/op 0 B/op 0 allocs/op 27 | 28 | (before) BenchmarkSuffixDecode 10000000 219 ns/op 48 B/op 2 allocs/op 29 | (now) BenchmarkSuffixDecode 50000000 56 ns/op 0 B/op 0 allocs/op 30 | 31 | (before) BenchmarkEncode 50000 70708 ns/op 58614 B/op 184 allocs/op 32 | (now) BenchmarkEncode 200000 13115 ns/op 1552 B/op 41 allocs/op 33 | 34 | (now) BenchmarkDecode 500000 3401 ns/op 550 B/op 14 allocs/op 35 | -------------------------------------------------------------------------------- /clone_cbor_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "reflect" 5 | 6 | func TestCborClone(t *testing.T) { 7 | dotest := func(config *Config) { 8 | cbr := config.NewCbor(make([]byte, 0, 1024)) 9 | cbr.data = cbr.data[:cbr.n+1] 10 | cbr.data[0] = hdrIndefiniteArray 11 | cbr.n++ 12 | config.NewValue(nil).Tocbor(cbr) 13 | config.NewValue(true).Tocbor(config.NewValue(false).Tocbor(cbr)) 14 | config.NewValue(int8(-1)).Tocbor(config.NewValue(uint8(1)).Tocbor(cbr)) 15 | config.NewValue(int8(-100)).Tocbor(cbr) 16 | config.NewValue(uint8(100)).Tocbor(cbr) 17 | config.NewValue(uint16(1024)).Tocbor(cbr) 18 | config.NewValue(int16(-1024)).Tocbor(cbr) 19 | config.NewValue(uint32(1048576)).Tocbor(cbr) 20 | config.NewValue(int32(-1048576)).Tocbor(cbr) 21 | config.NewValue(uint64(1099511627776)).Tocbor(cbr) 22 | config.NewValue(int64(-1099511627776)).Tocbor(cbr) 23 | config.NewValue(float32(10.2)).Tocbor(cbr) 24 | config.NewValue(float64(-10.2)).Tocbor(cbr) 25 | config.NewValue([]byte("hello world")).Tocbor(cbr) 26 | config.NewValue("hello world").Tocbor(cbr) 27 | config.NewValue(CborUndefined(1)).Tocbor(cbr) 28 | config.NewValue(CborTagEpoch(1234567890)).Tocbor(cbr) 29 | cbr.EncodeSimpletype(100) 30 | config.NewValue( 31 | []interface{}{12.0, nil, true, false, "hello world"}).Tocbor(cbr) 32 | config.NewValue( 33 | map[string]interface{}{ 34 | "a": 12.0, "b": nil, "c": true, "d": false, "e": "hello world", 35 | }).Tocbor(cbr) 36 | cbr.EncodeBytechunks([][]byte{[]byte("hello"), []byte("world")}) 37 | cbr.EncodeTextchunks([]string{"hello", "world"}) 38 | cbr.data = cbr.data[:cbr.n+1] 39 | cbr.data[cbr.n] = brkstp 40 | cbr.n++ 41 | 42 | out := make([]byte, 1024) 43 | n := cborclone(cbr.Bytes(), out, config) 44 | cloned := config.NewCbor(out[:n]) 45 | 46 | ref := cbr.Tovalue() 47 | value := cloned.Tovalue() 48 | if !reflect.DeepEqual(value, ref) { 49 | t.Errorf("expected %v, got %v", ref, value) 50 | } 51 | } 52 | 53 | // with LengthPrefix 54 | config := NewDefaultConfig().SetContainerEncoding(LengthPrefix) 55 | dotest(config) 56 | // with Stream 57 | config = NewDefaultConfig().SetContainerEncoding(Stream) 58 | dotest(config) 59 | } 60 | -------------------------------------------------------------------------------- /template/md/image/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Image Templates] 3 | 4 | ## @color[black](Image
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/headphones.jpg 14 | @title[Covered Background] 15 | 16 | @snap[west text-black span-15] 17 | **@size[1.2em](Where words fail, music speaks.)** 18 | @snapend 19 | 20 | @snap[south-west template-note text-white] 21 | Covered background image template. 22 | @snapend 23 | 24 | 25 | +++?image=template/img/dataflow.png&size=contain 26 | @title[Contained Background] 27 | 28 | @snap[south-west template-note text-gray] 29 | Contained background image template. 30 | @snapend 31 | 32 | 33 | +++?image=template/img/batman.png&size=contain&color=linear-gradient(to right, #009fff, #ec2f4b) 34 | @title[Transparent Background] 35 | 36 | @snap[north-east text-white span-20] 37 | @quote[It's what I do that defines me.](Bruce Wayne) 38 | @snapend 39 | 40 | @snap[south-west template-note text-white] 41 | Transparent background with gradient template. 42 | @snapend 43 | 44 | @snap[south-east text-white] 45 | @size[0.3em](Lego Batman Clipart by Clipart.info is licensed under CC BY 4.0) 46 | @snapend 47 | 48 | 49 | +++?image=template/img/geek.png&repeat=repeat-x&color=#F5DB2E&size=25% auto 50 | @title[Repeat Background] 51 | 52 | @snap[north-east text-black span-70] 53 | @quote[Beware of geeks bearing formulas.] 54 | @snapend 55 | 56 | @snap[south-west template-note text-black] 57 | Transparent background image-repeat template. 58 | @snapend 59 | 60 | 61 | +++ 62 | @title[Side-by-Side Images] 63 | 64 | @snap[west span-50] 65 | ![SNOWMAN](template/img/snowman.gif) 66 | @snapend 67 | 68 | @snap[east span-50] 69 | ![OLAF](template/img/olaf.png) 70 | @snapend 71 | 72 | @snap[south-west template-note text-gray] 73 | Side-by-side inline images template. 74 | @snapend 75 | 76 | 77 | +++?image=template/img/geek.gif 78 | @title[GIF Background] 79 | 80 | @snap[north-east text-white] 81 | The Suave Geek 82 | @snapend 83 | 84 | @snap[south-east template-note text-white] 85 | Covered background animated GIF template. 86 | @snapend 87 | 88 | 89 | +++?image=template/img/grass.png&position=bottom&size=100% 30% 90 | @title[Positioned Background] 91 | 92 | ## Is the @size[2.2em](grass) @color[green](always) greener on the other side? 93 | 94 | @snap[north-east template-note text-gray] 95 | Fixed position background image template. 96 | @snapend 97 | -------------------------------------------------------------------------------- /json.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | // SpaceKind to skip white-spaces in JSON text. 4 | type SpaceKind byte 5 | 6 | const ( 7 | // AnsiSpace will skip white space characters defined by ANSI spec. 8 | AnsiSpace SpaceKind = iota + 1 9 | 10 | // UnicodeSpace will skip white space characters defined by Unicode spec. 11 | UnicodeSpace 12 | ) 13 | 14 | type jsonConfig struct { 15 | // if `strict` use encoding/json for string conversion, else use custom 16 | // encoder that is memory optimized. 17 | strict bool 18 | ws SpaceKind 19 | } 20 | 21 | // Json abstraction for value encoded as json text. 22 | type Json struct { 23 | config *Config 24 | data []byte 25 | n int 26 | } 27 | 28 | // Bytes return reference to byte-slice of valid json-buffer. 29 | func (jsn *Json) Bytes() []byte { 30 | return jsn.data[:jsn.n] 31 | } 32 | 33 | // Reset overwrite buffer with data, or if data is nil, 34 | // reset buffer to zero-length. 35 | func (jsn *Json) Reset(data []byte) *Json { 36 | if data == nil { 37 | jsn.n = 0 38 | return jsn 39 | } 40 | jsn.data, jsn.n = data, len(data) 41 | return jsn 42 | } 43 | 44 | // Tovalue parse json text to golang native value. Return remaining text. 45 | func (jsn *Json) Tovalue() (*Json, interface{}) { 46 | remaining, value := json2value(bytes2str(jsn.data[:jsn.n]), jsn.config) 47 | if remaining != "" { 48 | return jsn.config.NewJson(str2bytes(remaining)), value 49 | } 50 | return nil, value 51 | } 52 | 53 | // Tovalues parse json text to one or more go native values. 54 | func (jsn *Json) Tovalues() []interface{} { 55 | var values []interface{} 56 | var tok interface{} 57 | txt := bytes2str(jsn.data[:jsn.n]) 58 | for len(txt) > 0 { 59 | txt, tok = json2value(txt, jsn.config) 60 | values = append(values, tok) 61 | } 62 | return values 63 | } 64 | 65 | // Tocbor convert json encoded value into cbor encoded binary string. 66 | func (jsn *Json) Tocbor(cbr *Cbor) *Cbor { 67 | in, out := bytes2str(jsn.data[:jsn.n]), cbr.data[cbr.n:cap(cbr.data)] 68 | _ /*remning*/, m := json2cbor(in, out, jsn.config) 69 | cbr.n += m 70 | return cbr 71 | } 72 | 73 | // Tocollate convert json encoded value into binary-collation. 74 | func (jsn *Json) Tocollate(clt *Collate) *Collate { 75 | in, out := bytes2str(jsn.data[:jsn.n]), clt.data[clt.n:cap(clt.data)] 76 | _ /*remn*/, m := json2collate(in, out, jsn.config) 77 | clt.n += m 78 | return clt 79 | } 80 | 81 | func (ws SpaceKind) String() string { 82 | switch ws { 83 | case AnsiSpace: 84 | return "AnsiSpace" 85 | case UnicodeSpace: 86 | return "UnicodeSpace" 87 | default: 88 | panic("new space-kind") 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /json_string.go: -------------------------------------------------------------------------------- 1 | // Package json implements encoding and decoding of JSON objects as defined in 2 | // RFC 4627. The mapping between JSON objects and Go values is described 3 | // in the documentation for the Marshal and Unmarshal functions. 4 | // 5 | // See "JSON and Go" for an introduction to this package: 6 | // http://golang.org/doc/articles/json_and_go.html 7 | 8 | package gson 9 | 10 | import "unicode/utf8" 11 | 12 | var hex = "0123456789abcdef" 13 | 14 | // Copied from golang src/pkg/encoding/json/encode.go 15 | // Modified to use []byte as input and use DecodeRune() instead of 16 | // DecodeRuneInString. 17 | func encodeString(s, text []byte) ([]byte, error) { 18 | text = append(text, '"') 19 | start := 0 20 | for i := 0; i < len(s); { 21 | if b := s[i]; b < utf8.RuneSelf { 22 | if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { 23 | i++ 24 | continue 25 | } 26 | if start < i { 27 | text = append(text, s[start:i]...) 28 | } 29 | switch b { 30 | case '\\', '"': 31 | text = append(text, '\\') 32 | text = append(text, b) 33 | case '\n': 34 | text = append(text, '\\') 35 | text = append(text, 'n') 36 | case '\r': 37 | text = append(text, '\\') 38 | text = append(text, 'r') 39 | default: 40 | // This encodes bytes < 0x20 except for \n and \r, 41 | // as well as <, > and &. The latter are escaped because they 42 | // can lead to security holes when user-controlled strings 43 | // are rendered into JSON and served to some browsers. 44 | 45 | text = append(text, `\u00`...) 46 | text = append(text, hex[b>>4]) 47 | text = append(text, hex[b&0xF]) 48 | } 49 | i++ 50 | start = i 51 | continue 52 | } 53 | c, size := utf8.DecodeRune(s[i:]) 54 | if c == utf8.RuneError && size == 1 { 55 | if start < i { 56 | text = append(text, s[start:i]...) 57 | } 58 | text = append(text, `\ufffd`...) 59 | i += size 60 | start = i 61 | continue 62 | } 63 | // U+2028 is LINE SEPARATOR. 64 | // U+2029 is PARAGRAPH SEPARATOR. 65 | // They are both technically valid characters in JSON strings, 66 | // but don't work in JSONP, which has to be evaluated as JavaScript, 67 | // and can lead to security holes there. It is valid JSON to 68 | // escape them, so we do so unconditionally. 69 | // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. 70 | if c == '\u2028' || c == '\u2029' { 71 | if start < i { 72 | text = append(text, s[start:i]...) 73 | } 74 | text = append(text, `\u202`...) 75 | text = append(text, hex[c&0xF]) 76 | i += size 77 | start = i 78 | continue 79 | } 80 | i += size 81 | } 82 | if start < len(s) { 83 | text = append(text, s[start:]...) 84 | } 85 | text = append(text, '"') 86 | return text, nil 87 | } 88 | -------------------------------------------------------------------------------- /collate_json.go: -------------------------------------------------------------------------------- 1 | // transform json encoded value into collate encoding. 2 | // cnf: NumberKind, arrayLenPrefix, propertyLenPrefix 3 | 4 | package gson 5 | 6 | func collate2json(code []byte, text []byte, config *Config) (int, int) { 7 | if len(code) == 0 { 8 | return 0, 0 9 | } 10 | var scratch [64]byte 11 | n, m := 1, 0 12 | switch code[0] { 13 | case TypeMissing: 14 | copy(text, MissingLiteral) 15 | return n + 1, m + len(MissingLiteral) 16 | 17 | case TypeNull: 18 | copy(text, "null") 19 | return n + 1, m + 4 20 | 21 | case TypeTrue: 22 | copy(text, "true") 23 | return n + 1, m + 4 24 | 25 | case TypeFalse: 26 | copy(text, "false") 27 | return n + 1, m + 5 28 | 29 | case TypeNumber: 30 | x := getDatum(code[n:]) 31 | y := collated2Json(code[n:n+x-1], text, config.nk) 32 | return n + x, m + y 33 | 34 | case TypeString: 35 | var x int 36 | 37 | bufn := config.bufferh.getbuffer(len(code[n:]) * 5) 38 | scratch := bufn.data 39 | 40 | scratch, x = collate2String(code[n:], scratch[:]) 41 | 42 | if config.strict { 43 | config.buf.Reset() 44 | if err := config.enc.Encode(bytes2str(scratch)); err != nil { 45 | panic(err) 46 | } 47 | s := config.buf.Bytes() 48 | m += copy(text[m:], s[:len(s)-1]) // -1 to strip \n 49 | config.bufferh.putbuffer(bufn) 50 | return n + x, m 51 | } 52 | remtxt, err := encodeString(scratch, text[m:m]) 53 | if err != nil { 54 | panic(err) 55 | } 56 | config.bufferh.putbuffer(bufn) 57 | return n + x, m + len(remtxt) 58 | 59 | case TypeArray: 60 | if config.arrayLenPrefix { 61 | x := getDatum(code[n:]) 62 | collated2Int(code[n:n+x-1], scratch[:]) 63 | n += x 64 | } 65 | text[m] = '[' 66 | m++ 67 | for code[n] != Terminator { 68 | x, y := collate2json(code[n:], text[m:], config) 69 | n += x 70 | m += y 71 | text[m] = ',' 72 | m++ 73 | } 74 | n++ // skip terminator 75 | if text[m-1] == ',' { 76 | text[m-1] = ']' 77 | } else { 78 | text[m] = ']' 79 | m++ 80 | } 81 | return n, m 82 | 83 | case TypeObj: 84 | if config.propertyLenPrefix { 85 | x := getDatum(code[n:]) 86 | collated2Int(code[n:n+x-1], scratch[:]) 87 | n += x 88 | } 89 | text[m] = '{' 90 | m++ 91 | for code[n] != Terminator { 92 | x, y := collate2json(code[n:], text[m:], config) 93 | n, m = n+x, m+y 94 | text[m] = ':' 95 | m++ 96 | x, y = collate2json(code[n:], text[m:], config) 97 | n, m = n+x, m+y 98 | text[m] = ',' 99 | m++ 100 | } 101 | n++ // skip terminator 102 | if text[m-1] == ',' { 103 | text[m-1] = '}' 104 | } else { 105 | text[m] = '}' 106 | m++ 107 | } 108 | return n, m 109 | } 110 | panic("collate decode to json invalid binary") 111 | } 112 | -------------------------------------------------------------------------------- /cmd/mprof.sh: -------------------------------------------------------------------------------- 1 | go build -o gson 2 | 3 | echo "value2json ..." 4 | ./gson -repeat 100 -mprof value2json.mprof -value2json -inpfile ../../testdata/code.json.gz 5 | go tool pprof --svg --inuse_space gson value2json.mprof > value2json.inuse.svg 6 | go tool pprof --svg --alloc_space gson value2json.mprof > value2json.alloc.svg 7 | 8 | echo "json2value ..." 9 | ./gson -repeat 100 -mprof json2value.mprof -json2value -inpfile ../../testdata/code.json.gz 10 | go tool pprof --svg --inuse_space gson json2value.mprof > json2value.inuse.svg 11 | go tool pprof --svg --alloc_space gson json2value.mprof > json2value.alloc.svg 12 | 13 | echo "value2cbor ..." 14 | ./gson -repeat 100 -mprof value2cbor.mprof -value2cbor -inpfile ../../testdata/code.json.gz 15 | go tool pprof --svg --inuse_space gson value2cbor.mprof > value2cbor.inuse.svg 16 | go tool pprof --svg --alloc_space gson value2cbor.mprof > value2cbor.alloc.svg 17 | 18 | echo "cbor2value ..." 19 | ./gson -repeat 100 -mprof cbor2value.mprof -cbor2value -inpfile ../../testdata/code.cbor.gz 20 | go tool pprof --svg --inuse_space gson cbor2value.mprof > cbor2value.inuse.svg 21 | go tool pprof --svg --alloc_space gson cbor2value.mprof > cbor2value.alloc.svg 22 | 23 | echo "json2cbor ..." 24 | ./gson -repeat 100 -mprof json2cbor.mprof -json2cbor -inpfile ../../testdata/code.json.gz 25 | go tool pprof --svg --inuse_space gson json2cbor.mprof > json2cbor.inuse.svg 26 | go tool pprof --svg --alloc_space gson json2cbor.mprof > json2cbor.alloc.svg 27 | 28 | echo "cbor2json ..." 29 | ./gson -repeat 100 -mprof cbor2json.mprof -cbor2json -inpfile ../../testdata/code.cbor.gz 30 | go tool pprof --svg --inuse_space gson cbor2json.mprof > cbor2json.inuse.svg 31 | go tool pprof --svg --alloc_space gson cbor2json.mprof > cbor2json.alloc.svg 32 | 33 | echo "cbor2collate ..." 34 | ./gson -repeat 100 -mprof cbor2collate.mprof -cbor2collate -inpfile ../../testdata/code.cbor.gz 35 | go tool pprof --svg --inuse_space gson cbor2collate.mprof > cbor2collate.inuse.svg 36 | go tool pprof --svg --alloc_space gson cbor2collate.mprof > cbor2collate.alloc.svg 37 | 38 | echo "collate2cbor ..." 39 | ./gson -repeat 100 -mprof collate2cbor.mprof -collate2cbor -inpfile ../../testdata/code.collate.gz 40 | go tool pprof --svg --inuse_space gson collate2cbor.mprof > collate2cbor.inuse.svg 41 | go tool pprof --svg --alloc_space gson collate2cbor.mprof > collate2cbor.alloc.svg 42 | 43 | echo "json2collate ..." 44 | ./gson -repeat 100 -mprof json2collate.mprof -json2collate -inpfile ../../testdata/code.json.gz 45 | go tool pprof --svg --inuse_space gson json2collate.mprof > json2collate.inuse.svg 46 | go tool pprof --svg --alloc_space gson json2collate.mprof > json2collate.alloc.svg 47 | 48 | echo "collate2json ..." 49 | ./gson -repeat 100 -mprof collate2json.mprof -collate2json -inpfile ../../testdata/code.collate.gz 50 | go tool pprof --svg --inuse_space gson collate2json.mprof > collate2json.inuse.svg 51 | go tool pprof --svg --alloc_space gson collate2json.mprof > collate2json.alloc.svg 52 | -------------------------------------------------------------------------------- /collate_value.go: -------------------------------------------------------------------------------- 1 | // transform collated value into golang native value. 2 | // cnf: NumberKind, arrayLenPrefix, propertyLenPrefix 3 | 4 | package gson 5 | 6 | import "strconv" 7 | 8 | func collate2gson(code []byte, config *Config) (interface{}, int) { 9 | if len(code) == 0 { 10 | return nil, 0 11 | } 12 | 13 | var scratch [64]byte 14 | n := 1 15 | switch code[0] { 16 | case TypeMissing: 17 | return MissingLiteral, 2 18 | 19 | case TypeNull: 20 | return nil, 2 21 | 22 | case TypeTrue: 23 | return true, 2 24 | 25 | case TypeFalse: 26 | return false, 2 27 | 28 | case TypeNumber: 29 | m := getDatum(code[n:]) 30 | ui, i, f, what := collated2Number(code[n:n+m-1], config.nk) 31 | switch what { 32 | case 1: 33 | return ui, n + m 34 | case 2: 35 | return i, n + m 36 | case 3: 37 | return f, n + m 38 | } 39 | 40 | case TypeString: 41 | s := make([]byte, encodedStringSize(code[n:])) 42 | s, x := collate2String(code[n:], s) 43 | return bytes2str(s), n + x 44 | 45 | case TypeBinary: 46 | m := getDatum(code[n:]) 47 | bs := make([]byte, m-1) 48 | copy(bs, code[n:n+m-1]) 49 | return bs, n + m 50 | 51 | case TypeArray: 52 | var arr []interface{} 53 | if config.arrayLenPrefix { 54 | if code[n] != TypeLength { 55 | panic("collate decode expected array length prefix") 56 | } 57 | n++ 58 | m := getDatum(code[n:]) 59 | _, y := collated2Int(code[n:n+m], scratch[:]) 60 | ln, err := strconv.Atoi(bytes2str(scratch[:y])) 61 | if err != nil { 62 | panic(err) 63 | } 64 | arr = make([]interface{}, 0, ln) 65 | n += m 66 | } else { 67 | arr = make([]interface{}, 0, 8) 68 | } 69 | for code[n] != Terminator { 70 | item, y := collate2gson(code[n:], config) 71 | arr = append(arr, item) 72 | n += y 73 | } 74 | return arr, n + 1 // +1 to skip terminator 75 | 76 | case TypeObj: 77 | obj := make(map[string]interface{}) 78 | if config.propertyLenPrefix { 79 | if code[n] != TypeLength { 80 | panic("collate decode expected object length prefix") 81 | } 82 | n++ 83 | m := getDatum(code[n:]) 84 | _, y := collated2Int(code[n:n+m], scratch[:]) 85 | _, err := strconv.Atoi(bytes2str(scratch[:y])) // just skip 86 | if err != nil { 87 | panic(err) 88 | } 89 | n += m 90 | } 91 | for code[n] != Terminator { 92 | key, m := collate2gson(code[n:], config) 93 | n += m 94 | value, m := collate2gson(code[n:], config) 95 | obj[key.(string)] = value 96 | n += m 97 | } 98 | return obj, n + 1 // +1 to skip terminator 99 | } 100 | panic("collate decode invalid binary") 101 | } 102 | 103 | // get the collated datum based on Terminator and return the length 104 | // of the datum. 105 | func getDatum(code []byte) int { 106 | var i int 107 | var b byte 108 | for i, b = range code { 109 | if b == Terminator { 110 | return i + 1 111 | } 112 | } 113 | panic("collate decode terminator not found") 114 | } 115 | -------------------------------------------------------------------------------- /docs/gettingstarted.md: -------------------------------------------------------------------------------- 1 | Getting started 2 | =============== 3 | 4 | Gson is essentially a data representation package, transforming them from 5 | one format to another. Added to that, some common operation on data, in 6 | its different representation, can be supported as well. 7 | 8 | And, all formats are specified as RFC standard ... 9 | 10 | To start using the Gson package, start with configuration: 11 | 12 | ```go 13 | config := NewDefaultConfig() 14 | ``` 15 | 16 | NewDefaultConfig() creates a new Config{} object with default set of 17 | configuration. Note that fields within the Config{} object are intentionally 18 | hidden, and it shall remain that way. Also, note that config objects are 19 | neither re-entrant and nor thread-safe. It is advised to not to share 20 | config object between go-routines unless method calls are globally 21 | serialized. 22 | 23 | Once we have the Config{} object its configuration settings can be modified 24 | using the supplied APIs. For example: 25 | 26 | ```go 27 | config := NewDefaultConfig() 28 | config = config.SetNumberKind(FloatNumber).SetContainerEncoding(Stream) 29 | ``` 30 | 31 | Config{} objects are immutable. Call to one of the config API will return 32 | a new config instance with new settings. This also allows config-apis to be 33 | chained. 34 | 35 | Use the config instance to create CBOR, JSON, Value and Collate instances. 36 | It is not encouraged to create these instances directly. The created instances 37 | will adhere to the configuration settings available from the config object 38 | that was used to instantiate them. Once configured try to re-use these 39 | instances as much as possible, to avoid memory pressure on GC. 40 | 41 | **GSON objects:** 42 | 43 | ```go 44 | val := config.NewValue("any golang value") // *gson.Value 45 | jsn := config.NewJson(json_byteslice) // *gson.Json 46 | cbr := config.NewCbor(cbor_byteslice) // *gson.Cbor 47 | clt := config.NewCollate(collated_byteslice) // *gson.Collate 48 | ``` 49 | 50 | JSON, CBOR, and Collate can also be initialized with empty buffer, 51 | that have adequate capacity: 52 | 53 | ```go 54 | jsn := config.NewJson(make([]byte, 0, 1024)) 55 | cbr := config.NewCbor(make([]byte, 0, 1024)) 56 | clt := config.NewCollate(make([]byte, 0, 1024)) 57 | ``` 58 | 59 | To reuse JSON, CBOR, or Collate objects: 60 | 61 | ```go 62 | jsn.Reset(nil) 63 | cbr.Reset(nil) 64 | clt.Reset(nil) 65 | ``` 66 | 67 | To reset JSON, CBOR, or Collate objects with another buffer. 68 | 69 | ```go 70 | jsn.Reset(another_json) 71 | cbr.Reset(another_cbor) 72 | clt.Reset(another_collate) 73 | ``` 74 | 75 | To get the underlying buffer as byte-slice. 76 | 77 | ```go 78 | jsn.Bytes() 79 | cbr.Bytes() 80 | clt.Bytes() 81 | ``` 82 | 83 | An example transformation from one data format to another: 84 | 85 | ```go 86 | val := config.NewValue(jsn.Tovalue()) // json -> value 87 | cbr = jsn.Tocbor(cbr) // json -> cbor 88 | clt = jsn.Tocollate(collate) // json -> collate 89 | 90 | // json -> collate -> cbor -> value 91 | val := config.NewValue(jsn.Tocollate(cbr).Tocbor(clt).Tovalue()) 92 | ``` 93 | -------------------------------------------------------------------------------- /template/md/header-footer/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Header + Footer Templates] 3 | 4 | ## @color[black](Header & Footer
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/bg/orange.jpg&position=top&size=100% 20% 14 | @title[Header Bar + Image Body] 15 | 16 | @snap[north text-white span-100] 17 | @size[1.5em](Lorem Ipsum Dolor Sit Amet) 18 | @snapend 19 | 20 | @snap[south span-100] 21 | ![DATAFLOW](template/img/dataflow.png) 22 |

23 | @snapend 24 | 25 | @snap[south-west template-note text-gray] 26 | Header bar with image body template. 27 | @snapend 28 | 29 | 30 | +++?image=template/img/bg/blue.jpg&position=bottom&size=100% 20% 31 | @title[Footer Bar + Image Body] 32 | 33 | @snap[south text-white span-100] 34 | @size[1.5em](Lorem Ipsum Dolor Sit Amet) 35 | @snapend 36 | 37 | @snap[north span-100] 38 |
39 | ![DATAFLOW](template/img/dataflow.png) 40 | @snapend 41 | 42 | @snap[north-east template-note text-gray span-40] 43 | Footer bar with image body template. 44 | @snapend 45 | 46 | 47 | +++?image=template/img/bg/black.jpg&position=center&size=100% 65% 48 | @title[Center Bar + Image Body] 49 | 50 | @snap[north span-100] 51 | @size[1.5em](Lorem Ipsum Dolor Sit Amet) 52 | @snapend 53 | 54 | @snap[midpoint span-80] 55 | ![DATAFLOW](template/img/dataflow.png) 56 | @snapend 57 | 58 | @snap[south-west template-note text-gray] 59 | Center bar with image body template. 60 | @snapend 61 | 62 | 63 | +++?image=template/img/bg/purple.jpg&position=top&size=100% 20% 64 | @title[Header Bar + List Body] 65 | 66 | @snap[north text-white span-100] 67 | @size[1.5em](Lorem Ipsum Dolor Sit Amet) 68 | @snapend 69 | 70 | @snap[south span-100] 71 | @ol[bullet-green](false) 72 | - Consectetur adipiscing elit 73 | - Sed do eiusmod tempor 74 | - Ut enim ad minim veniam 75 | - Duis aute irure dolor in 76 | - Excepteur sint occaecat 77 | - Cupidatat non proident 78 | - Sunt in culpa qui officia 79 | @olend 80 |

81 | @snapend 82 | 83 | @snap[south-west template-note text-gray] 84 | Header bar with list body template. 85 | @snapend 86 | 87 | 88 | +++?image=template/img/bg/green.jpg&position=center&size=100% 65% 89 | @title[Center Bar + List Body] 90 | 91 | @snap[north span-100] 92 | @size[1.5em](Lorem Ipsum Dolor Sit Amet) 93 | @snapend 94 | 95 | @snap[midpoint text-white span-100] 96 | @ul[header-footer-list-shrink](false) 97 | - Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 98 | - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 99 | - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 100 | - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 101 | @snapend 102 | 103 | @snap[south-west template-note text-gray] 104 | Center bar with list body template. 105 | @snapend 106 | -------------------------------------------------------------------------------- /collate.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "encoding/json" 4 | import "math/big" 5 | import "bytes" 6 | 7 | import "golang.org/x/text/collate" 8 | 9 | // Collation order for supported types. Applications desiring different 10 | // ordering between types can initialize these byte values before 11 | // instantiating a config object. 12 | var ( 13 | Terminator byte = 0 14 | TypeMissing byte = 49 15 | TypeNull byte = 50 16 | TypeFalse byte = 60 17 | TypeTrue byte = 70 18 | TypeNumber byte = 80 19 | TypeString byte = 90 20 | TypeLength byte = 100 21 | TypeArray byte = 110 22 | TypeObj byte = 120 23 | TypeBinary byte = 130 24 | ) 25 | 26 | // Missing denotes a special type for an item that evaluates to _nothing_. 27 | type Missing string 28 | 29 | // MissingLiteral is undocumented, for now. 30 | const MissingLiteral = Missing("~[]{}falsenilNA~") 31 | 32 | type collateConfig struct { 33 | doMissing bool // handle missing values (for N1QL) 34 | arrayLenPrefix bool // first sort arrays based on its length 35 | propertyLenPrefix bool // first sort properties based on length 36 | enc *json.Encoder 37 | buf *bytes.Buffer 38 | zf *big.Float 39 | tcltbuffer *collate.Buffer 40 | textcollator *collate.Collator 41 | } 42 | 43 | // Collate abstraction for value encoded into binary-collation. 44 | type Collate struct { 45 | config *Config 46 | data []byte 47 | n int 48 | } 49 | 50 | // Bytes return the byte-slice holding the collated data. 51 | func (clt *Collate) Bytes() []byte { 52 | return clt.data[:clt.n] 53 | } 54 | 55 | // Reset overwrite buffer with data, or if data is nil, 56 | // reset buffer to zero-length. 57 | func (clt *Collate) Reset(data []byte) *Collate { 58 | if data == nil { 59 | clt.n = 0 60 | return clt 61 | } 62 | clt.data, clt.n = data, len(data) 63 | return clt 64 | } 65 | 66 | // Tovalue convert to golang native value. 67 | func (clt *Collate) Tovalue() interface{} { 68 | if clt.n == 0 { 69 | panic("cannot convert empty binary-collate to value") 70 | } 71 | value, _ /*rb*/ := collate2gson(clt.data[:clt.n], clt.config) 72 | return value 73 | } 74 | 75 | // Tojson convert to json encoded text. 76 | func (clt *Collate) Tojson(jsn *Json) *Json { 77 | if clt.n == 0 { 78 | panic("cannot convert empty binary-collate to json") 79 | } 80 | in, out := clt.data[:clt.n], jsn.data[jsn.n:cap(jsn.data)] 81 | _ /*rb*/, m /*wb*/ := collate2json(in, out, clt.config) 82 | jsn.n += m 83 | return jsn 84 | } 85 | 86 | // Tocbor convert to cbor encoded value. 87 | func (clt *Collate) Tocbor(cbr *Cbor) *Cbor { 88 | if clt.n == 0 { 89 | panic("cannot convert empty binary-collate to cbor") 90 | } 91 | in, out := clt.data[:clt.n], cbr.data[cbr.n:cap(cbr.data)] 92 | _ /*rb*/, m /*wb*/ := collate2cbor(in, out, clt.config) 93 | cbr.n += m 94 | return cbr 95 | } 96 | 97 | // Equal checks wether n is MissingLiteral 98 | func (m Missing) Equal(n string) bool { 99 | s := string(m) 100 | if len(n) == len(s) && n[0] == '~' && n[1] == '[' { 101 | return s == n 102 | } 103 | return false 104 | } 105 | -------------------------------------------------------------------------------- /json_cbor_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | 5 | // All test cases are folded into cbor_json_test.go, contains only few 6 | // missing testcases (if any) and benchmarks. 7 | 8 | func TestStrictFloat(t *testing.T) { 9 | config := NewDefaultConfig().SetNumberKind(FloatNumber) 10 | cbr := config.NewCbor(make([]byte, 0, 1024)) 11 | jsn := config.NewJson([]byte("10.2")) 12 | jsn.Tocbor(cbr) 13 | if value := cbr.Tovalue(); value != 10.2 { 14 | t.Errorf("expected %v, got %v", 10.2, value) 15 | } 16 | } 17 | 18 | func BenchmarkJson2CborNull(b *testing.B) { 19 | config := NewDefaultConfig() 20 | jsn := config.NewJson([]byte("null")) 21 | cbr := config.NewCbor(make([]byte, 0, 1024)) 22 | 23 | for i := 0; i < b.N; i++ { 24 | jsn.Tocbor(cbr.Reset(nil)) 25 | } 26 | 27 | b.SetBytes(int64(len(jsn.Bytes()))) 28 | } 29 | 30 | func BenchmarkJson2CborInt(b *testing.B) { 31 | config := NewDefaultConfig() 32 | jsn := config.NewJson([]byte("123456567")) 33 | cbr := config.NewCbor(make([]byte, 0, 1024)) 34 | 35 | for i := 0; i < b.N; i++ { 36 | jsn.Tocbor(cbr.Reset(nil)) 37 | } 38 | b.SetBytes(int64(len(jsn.Bytes()))) 39 | } 40 | 41 | func BenchmarkJson2CborFlt(b *testing.B) { 42 | config := NewDefaultConfig() 43 | jsn := config.NewJson([]byte("1234.12312")) 44 | cbr := config.NewCbor(make([]byte, 0, 1024)) 45 | 46 | for i := 0; i < b.N; i++ { 47 | jsn.Tocbor(cbr.Reset(nil)) 48 | } 49 | b.SetBytes(int64(len(jsn.Bytes()))) 50 | } 51 | 52 | func BenchmarkJson2CborBool(b *testing.B) { 53 | config := NewDefaultConfig() 54 | jsn := config.NewJson([]byte("false")) 55 | cbr := config.NewCbor(make([]byte, 0, 1024)) 56 | 57 | for i := 0; i < b.N; i++ { 58 | jsn.Tocbor(cbr.Reset(nil)) 59 | } 60 | 61 | b.SetBytes(int64(len(jsn.Bytes()))) 62 | } 63 | 64 | func BenchmarkJson2CborStr(b *testing.B) { 65 | config := NewDefaultConfig() 66 | jsn := config.NewJson([]byte(`"汉语 / 漢語; Hàn\b \t\uef24yǔ "`)) 67 | cbr := config.NewCbor(make([]byte, 0, 1024)) 68 | 69 | for i := 0; i < b.N; i++ { 70 | jsn.Tocbor(cbr.Reset(nil)) 71 | } 72 | b.SetBytes(int64(len(jsn.Bytes()))) 73 | } 74 | 75 | func BenchmarkJson2CborArr(b *testing.B) { 76 | in := ` [null,true,false,10,"tru\"e"]` 77 | config := NewDefaultConfig() 78 | jsn := config.NewJson([]byte(in)) 79 | cbr := config.NewCbor(make([]byte, 0, 1024)) 80 | 81 | for i := 0; i < b.N; i++ { 82 | jsn.Tocbor(cbr.Reset(nil)) 83 | } 84 | b.SetBytes(int64(len(jsn.Bytes()))) 85 | } 86 | 87 | func BenchmarkJson2CborMap(b *testing.B) { 88 | in := `{"a":null,"b":true,"c":false,"d\"":10,"e":"tru\"e", "f":[1,2]}` 89 | config := NewDefaultConfig() 90 | jsn := config.NewJson([]byte(in)) 91 | cbr := config.NewCbor(make([]byte, 0, 1024)) 92 | 93 | for i := 0; i < b.N; i++ { 94 | jsn.Tocbor(cbr.Reset(nil)) 95 | } 96 | b.SetBytes(int64(len(jsn.Bytes()))) 97 | } 98 | 99 | func BenchmarkJson2CborTyp(b *testing.B) { 100 | in := testdataFile("testdata/typical.json") 101 | config := NewDefaultConfig() 102 | jsn := config.NewJson(in) 103 | cbr := config.NewCbor(make([]byte, 0, 10*1024)) 104 | 105 | b.ResetTimer() 106 | for i := 0; i < b.N; i++ { 107 | jsn.Tocbor(cbr.Reset(nil)) 108 | } 109 | b.SetBytes(int64(len(jsn.Bytes()))) 110 | } 111 | -------------------------------------------------------------------------------- /json_collate_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "fmt" 4 | import "testing" 5 | 6 | // All test cases are folded into collate_json_test.go, contains only few 7 | // missing testcases (if any) and benchmarks. 8 | 9 | func BenchmarkJson2CollNil(b *testing.B) { 10 | config := NewDefaultConfig() 11 | jsn := config.NewJson([]byte("null")) 12 | clt := config.NewCollate(make([]byte, 0, 1024)) 13 | 14 | for i := 0; i < b.N; i++ { 15 | jsn.Tocollate(clt.Reset(nil)) 16 | } 17 | } 18 | 19 | func BenchmarkJson2CollTrue(b *testing.B) { 20 | config := NewDefaultConfig() 21 | jsn := config.NewJson([]byte("true")) 22 | clt := config.NewCollate(make([]byte, 0, 1024)) 23 | 24 | for i := 0; i < b.N; i++ { 25 | jsn.Tocollate(clt.Reset(nil)) 26 | } 27 | } 28 | 29 | func BenchmarkJson2CollFalse(b *testing.B) { 30 | config := NewDefaultConfig() 31 | jsn := config.NewJson([]byte("false")) 32 | clt := config.NewCollate(make([]byte, 0, 1024)) 33 | 34 | for i := 0; i < b.N; i++ { 35 | jsn.Tocollate(clt.Reset(nil)) 36 | } 37 | } 38 | 39 | func BenchmarkJson2CollF64(b *testing.B) { 40 | config := NewDefaultConfig() 41 | jsn := config.NewJson([]byte("10.121312213123123")) 42 | clt := config.NewCollate(make([]byte, 0, 1024)) 43 | 44 | for i := 0; i < b.N; i++ { 45 | jsn.Tocollate(clt.Reset(nil)) 46 | } 47 | } 48 | 49 | func BenchmarkJson2CollI64(b *testing.B) { 50 | config := NewDefaultConfig() 51 | jsn := config.NewJson([]byte("123456789")) 52 | clt := config.NewCollate(make([]byte, 0, 1024)) 53 | 54 | for i := 0; i < b.N; i++ { 55 | jsn.Tocollate(clt.Reset(nil)) 56 | } 57 | } 58 | 59 | func BenchmarkJson2CollMiss(b *testing.B) { 60 | inp := fmt.Sprintf(`"%s"`, MissingLiteral) 61 | 62 | config := NewDefaultConfig() 63 | jsn := config.NewJson([]byte(inp)) 64 | clt := config.NewCollate(make([]byte, 0, 1024)) 65 | 66 | for i := 0; i < b.N; i++ { 67 | jsn.Tocollate(clt.Reset(nil)) 68 | } 69 | } 70 | 71 | func BenchmarkJson2CollStr(b *testing.B) { 72 | config := NewDefaultConfig() 73 | jsn := config.NewJson([]byte(`"hello world"`)) 74 | clt := config.NewCollate(make([]byte, 0, 1024)) 75 | 76 | b.ResetTimer() 77 | for i := 0; i < b.N; i++ { 78 | jsn.Tocollate(clt.Reset(nil)) 79 | } 80 | } 81 | 82 | func BenchmarkJson2CollArr(b *testing.B) { 83 | inp := `[null,true,false,"hello world",10.23122312]` 84 | config := NewDefaultConfig() 85 | jsn := config.NewJson([]byte(inp)) 86 | clt := config.NewCollate(make([]byte, 0, 1024)) 87 | 88 | b.ResetTimer() 89 | for i := 0; i < b.N; i++ { 90 | jsn.Tocollate(clt.Reset(nil)) 91 | } 92 | } 93 | 94 | func BenchmarkJson2CollMap(b *testing.B) { 95 | inp := `{"key1":null,"key2":true,"key3":false,"key4":"hello world",` + 96 | `"key5":10.23122312}` 97 | config := NewDefaultConfig().SetMaxkeys(10) 98 | jsn := config.NewJson([]byte(inp)) 99 | clt := config.NewCollate(make([]byte, 0, 1024)) 100 | 101 | b.ResetTimer() 102 | for i := 0; i < b.N; i++ { 103 | jsn.Tocollate(clt.Reset(nil)) 104 | } 105 | } 106 | 107 | func BenchmarkJson2CollTyp(b *testing.B) { 108 | inp := testdataFile("testdata/typical.json") 109 | config := NewDefaultConfig().SetMaxkeys(100) 110 | jsn := config.NewJson(inp) 111 | clt := config.NewCollate(make([]byte, 0, 10*1024)) 112 | 113 | b.ResetTimer() 114 | for i := 0; i < b.N; i++ { 115 | jsn.Tocollate(clt.Reset(nil)) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /template/md/list-content/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[List Content Templates] 3 | 4 | ## @color[black](List Content
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/spotlight.png&position=top right&size=20% auto 14 | @title[Title + Concise List] 15 | 16 | @snap[north-west] 17 | The Agenda 18 | @snapend 19 | 20 | @snap[south-west list-content-concise span-100] 21 | @ol[list-bullets-black](false) 22 | - Lorem ipsum dolor sit amet 23 | - Consectetur adipiscing elit 24 | - Sed do eiusmod tempor 25 | - Ut enim ad minim veniam 26 | - Duis aute irure dolor in 27 | - Excepteur sint occaecat 28 | - Cupidatat non proident 29 | - Sunt in culpa qui officia 30 | @olend 31 |

32 | @snapend 33 | 34 | @snap[south-west template-note text-gray] 35 | Concise ordered list-items template. 36 | @snapend 37 | 38 | 39 | +++?image=template/img/spotlight.png&position=top right&size=20% auto 40 | @title[Title + List Fragments] 41 | 42 | @snap[north-west] 43 | The Agenda [ Step-by-Step ] 44 | @snapend 45 | 46 | @snap[south-west list-content-concise span-100] 47 | @ol 48 | - Lorem ipsum dolor sit amet 49 | - Consectetur adipiscing elit 50 | - Sed do eiusmod tempor 51 | - Ut enim ad minim veniam 52 | - Duis aute irure dolor in 53 | - Excepteur sint occaecat 54 | - Cupidatat non proident 55 | - Sunt in culpa qui officia 56 | @olend 57 |

58 | @snapend 59 | 60 | @snap[south-west template-note text-gray] 61 | Concise list-item fragments template. 62 | @snapend 63 | 64 | 65 | +++?image=template/img/spotlight.png&position=top right&size=20% auto 66 | @title[Title + Verbose List] 67 | 68 | @snap[north-west] 69 | The Key Concepts 70 | @snapend 71 | 72 | @snap[west list-content-verbose span-100] 73 |
74 | @ul[](false) 75 | - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 76 | - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 77 | - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 78 | - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 79 | @ulend 80 | @snapend 81 | 82 | @snap[south-west template-note text-gray] 83 | Verbose unordered list-items template. 84 | @snapend 85 | 86 | 87 | +++?image=template/img/spotlight.png&position=top right&size=20% auto 88 | @title[Title + List Fragments] 89 | 90 | @snap[north-west] 91 | The Key Concepts [ Step-by-Step ] 92 | @snapend 93 | 94 | @snap[west list-content-verbose span-100] 95 |
96 | @ul[list-bullets-circles] 97 | - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 98 | - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 99 | - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 100 | - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 101 | @ulend 102 | @snapend 103 | 104 | @snap[south-west template-note text-gray] 105 | Verbose list-item fragments template. 106 | @snapend 107 | -------------------------------------------------------------------------------- /value_collate.go: -------------------------------------------------------------------------------- 1 | // transform golang native value into binary collated encoding. 2 | // cnf: NumberKind, doMissing, arrayLenPrefix, propertyLenPrefix 3 | 4 | package gson 5 | 6 | import "fmt" 7 | import "strconv" 8 | import "encoding/json" 9 | 10 | func gson2collate(obj interface{}, code []byte, config *Config) int { 11 | if obj == nil { 12 | code[0], code[1] = TypeNull, Terminator 13 | return 2 14 | } 15 | 16 | switch value := obj.(type) { 17 | case bool: 18 | if value { 19 | code[0] = TypeTrue 20 | } else { 21 | code[0] = TypeFalse 22 | } 23 | code[1] = Terminator 24 | return 2 25 | 26 | case float64: 27 | n := 0 28 | code[n] = TypeNumber 29 | n++ 30 | n += collateFloat64(value, code[n:]) 31 | code[n] = Terminator 32 | n++ 33 | return n 34 | 35 | case float32: 36 | n := 0 37 | code[n] = TypeNumber 38 | n++ 39 | n += collateFloat64(float64(value), code[n:]) 40 | code[n] = Terminator 41 | n++ 42 | return n 43 | 44 | case int64: 45 | n := 0 46 | code[n] = TypeNumber 47 | n++ 48 | n += collateInt64(value, code[n:], config) 49 | code[n] = Terminator 50 | n++ 51 | return n 52 | 53 | case uint64: 54 | n := 0 55 | code[n] = TypeNumber 56 | n++ 57 | n += collateUint64(value, code[n:], config) 58 | code[n] = Terminator 59 | n++ 60 | return n 61 | 62 | case int: 63 | n := 0 64 | code[n] = TypeNumber 65 | n++ 66 | n += collateInt64(int64(value), code[n:], config) 67 | code[n] = Terminator 68 | n++ 69 | return n 70 | 71 | case json.Number: 72 | n := 0 73 | code[n] = TypeNumber 74 | n++ 75 | n += collateJsonNumber(string(value), code[n:], config) 76 | code[n] = Terminator 77 | n++ 78 | return n 79 | 80 | case Missing: 81 | if config.doMissing && MissingLiteral.Equal(string(value)) { 82 | code[0], code[1] = TypeMissing, Terminator 83 | return 2 84 | } 85 | panic("collate missing not configured") 86 | 87 | case string: 88 | return collateString(value, code, config) 89 | 90 | case []byte: 91 | n := 0 92 | code[n] = TypeBinary 93 | n++ 94 | m := copy(code[n:], value) 95 | n += m 96 | code[n] = Terminator 97 | n++ 98 | return n 99 | 100 | case []interface{}: 101 | n := 0 102 | code[n] = TypeArray 103 | n++ 104 | if config.arrayLenPrefix { 105 | n += collateLength(len(value), code[n:]) 106 | } 107 | for _, val := range value { 108 | n += gson2collate(val, code[n:], config) 109 | } 110 | code[n] = Terminator 111 | n++ 112 | return n 113 | 114 | case map[string]interface{}: 115 | n := 0 116 | code[n] = TypeObj 117 | n++ 118 | if config.propertyLenPrefix { 119 | n += collateLength(len(value), code[n:]) 120 | } 121 | 122 | mkeys := config.mkeysh.getmkeys(len(value)) 123 | 124 | for _, key := range mkeys.sortProps1(value) { 125 | n += collateString(key, code[n:], config) // encode key 126 | n += gson2collate(value[key], code[n:], config) // encode value 127 | } 128 | code[n] = Terminator 129 | n++ 130 | 131 | config.mkeysh.putmkeys(mkeys) 132 | return n 133 | } 134 | panic(fmt.Errorf("collate invalid golang type %T", obj)) 135 | } 136 | 137 | func collateLength(length int, code []byte) (n int) { 138 | var num [64]byte 139 | code[n] = TypeLength 140 | n++ 141 | bs := strconv.AppendInt(num[:0], int64(length), 10) 142 | n += collateInt(bs, code[n:]) 143 | code[n] = Terminator 144 | n++ 145 | return n 146 | } 147 | -------------------------------------------------------------------------------- /docs/references: -------------------------------------------------------------------------------- 1 | RFCs related to JSON specification 2 | ---------------------------------- 3 | 4 | 6901 JavaScript Object Notation (JSON) Pointer. P. Bryan, Ed., K. Zyp, M. 5 | Nottingham, Ed.. April 2013. (Format: TXT=13037 bytes) (Status: 6 | PROPOSED STANDARD) (DOI: 10.17487/RFC6901) 7 | 8 | 6902 JavaScript Object Notation (JSON) Patch. P. Bryan, Ed., M. 9 | Nottingham, Ed.. April 2013. (Format: TXT=26405 bytes) (Status: 10 | PROPOSED STANDARD) (DOI: 10.17487/RFC6902) 11 | 12 | 7049 Concise Binary Object Representation (CBOR). C. Bormann, P. Hoffman. 13 | October 2013. (Format: TXT=134062 bytes) (Status: PROPOSED STANDARD) 14 | (DOI: 10.17487/RFC7049) 15 | 16 | 7095 jCard: The JSON Format for vCard. P. Kewisch. January 2014. (Format: 17 | TXT=59088 bytes) (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC7095) 18 | 19 | 7159 The JavaScript Object Notation (JSON) Data Interchange Format. T. 20 | Bray, Ed.. March 2014. (Format: TXT=27451 bytes) (Obsoletes RFC4627, 21 | RFC7158) (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC7159) 22 | 23 | 7165 Use Cases and Requirements for JSON Object Signing and Encryption 24 | (JOSE). R. Barnes. April 2014. (Format: TXT=58324 bytes) (Status: 25 | INFORMATIONAL) (DOI: 10.17487/RFC7165) 26 | 27 | 7265 jCal: The JSON Format for iCalendar. P. Kewisch, C. Daboo, M. 28 | Douglass. May 2014. (Format: TXT=56274 bytes) (Updated by RFC7529) 29 | (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC7265) 30 | 31 | 7396 JSON Merge Patch. P. Hoffman, J. Snell. October 2014. (Format: 32 | TXT=12791 bytes) (Obsoletes RFC7386) (Status: PROPOSED STANDARD) 33 | (DOI: 10.17487/RFC7396) 34 | 35 | 7464 JavaScript Object Notation (JSON) Text Sequences. N. Williams. 36 | February 2015. (Format: TXT=16132 bytes) (Status: PROPOSED STANDARD) 37 | (DOI: 10.17487/RFC7464) 38 | 39 | 7485 Inventory and Analysis of WHOIS Registration Objects. L. Zhou, N. 40 | Kong, S. Shen, S. Sheng, A. Servin. March 2015. (Format: TXT=74392 41 | bytes) (Status: INFORMATIONAL) (DOI: 10.17487/RFC7485) 42 | 43 | 7493 The I-JSON Message Format. T. Bray, Ed.. March 2015. (Format: 44 | TXT=12849 bytes) (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC7493) 45 | 46 | 7515 JSON Web Signature (JWS). M. Jones, J. Bradley, N. Sakimura. May 47 | 2015. (Format: TXT=131110 bytes) (Status: PROPOSED STANDARD) (DOI: 48 | 10.17487/RFC7515) 49 | 50 | 7516 JSON Web Encryption (JWE). M. Jones, J. Hildebrand. May 2015. 51 | (Format: TXT=108322 bytes) (Status: PROPOSED STANDARD) (DOI: 52 | 10.17487/RFC7516) 53 | 54 | 7517 JSON Web Key (JWK). M. Jones. May 2015. (Format: TXT=93906 bytes) 55 | (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC7517) 56 | 57 | 7518 JSON Web Algorithms (JWA). M. Jones. May 2015. (Format: TXT=155905 58 | bytes) (Status: PROPOSED STANDARD) (DOI: 10.17487/RFC7518) 59 | 60 | 7519 JSON Web Token (JWT). M. Jones, J. Bradley, N. Sakimura. May 2015. 61 | (Format: TXT=63039 bytes) (Status: PROPOSED STANDARD) (DOI: 62 | 10.17487/RFC7519) 63 | 64 | 7520 Examples of Protecting Content Using JSON Object Signing and 65 | Encryption (JOSE). M. Miller. May 2015. (Format: TXT=198174 bytes) 66 | (Status: INFORMATIONAL) (DOI: 10.17487/RFC7520) 67 | 68 | 7523 JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and 69 | Authorization Grants. M. Jones, B. Campbell, C. Mortimore. May 2015. 70 | (Format: TXT=26459 bytes) (Status: PROPOSED STANDARD) (DOI: 71 | 10.17487/RFC7523) 72 | -------------------------------------------------------------------------------- /template/md/code-presenting/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Code Presenting Templates] 3 | 4 | ## @color[black](Code Presenting
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?code=template/src/go/server.go&lang=golang 14 | @title[Repo Source File] 15 | 16 | @[1,3-6](Present code found within any repository source file.) 17 | @[8-18](Without ever leaving your slideshow.) 18 | @[19-28](Using GitPitch code-presenting with (optional) annotations.) 19 | 20 | @snap[north-east template-note text-gray] 21 | Code presenting repository source file template. 22 | @snapend 23 | 24 | 25 | +++?color=lavender 26 | @title[Fenced Code Block] 27 | 28 | ```javascript 29 | // Include http module. 30 | var http = require("http"); 31 | 32 | // Create the server. Function passed as parameter 33 | // is called on every request made. 34 | http.createServer(function (request, response) { 35 | // Attach listener on end event. This event is 36 | // called when client sent, awaiting response. 37 | request.on("end", function () { 38 | // Write headers to the response. 39 | // HTTP 200 status, Content-Type text/plain. 40 | response.writeHead(200, { 41 | 'Content-Type': 'text/plain' 42 | }); 43 | // Send data and end response. 44 | response.end('Hello HTTP!'); 45 | }); 46 | 47 | // Listen on the 8080 port. 48 | }).listen(8080); 49 | ``` 50 | 51 | @[1,2](You can present code inlined within your slide markdown too.) 52 | @[9-17](Your code is displayed using code-syntax highlighting just like your IDE.) 53 | @[19-20](Again, all of this without ever leaving your slideshow.) 54 | 55 | @snap[north-east template-note text-gray] 56 | Code presenting fenced code block template. 57 | @snapend 58 | 59 | 60 | +++?gist=onetapbeyond/494e0fecaf0d6a2aa2acadfb8eb9d6e8&lang=scala&color=black 61 | @title[GitHub GIST] 62 | 63 | @[1-6](You can even present code found within any GitHub GIST.) 64 | @[41-53](GIST source code is beautifully rendered on any slide.) 65 | @[57-62](Code-presenting works seamlessly both online and offline.) 66 | 67 | @snap[north-east template-note text-white] 68 | Code presenting GitHub GIST template. 69 | @snapend 70 | 71 | 72 | +++?color=#36454F 73 | @title[Fenced Text Block] 74 | 75 | ```text 76 | . 77 | ├── PITCHME.md 78 | ├── PITCHME.yaml 79 | └── template 80 | ├── css 81 | │   └── PITCHME.css 82 | ├── img 83 | │   ├── batman.png 84 | │   ├── dataflow.png 85 | │   ├── developer.jpg 86 | │   └── .... 87 | └── md 88 |    ├── about/PITCHME.md 89 |    ├── announcement/PITCHME.md 90 |    ├── code-presenting/PITCHME.md 91 |    ├── header-footer/PITCHME.md 92 |    ├── image/PITCHME.md 93 |    ├── list-content/PITCHME.md 94 |    ├── quotation/PITCHME.md 95 |    ├── sidebar/PITCHME.md 96 |    ├── sidebox/PITCHME.md 97 |    ├── split-screen/PITCHME.md 98 |    └── wrap-up/PITCHME.md 99 | ``` 100 | 101 | @[1-3, 6](Code presenting can also be used to step through any text-based content.) 102 | @[4,5,7,12](Here for example we can navigate through the directory structure for this template.) 103 | @[12-23](We can see that this template uses GitPitch's cool modular markdown support @fa[smile-o fa-spin]) 104 | 105 | @snap[north-east template-note text-white] 106 | Code presenting fenced text block template. 107 | @snapend 108 | -------------------------------------------------------------------------------- /collate_cbor.go: -------------------------------------------------------------------------------- 1 | // transform binary-collated data into cbor encoding. 2 | // cnf: NumberKind, ContainerEncoding, arrayLenPrefix, propertyLenPrefix 3 | 4 | package gson 5 | 6 | //---- collate to cbor 7 | 8 | func collate2cbor(code, out []byte, config *Config) (int, int) { 9 | if len(code) == 0 { 10 | return 0, 0 11 | } 12 | var scratch [64]byte 13 | m, n := 1, 0 14 | switch code[0] { 15 | case TypeMissing: 16 | n += valtext2cbor(string(MissingLiteral), out[n:]) 17 | return m + 1, n 18 | 19 | case TypeNull: 20 | n += cborNull(out[n:]) 21 | return m + 1, n 22 | 23 | case TypeTrue: 24 | n += cborTrue(out[n:]) 25 | return m + 1, n 26 | 27 | case TypeFalse: 28 | n += cborFalse(out[n:]) 29 | return m + 1, n 30 | 31 | case TypeNumber: 32 | x := getDatum(code[m:]) 33 | // -1 is to skip terminator 34 | ui, i, f, what := collated2Number(code[m:m+x-1], config.nk) 35 | switch what { 36 | case 1: 37 | n += valuint642cbor(ui, out[n:]) 38 | case 2: 39 | n += valint642cbor(i, out[n:]) 40 | case 3: 41 | n += valfloat642cbor(f, out[n:]) 42 | } 43 | return m + x, n 44 | 45 | case TypeString: 46 | var x int 47 | 48 | bufn := config.bufferh.getbuffer(len(code[m:]) * 5) 49 | scratch := bufn.data 50 | scratch, x = collate2String(code[m:], scratch[:]) 51 | n += valtext2cbor(bytes2str(scratch), out[n:]) 52 | config.bufferh.putbuffer(bufn) 53 | return m + x, n 54 | 55 | case TypeBinary: 56 | x := getDatum(code[m:]) 57 | n += valbytes2cbor(code[m:m+x-1], out[n:]) 58 | return m + x, n 59 | 60 | case TypeArray: 61 | if config.arrayLenPrefix { 62 | if code[m] != TypeLength { 63 | panic("collate decode expected array length prefix") 64 | } 65 | x := getDatum(code[m:]) 66 | // -1 skip terminator 67 | collated2Int(code[m:m+x-1], scratch[:]) // skip length 68 | m += x 69 | } 70 | nn, nnn := n, n 71 | if config.ct == LengthPrefix { 72 | nn, nnn = n+32, n+32 73 | } else if config.ct == Stream { 74 | nnn += arrayStart(out[nnn:]) 75 | } 76 | ln := 0 77 | for code[m] != Terminator { 78 | x, y := collate2cbor(code[m:], out[nnn:], config) 79 | m, nnn = m+x, nnn+y 80 | ln++ 81 | } 82 | if config.ct == LengthPrefix { 83 | x := valuint642cbor(uint64(ln), out[n:]) 84 | out[n] = (out[n] & 0x1f) | cborType4 // fix type from type0->type4 85 | n += x 86 | n += copy(out[n:], out[nn:nnn]) 87 | } else if config.ct == Stream { 88 | nnn += breakStop(out[nnn:]) 89 | n = nnn 90 | } 91 | return m + 1, n 92 | 93 | case TypeObj: 94 | if config.propertyLenPrefix { 95 | if code[m] != TypeLength { 96 | panic("collate decode expected property length prefix") 97 | } 98 | x := getDatum(code[m:]) 99 | // -1 skip terminator 100 | collated2Int(code[m:m+x-1], scratch[:]) // skip length 101 | m += x 102 | } 103 | nn, nnn := n, n 104 | if config.ct == LengthPrefix { 105 | nn, nnn = n+32, n+32 106 | } else if config.ct == Stream { 107 | nnn += mapStart(out[nnn:]) 108 | } 109 | 110 | ln := 0 111 | for code[m] != Terminator { 112 | x, y := collate2cbor(code[m:], out[nnn:], config) 113 | m, nnn = m+x, nnn+y 114 | x, y = collate2cbor(code[m:], out[nnn:], config) 115 | m, nnn = m+x, nnn+y 116 | ln++ 117 | } 118 | if config.ct == LengthPrefix { 119 | x := valuint642cbor(uint64(ln), out[n:]) 120 | out[n] = (out[n] & 0x1f) | cborType5 // fix type from type0->type5 121 | n += x 122 | n += copy(out[n:], out[nn:nnn]) 123 | } else if config.ct == Stream { 124 | nnn += breakStop(out[nnn:]) 125 | n = nnn 126 | } 127 | return m + 1, n 128 | } 129 | panic("collate decode to cbor invalid binary") 130 | } 131 | -------------------------------------------------------------------------------- /template/md/split-screen/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Split-Screen Templates] 3 | 4 | ## @color[black](Split-Screen
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | +++?image=template/img/bg/orange.jpg&position=right&size=50% 100% 13 | @title[Heading + List Body] 14 | 15 | @snap[west split-screen-heading text-orange span-50] 16 | Topics to be covered today 17 | @snapend 18 | 19 | @snap[east text-white span-45] 20 | @ol[split-screen-list](false) 21 | - Lorem ipsum dolor sit amet, consectetur elit 22 | - Ut enim ad minim veniam, quis exercitation 23 | - Duis aute irure dolor in reprehenderit in voluptate 24 | @olend 25 | @snapend 26 | 27 | @snap[south-west template-note text-gray] 28 | Split-screen heading and list body template. 29 | @snapend 30 | 31 | 32 | +++?image=template/img/bg/pink.jpg&position=left&size=70% 100% 33 | @title[Heading + List Body] 34 | 35 | @snap[east split-screen-heading text-pink span-50] 36 | Top
Tips! 37 | @snapend 38 | 39 | @snap[west text-white span-65] 40 | @ul[split-screen-list](false) 41 | - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore 42 | - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 43 | - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore 44 | - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id 45 | @ulend 46 | @snapend 47 | 48 | @snap[south-west template-note text-white] 49 | Split-screen heading and list body template. 50 | @snapend 51 | 52 | 53 | +++?image=template/img/bg/black.jpg&position=right&size=50% 100% 54 | @title[Text + Image] 55 | 56 | @snap[east split-screen-byline text-white] 57 | Lorem ipsum sit dolor amet, consectetur elit. 58 | @snapend 59 | 60 | @snap[west split-screen-img] 61 | ![DEVELOPER](template/img/developer.jpg) 62 | @snapend 63 | 64 | @snap[south-west template-note text-gray] 65 | Split-screen text and image template. 66 | @snapend 67 | 68 | 69 | +++?image=template/img/bg/green.jpg&position=left&size=50% 100% 70 | @title[Text + Image Fragment] 71 | 72 | @snap[west split-screen-byline text-white] 73 | Lorem ipsum sit dolor amet, consectetur elit. 74 | @snapend 75 | 76 | @snap[east split-screen-img fragment] 77 | ![DEVELOPER](template/img/developer.jpg) 78 | @snapend 79 | 80 | @snap[south-west template-note text-white] 81 | Split-screen text and image-fragment template. 82 | @snapend 83 | 84 | 85 | +++?image=template/img/bg/black.jpg&position=left&size=50% 100% 86 | @title[Text + Image Centered] 87 | 88 | @snap[west split-screen-byline text-white] 89 | Lorem ipsum
sit dolor amet, consectetur elit. 90 | @snapend 91 | 92 | @snap[midpoint split-screen-img] 93 | ![DEVELOPER](template/img/developer.jpg) 94 | @snapend 95 | 96 | @snap[east split-screen-text text-black] 97 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 98 | @snapend 99 | 100 | @snap[south-west template-note text-white] 101 | Split-screen text and centered image template. 102 | @snapend 103 | 104 | 105 | +++?image=template/img/bg/pink.jpg&position=right&size=50% 100% 106 | @title[Text + Image Centered] 107 | 108 | @snap[east split-screen-text text-white] 109 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 110 | @snapend 111 | 112 | @snap[midpoint split-screen-img] 113 | ![DEVELOPER](template/img/developer.jpg) 114 | @snapend 115 | 116 | @snap[west split-screen-byline] 117 | Lorem ipsum
sit dolor amet, consectetur elit. 118 | @snapend 119 | 120 | @snap[south-west template-note text-gray] 121 | Split-screen text and centered image template. 122 | @snapend 123 | -------------------------------------------------------------------------------- /template/md/wrap-up/PITCHME.md: -------------------------------------------------------------------------------- 1 | ---?image=template/img/pencils.jpg 2 | @title[Wrap-Up Templates] 3 | 4 | ## @color[black](Wrap-Up
Slide Templates) 5 | 6 | @fa[arrow-down text-black] 7 | 8 | @snap[south docslink span-50] 9 | [The Template Docs](https://gitpitch.com/docs/the-template) 10 | @snapend 11 | 12 | 13 | +++?image=template/img/questions-1.png&size=80% auto 14 | @title[Questions #1] 15 | 16 | @snap[south-west template-note text-gray] 17 | Audience questions template. 18 | @snapend 19 | 20 | 21 | +++?image=template/img/questions-2.png&size=80% auto 22 | @title[Questions #2] 23 | 24 | @snap[south-west template-note text-gray] 25 | Audience questions template. 26 | @snapend 27 | 28 | 29 | +++?image=template/img/questions-3.png&size=auto 60% 30 | @title[Questions #3] 31 | 32 | @snap[south-west template-note text-gray] 33 | Audience questions template. 34 | @snapend 35 | 36 | 37 | +++ 38 | @title[Questions #4] 39 | 40 | @snap[east span-50] 41 | ![QUESTIONS-4](template/img/questions-4.png) 42 | @snapend 43 | 44 | @snap[south-west template-note text-gray] 45 | Audience questions template. 46 | @snapend 47 | 48 | 49 | +++?color=white 50 | @title[Get In Touch #1] 51 | 52 | @snap[west] 53 | @css[contact-name](Wendy Sesay)
54 | @fa[twitter-square text-blue pad-right-icon]@css[twitter-handle text-blue](@wendy)
55 | @fa[envelope-o text-pink pad-right-icon]@css[contact-email text-pink](wendy@gmail.com) 56 |
57 |
58 | @css[contact-name](Abby Bauer)
59 | @fa[twitter-square text-blue pad-right-icon]@css[twitter-handle text-blue](@abbycode)
60 | @fa[github-square pad-right-icon]@css[git-handle](abbycode)
61 | @fa[envelope-o text-pink pad-right-icon]@css[contact-email text-pink](abcode@hotmail.com) 62 |
63 |
64 | @css[contact-name](Berry Nguyen)
65 | @fa[twitter-square text-blue pad-right-icon]@css[twitter-handle text-blue](@BerryNgu)
66 | @fa[envelope-o text-pink pad-right-icon]@css[contact-email text-pink](B.Nguyen@gmail.com) 67 | @snapend 68 | 69 | @snap[east] 70 |

Contact Us

71 | @snapend 72 | 73 | @snap[north-east template-note text-gray] 74 | Contact info template. 75 | @snapend 76 | 77 | 78 | +++?color=#ED7D31 79 | @title[Get In Touch #2] 80 | 81 | @snap[east] 82 | @css[contact-name](Wendy Sesay)
83 | @css[twitter-handle text-white](@wendy) 84 | @fa[twitter-square text-white pad-left-icon]
85 | @css[contact-email text-white](wendy@gmail.com) 86 | @fa[envelope-o text-white pad-left-icon]
87 |
88 | @css[contact-name](Abby Bauer)
89 | @css[twitter-handle text-white](@abbycode)@fa[twitter-square text-white pad-left-icon]
90 | @css[git-handle text-white](abbycode)@fa[github-square text-white pad-left-icon]
91 | @css[contact-email text-white](abcode@hotmail.com)@fa[envelope-o text-white pad-left-icon]
92 |
93 | @css[contact-name](Berry Nguyen)
94 | @css[twitter-handle text-white](@BerryNgu)@fa[twitter-square text-white pad-left-icon]
95 | @css[contact-email text-white](B.Nguyen@gmail.com)@fa[envelope-o text-white pad-left-icon]
96 | @snapend 97 | 98 | @snap[west span-50] 99 | ![CONTACT-2](template/img/contact-2.png) 100 | @snapend 101 | 102 | @snap[north-west text-white template-note] 103 | Contact info template. 104 | @snapend 105 | 106 | 107 | +++ 108 | @title[Get In Touch #3] 109 | 110 | @snap[west contact-links] 111 | @css[contact-name](David Russell)
112 | 113 | @fa[twitter-square pad-right-icon]@css[twitter-handle](@gitpitch) 114 |
115 | 116 | @fa[github-square pad-right-icon]@css[git-handle](gitpitch) 117 |
118 | 119 | @fa[envelope-o pad-right-icon]@css[contact-email](david@gitpitch.com) 120 | 121 | @snapend 122 | 123 | @snap[east span-50] 124 | ![](template/img/contact-1.png) 125 | @snapend 126 | 127 | @snap[north-east template-note text-gray] 128 | Contact info template. 129 | @snapend 130 | 131 | -------------------------------------------------------------------------------- /cbor_collate_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "fmt" 4 | import "testing" 5 | 6 | // All test cases are folded into collate_cbor_test.go, contains only few 7 | // missing testcases (if any) and benchmarks. 8 | 9 | func BenchmarkCbor2CollNil(b *testing.B) { 10 | config := NewDefaultConfig() 11 | jsn := config.NewJson([]byte("null")) 12 | cbr := config.NewCbor(make([]byte, 0, 1024)) 13 | clt := config.NewCollate(make([]byte, 0, 1024)) 14 | 15 | jsn.Tocbor(cbr) 16 | 17 | for i := 0; i < b.N; i++ { 18 | cbr.Tocollate(clt.Reset(nil)) 19 | } 20 | } 21 | 22 | func BenchmarkCbor2CollTrue(b *testing.B) { 23 | config := NewDefaultConfig() 24 | jsn := config.NewJson([]byte("true")) 25 | cbr := config.NewCbor(make([]byte, 0, 1024)) 26 | clt := config.NewCollate(make([]byte, 0, 1024)) 27 | 28 | jsn.Tocbor(cbr) 29 | 30 | for i := 0; i < b.N; i++ { 31 | cbr.Tocollate(clt.Reset(nil)) 32 | } 33 | } 34 | 35 | func BenchmarkCbor2CollFalse(b *testing.B) { 36 | config := NewDefaultConfig() 37 | jsn := config.NewJson([]byte("false")) 38 | cbr := config.NewCbor(make([]byte, 0, 1024)) 39 | clt := config.NewCollate(make([]byte, 0, 1024)) 40 | 41 | jsn.Tocbor(cbr) 42 | 43 | for i := 0; i < b.N; i++ { 44 | cbr.Tocollate(clt.Reset(nil)) 45 | } 46 | } 47 | 48 | func BenchmarkCbor2CollF64(b *testing.B) { 49 | config := NewDefaultConfig() 50 | jsn := config.NewJson([]byte("10.121312213123123")) 51 | cbr := config.NewCbor(make([]byte, 0, 1024)) 52 | clt := config.NewCollate(make([]byte, 0, 1024)) 53 | 54 | jsn.Tocbor(cbr) 55 | 56 | for i := 0; i < b.N; i++ { 57 | cbr.Tocollate(clt.Reset(nil)) 58 | } 59 | } 60 | 61 | func BenchmarkCbor2CollI64(b *testing.B) { 62 | config := NewDefaultConfig() 63 | jsn := config.NewJson([]byte("123456789")) 64 | cbr := config.NewCbor(make([]byte, 0, 1024)) 65 | clt := config.NewCollate(make([]byte, 0, 1024)) 66 | 67 | jsn.Tocbor(cbr) 68 | 69 | for i := 0; i < b.N; i++ { 70 | cbr.Tocollate(clt.Reset(nil)) 71 | } 72 | } 73 | 74 | func BenchmarkCbor2CollMiss(b *testing.B) { 75 | config := NewDefaultConfig() 76 | jsn := config.NewJson([]byte(fmt.Sprintf(`"%s"`, MissingLiteral))) 77 | cbr := config.NewCbor(make([]byte, 0, 1024)) 78 | clt := config.NewCollate(make([]byte, 0, 1024)) 79 | 80 | jsn.Tocbor(cbr) 81 | 82 | for i := 0; i < b.N; i++ { 83 | cbr.Tocollate(clt.Reset(nil)) 84 | } 85 | } 86 | 87 | func BenchmarkCbor2CollStr(b *testing.B) { 88 | config := NewDefaultConfig() 89 | jsn := config.NewJson([]byte(`"hello world"`)) 90 | cbr := config.NewCbor(make([]byte, 0, 1024)) 91 | clt := config.NewCollate(make([]byte, 0, 1024)) 92 | 93 | jsn.Tocbor(cbr) 94 | 95 | for i := 0; i < b.N; i++ { 96 | cbr.Tocollate(clt.Reset(nil)) 97 | } 98 | } 99 | 100 | func BenchmarkCbor2CollArr(b *testing.B) { 101 | in := []byte(`[null,true,false,"hello world",10.23122312]`) 102 | 103 | config := NewDefaultConfig() 104 | jsn := config.NewJson(in) 105 | cbr := config.NewCbor(make([]byte, 0, 1024)) 106 | clt := config.NewCollate(make([]byte, 0, 1024)) 107 | 108 | jsn.Tocbor(cbr) 109 | 110 | for i := 0; i < b.N; i++ { 111 | cbr.Tocollate(clt.Reset(nil)) 112 | } 113 | } 114 | 115 | func BenchmarkCbor2CollMap(b *testing.B) { 116 | inp := `{"key1":null,"key2":true,"key3":false,"key4":"hello world",` + 117 | `"key5":10.23122312}` 118 | config := NewDefaultConfig().SetMaxkeys(10) 119 | jsn := config.NewJson([]byte(inp)) 120 | cbr := config.NewCbor(make([]byte, 0, 1024)) 121 | clt := config.NewCollate(make([]byte, 0, 1024)) 122 | 123 | jsn.Tocbor(cbr) 124 | 125 | for i := 0; i < b.N; i++ { 126 | cbr.Tocollate(clt.Reset(nil)) 127 | } 128 | } 129 | 130 | func BenchmarkCbor2CollTyp(b *testing.B) { 131 | data := testdataFile("testdata/typical.json") 132 | 133 | config := NewDefaultConfig().SetMaxkeys(100) 134 | jsn := config.NewJson(data) 135 | cbr := config.NewCbor(make([]byte, 0, 10*1024)) 136 | clt := config.NewCollate(make([]byte, 0, 10*1024)) 137 | 138 | jsn.Tocbor(cbr) 139 | 140 | for i := 0; i < b.N; i++ { 141 | cbr.Tocollate(clt.Reset(nil)) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /json_scanner.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "unicode" 4 | import "unicode/utf8" 5 | import "unicode/utf16" 6 | import "strconv" 7 | 8 | var spaceCode = [256]byte{ 9 | '\t': 1, 10 | '\n': 1, 11 | '\v': 1, 12 | '\f': 1, 13 | '\r': 1, 14 | ' ': 1, 15 | } 16 | 17 | func skipWS(txt string, ws SpaceKind) string { 18 | switch ws { 19 | case UnicodeSpace: 20 | for i, ch := range txt { 21 | if unicode.IsSpace(ch) { 22 | continue 23 | } 24 | return txt[i:] 25 | } 26 | return "" 27 | 28 | case AnsiSpace: 29 | i := 0 30 | for i < len(txt) && spaceCode[txt[i]] == 1 { 31 | i++ 32 | } 33 | txt = txt[i:] 34 | } 35 | return txt 36 | } 37 | 38 | var escapeCode = [256]byte{ 39 | '"': '"', 40 | '\\': '\\', 41 | '/': '/', 42 | '\'': '\'', 43 | 'b': '\b', 44 | 'f': '\f', 45 | 'n': '\n', 46 | 'r': '\r', 47 | 't': '\t', 48 | } 49 | 50 | func scanString(txt string, out []byte) (string, int) { 51 | if len(txt) < 2 { 52 | panic("scanner expectedString") 53 | } 54 | 55 | e := 1 56 | for txt[e] != '"' { 57 | c := txt[e] 58 | if c == '\\' || c == '"' || c < ' ' { 59 | break 60 | } 61 | if c < utf8.RuneSelf { 62 | e++ 63 | continue 64 | } 65 | r, size := utf8.DecodeRuneInString(txt[e:]) 66 | if r == utf8.RuneError && size == 1 { 67 | break 68 | } 69 | e += size 70 | if e == len(txt) { 71 | panic("scanner expectedString") 72 | } 73 | } 74 | 75 | if txt[e] == '"' { // done we have nothing to unquote 76 | return txt[e+1:], copy(out, txt[1:e]) 77 | } 78 | 79 | oute := copy(out, txt[1:e]) // copy so far 80 | 81 | loop: 82 | for e < len(txt) { 83 | switch c := txt[e]; { 84 | case c == '"': 85 | out[oute] = c 86 | e++ 87 | break loop 88 | 89 | case c == '\\': 90 | if txt[e+1] == 'u' { 91 | r := getu4(txt[e:]) 92 | if r < 0 { // invalid 93 | panic("scanner expectedString") 94 | } 95 | e += 6 96 | if utf16.IsSurrogate(r) { 97 | nextr := getu4(txt[e:]) 98 | dec := utf16.DecodeRune(r, nextr) 99 | if dec != unicode.ReplacementChar { // A valid pair consume 100 | oute += utf8.EncodeRune(out[oute:], dec) 101 | e += 6 102 | break loop 103 | } 104 | // Invalid surrogate; fall back to replacement rune. 105 | r = unicode.ReplacementChar 106 | } 107 | oute += utf8.EncodeRune(out[oute:], r) 108 | 109 | } else { // escaped with " \ / ' b f n r t 110 | out[oute] = escapeCode[txt[e+1]] 111 | e += 2 112 | oute++ 113 | } 114 | 115 | case c < ' ': // control character is invalid 116 | panic("scanner expectedString") 117 | 118 | case c < utf8.RuneSelf: // ASCII 119 | out[oute] = c 120 | oute++ 121 | e++ 122 | 123 | default: // coerce to well-formed UTF-8 124 | r, size := utf8.DecodeRuneInString(txt[e:]) 125 | e += size 126 | oute += utf8.EncodeRune(out[oute:], r) 127 | } 128 | } 129 | 130 | if out[oute] == '"' { 131 | return txt[e:], oute 132 | } 133 | panic("scanner expectedString") 134 | } 135 | 136 | // getu4 decodes \uXXXX from the beginning of s, returning the hex value, 137 | // or it returns -1. 138 | func getu4(s string) rune { 139 | if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { 140 | return -1 141 | } 142 | r, err := strconv.ParseUint(s[2:6], 16, 64) 143 | if err != nil { 144 | return -1 145 | } 146 | return rune(r) 147 | } 148 | 149 | var intCheck = [256]byte{} 150 | var digitCheck = [256]byte{} 151 | var numCheck = [256]byte{} 152 | var fltCheck = [256]byte{} 153 | 154 | func init() { 155 | for i := 48; i <= 57; i++ { 156 | intCheck[i] = 1 157 | numCheck[i] = 1 158 | } 159 | intCheck['-'] = 1 160 | intCheck['+'] = 1 161 | intCheck['.'] = 1 162 | intCheck['e'] = 1 163 | intCheck['E'] = 1 164 | 165 | numCheck['-'] = 1 166 | numCheck['+'] = 1 167 | numCheck['.'] = 1 168 | 169 | fltCheck['.'] = 1 170 | fltCheck['e'] = 1 171 | fltCheck['E'] = 1 172 | 173 | for i := 48; i <= 57; i++ { 174 | digitCheck[i] = 1 175 | } 176 | digitCheck['-'] = 1 177 | digitCheck['+'] = 1 178 | digitCheck['.'] = 1 179 | } 180 | -------------------------------------------------------------------------------- /json_value.go: -------------------------------------------------------------------------------- 1 | // transform json encoded data into golang native value. 2 | // cnf: SpaceKind, NumberKind, strict 3 | 4 | package gson 5 | 6 | import "strconv" 7 | 8 | // primary interface to scan JSON text and return, 9 | // a. text remaining to be parsed. 10 | // b. as go-native value. 11 | // calling this function will scan for exactly one JSON value 12 | func json2value(txt string, config *Config) (string, interface{}) { 13 | txt = skipWS(txt, config.ws) 14 | 15 | if len(txt) < 1 { 16 | panic("gson scanner jsonEmpty") 17 | } 18 | 19 | if digitCheck[txt[0]] == 1 { 20 | return jsonnum2value(txt, config) 21 | } 22 | 23 | switch txt[0] { 24 | case 'n': 25 | if len(txt) >= 4 && txt[:4] == "null" { 26 | return txt[4:], nil 27 | } 28 | panic("gson scanner expectedNil") 29 | 30 | case 't': 31 | if len(txt) >= 4 && txt[:4] == "true" { 32 | return txt[4:], true 33 | } 34 | panic("gson scanner expectedTrue") 35 | 36 | case 'f': 37 | if len(txt) >= 5 && txt[:5] == "false" { 38 | return txt[5:], false 39 | } 40 | panic("gson scanner expectedFalse") 41 | 42 | case '"': 43 | bufn := config.bufferh.getbuffer(len(txt) * 5) 44 | scratch := bufn.data 45 | remtxt, n := scanString(txt, scratch) 46 | value := string(scratch[:n]) // this will copy the content. 47 | config.bufferh.putbuffer(bufn) 48 | return remtxt, value 49 | 50 | case '[': 51 | if txt = skipWS(txt[1:], config.ws); len(txt) == 0 { 52 | panic("gson scanner expectedCloseArray") 53 | } else if txt[0] == ']' { 54 | return txt[1:], []interface{}{} 55 | } 56 | arr := make([]interface{}, 0, 4) 57 | for { 58 | var tok interface{} 59 | txt, tok = json2value(txt, config) 60 | arr = append(arr, tok) 61 | if txt = skipWS(txt, config.ws); len(txt) == 0 { 62 | panic("gson scanner expectedCloseArray") 63 | } else if txt[0] == ',' { 64 | txt = skipWS(txt[1:], config.ws) 65 | } else if txt[0] == ']' { 66 | break 67 | } else { 68 | panic("gson scanner expectedCloseArray") 69 | } 70 | } 71 | return txt[1:], arr 72 | 73 | case '{': 74 | if txt = skipWS(txt[1:], config.ws); len(txt) == 0 { 75 | panic("gson scanner expectedCloseobject") 76 | } else if txt[0] == '}' { 77 | return txt[1:], map[string]interface{}{} 78 | } else if txt[0] != '"' { 79 | panic("gson scanner expectedKey") 80 | } 81 | 82 | var tok interface{} 83 | var n int 84 | 85 | m := make(map[string]interface{}) 86 | bufn := config.bufferh.getbuffer(len(txt) * 5) 87 | scratch := bufn.data 88 | for { 89 | txt, n = scanString(txt, scratch) // empty string is also valid key 90 | key := string(scratch[:n]) 91 | 92 | if txt = skipWS(txt, config.ws); len(txt) == 0 || txt[0] != ':' { 93 | panic("gson scanner expectedColon") 94 | } 95 | txt, tok = json2value(skipWS(txt[1:], config.ws), config) 96 | m[key] = tok 97 | if txt = skipWS(txt, config.ws); len(txt) == 0 { 98 | panic("gson scanner expectedCloseobject") 99 | } else if txt[0] == ',' { 100 | txt = skipWS(txt[1:], config.ws) 101 | } else if txt[0] == '}' { 102 | break 103 | } else { 104 | panic("gson scanner expectedCloseobject") 105 | } 106 | } 107 | config.bufferh.putbuffer(bufn) 108 | return txt[1:], m 109 | } 110 | panic("gson scanner expectedToken") 111 | } 112 | 113 | func jsonnum2value(txt string, config *Config) (string, interface{}) { 114 | s, e, l := 0, 1, len(txt) 115 | if len(txt) > 1 { 116 | for ; e < l && intCheck[txt[e]] == 1; e++ { 117 | } 118 | } 119 | 120 | switch config.nk { 121 | case FloatNumber: 122 | f, err := strconv.ParseFloat(txt[s:e], 64) 123 | if err != nil { 124 | panic(err) 125 | } 126 | return txt[e:], f 127 | 128 | case SmartNumber: 129 | if i, err := strconv.ParseInt(txt[s:e], 10, 64); err == nil { 130 | return txt[e:], i 131 | } else if ui, err := strconv.ParseUint(txt[s:e], 10, 64); err == nil { 132 | return txt[e:], ui 133 | } 134 | f, err := strconv.ParseFloat(txt[s:e], 64) 135 | if err != nil { 136 | panic(err) 137 | } 138 | return txt[e:], f 139 | } 140 | panic("unreachable code") 141 | } 142 | -------------------------------------------------------------------------------- /value_json.go: -------------------------------------------------------------------------------- 1 | // transform golang native value into json encoded value. 2 | // cnf: - 3 | 4 | package gson 5 | 6 | import "fmt" 7 | import "strconv" 8 | import "encoding/json" 9 | 10 | func value2json(value interface{}, out []byte, config *Config) int { 11 | var err error 12 | var outsl []byte 13 | 14 | if value == nil { 15 | return copy(out, "null") 16 | } 17 | 18 | switch v := value.(type) { 19 | case bool: 20 | if v { 21 | return copy(out, "true") 22 | } 23 | return copy(out, "false") 24 | 25 | case byte: 26 | out = strconv.AppendInt(out[:0], int64(v), 10) 27 | return len(out) 28 | 29 | case int8: 30 | out = strconv.AppendInt(out[:0], int64(v), 10) 31 | return len(out) 32 | 33 | case int16: 34 | out = strconv.AppendInt(out[:0], int64(v), 10) 35 | return len(out) 36 | 37 | case uint16: 38 | out = strconv.AppendInt(out[:0], int64(v), 10) 39 | return len(out) 40 | 41 | case int32: 42 | out = strconv.AppendInt(out[:0], int64(v), 10) 43 | return len(out) 44 | 45 | case uint32: 46 | out = strconv.AppendInt(out[:0], int64(v), 10) 47 | return len(out) 48 | 49 | case int: 50 | out = strconv.AppendFloat(out[:0], float64(v), 'f', -1, 64) 51 | return len(out) 52 | 53 | case uint: 54 | out = strconv.AppendFloat(out[:0], float64(v), 'f', -1, 64) 55 | return len(out) 56 | 57 | case int64: 58 | switch config.nk { 59 | case FloatNumber: 60 | out = strconv.AppendFloat(out[:0], float64(v), 'f', -1, 64) 61 | case SmartNumber: 62 | out = strconv.AppendInt(out[:0], v, 10) 63 | default: 64 | panic(fmt.Errorf("unknown number kind %v", config.nk)) 65 | } 66 | return len(out) 67 | 68 | case uint64: 69 | switch config.nk { 70 | case FloatNumber: 71 | out = strconv.AppendFloat(out[:0], float64(v), 'f', -1, 64) 72 | case SmartNumber: 73 | out = strconv.AppendUint(out[:0], v, 10) 74 | default: 75 | panic(fmt.Errorf("unknown number kind %v", config.nk)) 76 | } 77 | return len(out) 78 | 79 | case float32: 80 | out = strconv.AppendFloat(out[:0], float64(v), 'f', -1, 64) 81 | return len(out) 82 | 83 | case float64: 84 | out = strconv.AppendFloat(out[:0], v, 'f', -1, 64) 85 | return len(out) 86 | 87 | case string: 88 | out, err = encodeString(str2bytes(v), out[:0]) 89 | if err != nil { 90 | panic("error encoding string") 91 | } 92 | return len(out) 93 | 94 | case json.Number: 95 | return copy(out, v) 96 | 97 | case []interface{}: 98 | n := 0 99 | out[n] = '[' 100 | n++ 101 | for i, x := range v { 102 | n += value2json(x, out[n:], config) 103 | if i < len(v)-1 { 104 | out[n] = ',' 105 | n++ 106 | } 107 | } 108 | out[n] = ']' 109 | n++ 110 | return n 111 | 112 | case map[string]interface{}: 113 | n := 0 114 | out[n] = '{' 115 | n++ 116 | 117 | mkeys := config.mkeysh.getmkeys(len(v)) 118 | 119 | count := len(v) 120 | for _, key := range mkeys.sortProps1(v) { 121 | outsl, err = encodeString(str2bytes(key), out[n:n]) 122 | if err != nil { 123 | panic("error encoding key") 124 | } 125 | n += len(outsl) 126 | out[n] = ':' 127 | n++ 128 | 129 | n += value2json(v[key], out[n:], config) 130 | 131 | count-- 132 | if count > 0 { 133 | out[n] = ',' 134 | n++ 135 | } 136 | } 137 | out[n] = '}' 138 | n++ 139 | 140 | config.mkeysh.putmkeys(mkeys) 141 | return n 142 | 143 | case map[string]uint64: 144 | n := 0 145 | out[n] = '{' 146 | n++ 147 | 148 | mkeys := config.mkeysh.getmkeys(len(v)) 149 | 150 | count := len(v) 151 | for _, key := range mkeys.sortProps2(v) { 152 | outsl, err = encodeString(str2bytes(key), out[n:n]) 153 | if err != nil { 154 | panic("error encoding key") 155 | } 156 | n += len(outsl) 157 | out[n] = ':' 158 | n++ 159 | 160 | n += value2json(v[key], out[n:], config) 161 | 162 | count-- 163 | if count > 0 { 164 | out[n] = ',' 165 | n++ 166 | } 167 | } 168 | out[n] = '}' 169 | n++ 170 | 171 | config.mkeysh.putmkeys(mkeys) 172 | return n 173 | 174 | case [][2]interface{}: 175 | n := 0 176 | out[n] = '{' 177 | n++ 178 | 179 | for i, item := range v { 180 | n += value2json(item[0], out[n:], config) 181 | out[n] = ':' 182 | n++ 183 | 184 | n += value2json(item[1], out[n:], config) 185 | 186 | if i < len(v)-1 { 187 | out[n] = ',' 188 | n++ 189 | } 190 | } 191 | out[n] = '}' 192 | n++ 193 | return n 194 | } 195 | return 0 196 | } 197 | -------------------------------------------------------------------------------- /lookup_value.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "strconv" 4 | import "fmt" 5 | 6 | func valGet(segments [][]byte, doc interface{}) interface{} { 7 | if len(segments) == 0 { // exit recursion. 8 | return doc 9 | } 10 | 11 | segment := bytes2str(segments[0]) 12 | 13 | switch val := doc.(type) { 14 | case []interface{}: 15 | if segment == "-" { // not req. as per rfc-6901 16 | return valGet(segments[1:], val[len(val)-1]) 17 | } else if idx, err := strconv.Atoi(segment); err != nil { 18 | panic("valGet(): gson pointer-invalidIndex") 19 | } else if idx >= len(val) { 20 | panic("valGet(): gson pointer-index-outofRange") 21 | } else { 22 | return valGet(segments[1:], val[idx]) 23 | } 24 | 25 | case map[string]interface{}: 26 | if doc, ok := val[segment]; !ok { 27 | panic(fmt.Sprintf("valGet(): gson %v pointer-invalidKey", segment)) 28 | } else { 29 | return valGet(segments[1:], doc) 30 | } 31 | } 32 | panic("valGet(): gson invalidPointer") 33 | } 34 | 35 | func valSet(segments [][]byte, doc, item interface{}) (newdoc, old interface{}) { 36 | ln, container := len(segments), doc 37 | if ln == 0 { 38 | panic("valSet(): document is not a container") 39 | } else if ln > 1 { 40 | container = valGet(segments[:ln-1], doc) 41 | } // else if ln == 1, container _is_ doc 42 | 43 | var ok bool 44 | switch cont := container.(type) { 45 | case []interface{}: 46 | key := bytes2str(segments[ln-1]) 47 | if key == "-" { 48 | old, cont[len(cont)-1] = cont[len(cont)-1], item 49 | if ln > 1 { 50 | doc, _ = valSet(segments[:ln-1], doc, cont) 51 | } else { // edge case ! 52 | doc = cont 53 | } 54 | } else if idx, err := strconv.Atoi(key); err != nil { 55 | panic("valSet(): gson pointer-invalidIndex") 56 | } else if idx >= len(cont) { 57 | panic("valSet(): gson pointer-outofRange") 58 | } else { 59 | old, cont[idx] = cont[idx], item 60 | } 61 | 62 | case map[string]interface{}: 63 | key := string(segments[ln-1]) 64 | if old, ok = cont[key]; !ok { 65 | old = item 66 | } 67 | cont[key] = item 68 | default: 69 | panic("valSet(): gson invalidPointer") 70 | } 71 | return doc, old 72 | } 73 | 74 | func valDel(segments [][]byte, doc interface{}) (newdoc, old interface{}) { 75 | ln, container := len(segments), doc 76 | if ln == 0 { 77 | panic("valDel(): document is not a container") 78 | } else if ln > 1 { 79 | container = valGet(segments[:ln-1], doc) 80 | } // else if ln == 1, container _is_ doc 81 | 82 | key := bytes2str(segments[ln-1]) 83 | 84 | switch cont := container.(type) { 85 | case []interface{}: 86 | if idx, err := strconv.Atoi(key); err != nil { 87 | fmsg := fmt.Errorf("valDel(): gson pointer-invalidIndex `%v`", err) 88 | panic(fmsg) 89 | } else if idx >= len(cont) { 90 | panic("valDel(): gson pointer-outofRange") 91 | } else { 92 | old = cont[idx] 93 | copy(cont[idx:], cont[idx+1:]) 94 | cont = cont[:len(cont)-1] 95 | if ln > 1 { 96 | doc, _ = valSet(segments[:ln-1], doc, cont) 97 | return doc, old 98 | } 99 | // edge case !! 100 | return cont, old 101 | } 102 | 103 | case map[string]interface{}: 104 | old, _ = cont[key] 105 | delete(cont, key) 106 | 107 | default: 108 | panic("valDel(): gson invalidPointer") 109 | } 110 | return doc, old 111 | } 112 | 113 | func valAppend(segments [][]byte, doc, item interface{}) (newdoc interface{}) { 114 | container := doc 115 | if len(segments) > 0 { 116 | container = valGet(segments, doc) 117 | } // else if ln == 1, container _is_ doc 118 | 119 | switch cont := container.(type) { 120 | case []interface{}: 121 | cont = append(cont, item) 122 | if len(segments) == 0 { 123 | newdoc = cont 124 | } else { 125 | newdoc, _ = valSet(segments, doc, cont) 126 | } 127 | 128 | default: 129 | panic("valAppend(): invalidPointer") 130 | } 131 | return newdoc 132 | } 133 | 134 | func valPrepend(segments [][]byte, doc, item interface{}) (newdoc interface{}) { 135 | container := doc 136 | if len(segments) > 0 { 137 | container = valGet(segments, doc) 138 | } // else if ln == 1, container _is_ doc 139 | 140 | switch cont := container.(type) { 141 | case []interface{}: 142 | ln := len(cont) 143 | cont = append(cont, nil) 144 | copy(cont[1:], cont[:ln]) 145 | cont[0] = item 146 | if len(segments) == 0 { 147 | newdoc = cont 148 | } else { 149 | newdoc, _ = valSet(segments, doc, cont) 150 | } 151 | 152 | default: 153 | panic("valPrepend(): invalidPointer") 154 | } 155 | return newdoc 156 | } 157 | -------------------------------------------------------------------------------- /jptr_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "strings" 5 | import "sort" 6 | 7 | func TestParsePointer(t *testing.T) { 8 | var tcasesJSONPointers = [][3]interface{}{ 9 | {``, []string{}, ``}, 10 | {`/`, []string{""}, `/`}, 11 | {"/foo", []string{"foo"}, "/foo"}, 12 | {"/foo/0", []string{"foo", "0"}, "/foo/0"}, 13 | {"/a~1b", []string{"a/b"}, "/a~1b"}, 14 | {"/c%d", []string{"c%d"}, "/c%d"}, 15 | {"/e^f", []string{"e^f"}, "/e^f"}, 16 | {"/g|h", []string{"g|h"}, "/g|h"}, 17 | {`/i\j`, []string{`i\j`}, `/i\\j`}, 18 | {`/k\"l`, []string{`k\"l`}, `/k\\\"l`}, 19 | {"/ ", []string{" "}, "/ "}, 20 | {"/m~0n", []string{"m~n"}, "/m~0n"}, 21 | {"/g~1n~1r", []string{"g/n/r"}, "/g~1n~1r"}, 22 | {"/g/汉语/r", []string{"g", "汉语", "r"}, "/g/汉语/r"}, 23 | {"/dict/", []string{"dict", ""}, "/dict/"}, 24 | } 25 | 26 | // test ParseJsonPointer 27 | config := NewDefaultConfig() 28 | jptr := config.NewJsonpointer("") 29 | for _, tcase := range tcasesJSONPointers { 30 | t.Logf("input pointer %q", tcase[0].(string)) 31 | ref := tcase[1].([]string) 32 | 33 | jptr.ResetPath(tcase[0].(string)) 34 | segments := jptr.Segments() 35 | if len(segments) != len(ref) { 36 | t.Errorf("expected %v, got %v", len(ref), len(segments)) 37 | } else { 38 | for i, x := range ref { 39 | if string(segments[i]) != x { 40 | t.Errorf("expected %v, got %v", x, string(segments[i])) 41 | } 42 | } 43 | } 44 | 45 | // test encode pointers 46 | jptr.ResetPath("").ResetSegments(ref) 47 | if path := string(jptr.Path()); path != tcase[2].(string) { 48 | t.Errorf("expected %v, got %v", tcase[2].(string), path) 49 | } 50 | } 51 | } 52 | 53 | func TestTypicalPointers(t *testing.T) { 54 | refs := strings.Split(string(testdataFile("testdata/typical_pointers")), "\n") 55 | refs = refs[:len(refs)-1] // skip the last empty line 56 | sort.Strings(refs) 57 | config := NewDefaultConfig() 58 | 59 | data := testdataFile("testdata/typical.json") 60 | _, value := config.NewJson(data).Tovalue() 61 | val := config.NewValue(value) 62 | 63 | // test list pointers 64 | pointers := val.ListPointers(make([]string, 0, 1024)) 65 | sort.Strings(pointers) 66 | if len(refs) != len(pointers) { 67 | t.Errorf("expected %v, got %v", len(refs), len(pointers)) 68 | } 69 | for i, r := range refs { 70 | if r != pointers[i] { 71 | t.Errorf("expected %v, got %v", r, pointers[i]) 72 | } 73 | } 74 | 75 | // test list pointers for document using [][2]interface{} for map. 76 | value = GolangMap2cborMap(value) 77 | val = config.NewValue(value) 78 | 79 | pointers = val.ListPointers(make([]string, 0, 1024)) 80 | sort.Strings(pointers) 81 | 82 | if len(refs) != len(pointers) { 83 | t.Errorf("expected %v, got %v", len(refs), len(pointers)) 84 | } 85 | for i, r := range refs { 86 | if r != pointers[i] { 87 | t.Errorf("expected %v, got %v", r, pointers[i]) 88 | } 89 | } 90 | } 91 | 92 | func BenchmarkParseJsonPtr3(b *testing.B) { 93 | path := "/foo/g/0" 94 | jptr := NewDefaultConfig().NewJsonpointer(path) 95 | 96 | b.SetBytes(int64(len(path))) 97 | for i := 0; i < b.N; i++ { 98 | jptr.ResetPath(path).Segments() 99 | } 100 | } 101 | 102 | func BenchmarkParseJsonPtr4(b *testing.B) { 103 | path := "/foo/g~1n~1r/0/hello" 104 | jptr := NewDefaultConfig().NewJsonpointer(path) 105 | 106 | b.SetBytes(int64(len(path))) 107 | for i := 0; i < b.N; i++ { 108 | jptr.ResetPath(path).Segments() 109 | } 110 | } 111 | 112 | func BenchmarkParseJsonPtr5(b *testing.B) { 113 | segments := []string{"a", "ab", "a~b", "a/b", "a~/~/b"} 114 | jptr := NewDefaultConfig().NewJsonpointer("").ResetSegments(segments) 115 | path := string(jptr.Path()) 116 | 117 | b.ResetTimer() 118 | for i := 0; i < b.N; i++ { 119 | jptr.ResetPath(path).Segments() 120 | } 121 | b.SetBytes(int64(len(jptr.Path()))) 122 | } 123 | 124 | func BenchmarkToJsonPtr5(b *testing.B) { 125 | segments := []string{"a", "ab", "a~b", "a/b", "a~/~/b"} 126 | jptr := NewDefaultConfig().NewJsonpointer("") 127 | 128 | b.SetBytes(15) 129 | for i := 0; i < b.N; i++ { 130 | jptr.ResetSegments(segments) 131 | } 132 | } 133 | 134 | func BenchmarkListPtrsTyp(b *testing.B) { 135 | data := testdataFile("testdata/typical.json") 136 | config := NewDefaultConfig() 137 | _, value := config.NewJson(data).Tovalue() 138 | val := config.NewValue(value) 139 | 140 | pointers := []string{} 141 | 142 | b.SetBytes(int64(len(data))) 143 | b.ResetTimer() 144 | for i := 0; i < b.N; i++ { 145 | pointers = val.ListPointers(pointers[:0]) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /json_cbor.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | // transform json encoded value into cbor encoded value. 4 | // cnf: SpaceKind, NumberKind, ContainerEncoding, strict 5 | 6 | import "strconv" 7 | 8 | var nullStr = "null" 9 | var trueStr = "true" 10 | var falseStr = "false" 11 | 12 | func json2cbor(txt string, out []byte, config *Config) (string, int) { 13 | txt = skipWS(txt, config.ws) 14 | 15 | if len(txt) < 1 { 16 | panic("cbor scanner empty json text") 17 | } 18 | 19 | if numCheck[txt[0]] == 1 { 20 | return jsonNumToCbor(txt, out, config) 21 | } 22 | 23 | switch txt[0] { 24 | case 'n': 25 | if len(txt) >= 4 && txt[:4] == nullStr { 26 | n := cborNull(out) 27 | return txt[4:], n 28 | } 29 | panic("cbor scanner expected null") 30 | 31 | case 't': 32 | if len(txt) >= 4 && txt[:4] == trueStr { 33 | n := cborTrue(out) 34 | return txt[4:], n 35 | } 36 | panic("cbor scanner expected true") 37 | 38 | case 'f': 39 | if len(txt) >= 5 && txt[:5] == falseStr { 40 | n := cborFalse(out) 41 | return txt[5:], n 42 | } 43 | panic("cbor scanner expected false") 44 | 45 | case '"': 46 | n := 0 47 | txt, x := scanString(txt, out[n+16:]) // 16 reserved for cbor hdr 48 | n += valtext2cbor(bytes2str(out[n+16:n+16+x]), out[n:]) 49 | return txt, n 50 | 51 | case '[': 52 | n, m, nn, nnn := 0, 0, 0, 0 53 | switch config.ct { 54 | case LengthPrefix: 55 | nn, nnn = n+32, n+32 56 | case Stream: 57 | nnn += arrayStart(out[nnn:]) 58 | } 59 | 60 | var ln int 61 | if txt = skipWS(txt[1:], config.ws); len(txt) == 0 { 62 | panic("cbor scanner expected ']'") 63 | } else if txt[0] != ']' { 64 | for { 65 | txt, m = json2cbor(txt, out[nnn:], config) 66 | nnn += m 67 | ln++ 68 | if txt = skipWS(txt, config.ws); len(txt) == 0 { 69 | panic("cbor scanner expected ']'") 70 | } else if txt[0] == ',' { 71 | txt = skipWS(txt[1:], config.ws) 72 | } else if txt[0] == ']' { 73 | break 74 | } else { 75 | panic("cbor scanner expected ']'") 76 | } 77 | } 78 | } 79 | switch config.ct { 80 | case LengthPrefix: 81 | x := valuint642cbor(uint64(ln), out[n:]) 82 | out[n] = (out[n] & 0x1f) | cborType4 // fix type from type0->type4 83 | n += x 84 | n += copy(out[n:], out[nn:nnn]) 85 | case Stream: 86 | nnn += breakStop(out[nnn:]) 87 | n = nnn 88 | } 89 | return txt[1:], n 90 | 91 | case '{': 92 | n, m, nn, nnn := 0, 0, 0, 0 93 | switch config.ct { 94 | case LengthPrefix: 95 | nn, nnn = n+32, n+32 96 | case Stream: 97 | nnn += mapStart(out[nnn:]) 98 | } 99 | 100 | var ln int 101 | txt = skipWS(txt[1:], config.ws) 102 | if txt[0] == '}' { 103 | // pass 104 | } else if txt[0] != '"' { 105 | panic("cbor scanner expected property key") 106 | } else { 107 | for { 108 | // 16 reserved for cbor hdr 109 | txt, m = scanString(txt, out[nnn+16:]) 110 | nnn += valtext2cbor(bytes2str(out[nnn+16:nnn+16+m]), out[nnn:]) 111 | 112 | if txt = skipWS(txt, config.ws); len(txt) == 0 || txt[0] != ':' { 113 | panic("cbor scanner expected property colon") 114 | } 115 | txt, m = json2cbor(skipWS(txt[1:], config.ws), out[nnn:], config) 116 | nnn += m 117 | ln++ 118 | 119 | if txt = skipWS(txt, config.ws); len(txt) == 0 { 120 | panic("cbor scanner expected '}'") 121 | } else if txt[0] == ',' { 122 | txt = skipWS(txt[1:], config.ws) 123 | } else if txt[0] == '}' { 124 | break 125 | } else { 126 | panic("cbor scanner expected '}'") 127 | } 128 | } 129 | } 130 | switch config.ct { 131 | case LengthPrefix: 132 | x := valuint642cbor(uint64(ln), out[n:]) 133 | out[n] = (out[n] & 0x1f) | cborType5 // fix type from type0->type5 134 | n += x 135 | n += copy(out[n:], out[nn:nnn]) 136 | case Stream: 137 | nnn += breakStop(out[nnn:]) 138 | n = nnn 139 | } 140 | return txt[1:], n 141 | 142 | default: 143 | panic("cbor scanner expected token") 144 | } 145 | } 146 | 147 | func jsonNumToCbor(txt string, out []byte, config *Config) (string, int) { 148 | s, e, l, flt := 0, 1, len(txt), false 149 | if len(txt) > 1 { 150 | for ; e < l && intCheck[txt[e]] == 1; e++ { 151 | flt = flt || fltCheck[txt[e]] == 1 // detected as float 152 | } 153 | } 154 | if config.nk != FloatNumber && !flt { 155 | if i, err := strconv.ParseInt(txt[s:e], 10, 64); err == nil { 156 | n := valint642cbor(i, out) 157 | return txt[e:], n 158 | } else if ui, err := strconv.ParseUint(txt[s:e], 10, 64); err == nil { 159 | n := valuint642cbor(ui, out) 160 | return txt[e:], n 161 | } 162 | } 163 | num, err := strconv.ParseFloat(txt[s:e], 64) 164 | if err != nil { // once parsing logic is bullet proof remove this 165 | panic(err) 166 | } 167 | n := valfloat642cbor(num, out) 168 | return txt[e:], n 169 | } 170 | -------------------------------------------------------------------------------- /cmd/README.md: -------------------------------------------------------------------------------- 1 | General options 2 | --------------- 3 | 4 | * `-inpfile` process file containing JSON doc(s) based on other options. 5 | * `-inptxt` process input text based on their options. 6 | * `-mprof` take memory profile for testdata/code.json.gz. 7 | * `-outfile` write output to file. 8 | * `-overheads` compute overheads on CBOR and collation encoding. 9 | * `-quote` use strconv.Unquote on inptxt/inpfile. 10 | * `-repeat` repeat count. 11 | * `-nk` can be `smart`, treat number as int64 or fall back to float64, or, 12 | `float`, treat number only as float64 (default "float"). 13 | * `-ws` can be `ansi` white space, or, `unicode` white space, default 14 | "ANSI". 15 | 16 | To include [n1ql](https://www.couchbase.com/products/n1ql), compile it with 17 | `-tags n1ql`. 18 | 19 | Convert from JSON 20 | ----------------- 21 | 22 | * `-json2cbor` convert inptxt or content in inpfile to CBOR output. 23 | * `-json2collate` convert inptxt or content in inpfile to collated output. 24 | * `-json2value` convert inptxt or content in inpfile to golang value. 25 | 26 | **options for JSON** 27 | 28 | * `-pointers` list of json-pointers for doc specified by input-file. 29 | 30 | Convert from CBOR 31 | ----------------- 32 | 33 | * `-cbor2collate` convert inptxt or content in inpfile to collated output. 34 | * `-cbor2json` convert inptxt or content in inpfile to JSON output. 35 | * `-cbor2value` convert inptxt or content in inpfile to golang value. 36 | 37 | **options for CBOR** 38 | 39 | * `-ct` container encoding for CBOR, allowed `stream` (default), or, 40 | `lenprefix`. 41 | 42 | Convert from Collate 43 | -------------------- 44 | 45 | * `-collate2cbor` convert inptxt or content in inpfile to CBOR output. 46 | * `-collate2json` convert inptxt or content in inpfile to JSON output. 47 | * `-collate2value` convert inptxt or content in inpfile to value. 48 | 49 | 50 | **options for collation** 51 | 52 | * `-arrlenprefix` set SortbyArrayLen for collation ordering. 53 | * `-maplenprefix` SortbyPropertyLen for collation ordering (default true) 54 | * `-domissing` consider missing type while collation (default true). 55 | * `-collatesort` sort inpfile, with one or more JSON terms, using 56 | collation algorithm. 57 | * `-n1qlsort` sort inpfile, with one or more JSON terms, using 58 | collation algorithm. 59 | * `-checkdir` test files for collation order in specified directory. For 60 | every input file `/filename`, there should be reference file 61 | `/filename.ref`. 62 | 63 | Convert from value 64 | ------------------ 65 | 66 | * `-value2cbor` convert inptxt JSON to value and then to CBOR. 67 | * `-value2json` convert inptxt JSON to value and then back to JSON. 68 | * `-value2collate` convert inptxt JSON to value and then back to binary. 69 | 70 | 71 | Examples 72 | -------- 73 | 74 | **Transformations** 75 | 76 | ```bash 77 | $ gson -inpfile example.json -json2value 78 | Json: "hello world" 79 | Valu: hello world 80 | ``` 81 | 82 | ```bash 83 | $ gson -inptxt '"hello world"' -json2value 84 | Json: "hello world" 85 | Valu: hello world 86 | ``` 87 | 88 | ```bash 89 | $ gson -inptxt '"hello world"' -json2cbor 90 | Json: "hello world" 91 | Cbor: [107 104 101 108 108 111 32 119 111 114 108 100] 92 | Json: "hello world" 93 | ``` 94 | 95 | ```bash 96 | $ gson -inptxt '"hello world"' -json2collate 97 | Json: "hello world" 98 | Coll: "\x06hello world\x00\x00" 99 | Coll: [6 104 101 108 108 111 32 119 111 114 108 100 0 0] 100 | ``` 101 | 102 | Similarly to transform from CBOR: 103 | 104 | ```bash 105 | $ gson -inptxt "khello world" -cbor2value 106 | $ gson -inptxt "khello world" -cbor2json 107 | $ gson -inptxt "khello world" -cbor2collate 108 | ``` 109 | 110 | Specifying container type for transforming to CBOR: 111 | 112 | ```bash 113 | $ go build -o gson; gson -inptxt "[10,20]" -ct lenprefix -json2cbor 114 | Json: [10,20] 115 | Cbor: [130 251 64 36 0 0 0 0 0 0 251 64 52 0 0 0 0 0 0] 116 | Cbor: "\x82\xfb@$\x00\x00\x00\x00\x00\x00\xfb@4\x00\x00\x00\x00\x00\x00" 117 | Json: [10,20] 118 | $ go build -o gson; gson -inptxt "[10,20]" -ct stream -json2cbor 119 | Json: [10,20] 120 | Cbor: [159 251 64 36 0 0 0 0 0 0 251 64 52 0 0 0 0 0 0 255] 121 | Cbor: "\x9f\xfb@$\x00\x00\x00\x00\x00\x00\xfb@4\x00\x00\x00\x00\x00\x00\xff" 122 | Json: [10,20] 123 | ``` 124 | 125 | Similarly to transform from collate: 126 | 127 | ```bash 128 | $ gson -inpfile example.coll -collate2value 129 | $ gson -inpfile example.coll -collate2json 130 | $ gson -inpfile example.coll -collate2cbor 131 | ``` 132 | 133 | Similarly to transform from value: 134 | 135 | ```bash 136 | $ gson -inptxt '"hello world"' -value2json 137 | $ gson -inptxt '"hello world"' -value2cbor 138 | $ gson -inptxt '"hello world"' -value2collate 139 | ``` 140 | 141 | **possible list of json-pointer from a given doc** 142 | 143 | ```bash 144 | $ gson -inpfile typical.json -pointers 145 | ``` 146 | -------------------------------------------------------------------------------- /value_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "bytes" 5 | import "sort" 6 | import "io/ioutil" 7 | import "strings" 8 | import "path" 9 | 10 | func TestValueCompare(t *testing.T) { 11 | config := NewDefaultConfig() 12 | testcases := [][3]interface{}{ 13 | // numbers 14 | {uint64(10), float64(10), 0}, 15 | {uint64(10), float64(10.1), -1}, 16 | {uint64(10), int64(-10), 1}, 17 | {uint64(10), int64(10), 0}, 18 | {uint64(11), int64(10), 1}, 19 | {uint64(9), uint64(10), -1}, 20 | {uint64(10), uint64(10), 0}, 21 | {int64(10), int(11), -1}, 22 | {int64(11), int(10), 1}, 23 | {int64(10), int64(10), 0}, 24 | {int64(10), uint64(11), -1}, 25 | {int64(10), uint64(10), 0}, 26 | {int64(10), uint64(9), 1}, 27 | {float64(10), uint64(10), 0}, 28 | {float64(10.1), uint64(10), 1}, 29 | {float64(10), uint64(9), 1}, 30 | // all others 31 | {nil, nil, 0}, 32 | {nil, false, -1}, 33 | {nil, true, -1}, 34 | {nil, 10, -1}, 35 | {nil, "hello", -1}, 36 | {nil, []interface{}{10, 20}, -1}, 37 | {nil, map[string]interface{}{"key1": 10}, -1}, 38 | {false, nil, 1}, 39 | {false, false, 0}, 40 | {false, true, -1}, 41 | {false, 10, -1}, 42 | {false, "hello", -1}, 43 | {false, []interface{}{10, 20}, -1}, 44 | {false, map[string]interface{}{"key1": 10}, -1}, 45 | {true, nil, 1}, 46 | {true, false, 1}, 47 | {true, true, 0}, 48 | {true, 10, -1}, 49 | {true, "hello", -1}, 50 | {true, []interface{}{10, 20}, -1}, 51 | {true, map[string]interface{}{"key1": 10}, -1}, 52 | {10, nil, 1}, 53 | {10, false, 1}, 54 | {10, true, 1}, 55 | {10, 10, 0}, 56 | {10, "hello", -1}, 57 | {10, []interface{}{10, 20}, -1}, 58 | {10, map[string]interface{}{"key1": 10}, -1}, 59 | {[]interface{}{10}, nil, 1}, 60 | {[]interface{}{10}, false, 1}, 61 | {[]interface{}{10}, true, 1}, 62 | {[]interface{}{10}, 10, 1}, 63 | {[]interface{}{10}, "hello", 1}, 64 | {[]interface{}{10}, []interface{}{10}, 0}, 65 | {[]interface{}{10}, map[string]interface{}{"key1": 10}, -1}, 66 | {map[string]interface{}{"key1": 10}, nil, 1}, 67 | {map[string]interface{}{"key1": 10}, false, 1}, 68 | {map[string]interface{}{"key1": 10}, true, 1}, 69 | {map[string]interface{}{"key1": 10}, 10, 1}, 70 | {map[string]interface{}{"key1": 10}, "hello", 1}, 71 | {map[string]interface{}{"key1": 10}, []interface{}{10}, 1}, 72 | {map[string]interface{}{"key1": 10}, 73 | map[string]interface{}{"key1": 10}, 0}, 74 | } 75 | for _, tcase := range testcases { 76 | val1 := config.NewValue(tcase[0]) 77 | val2 := config.NewValue(tcase[1]) 78 | ref, cmp := tcase[2].(int), val1.Compare(val2) 79 | if cmp != ref { 80 | t.Errorf("for nil expected %v, got %v", ref, cmp) 81 | } 82 | } 83 | } 84 | 85 | func TestValueCollate(t *testing.T) { 86 | dirname := "testdata/collate" 87 | entries, err := ioutil.ReadDir(dirname) 88 | if err != nil { 89 | t.Fatal(err) 90 | } 91 | for _, entry := range entries { 92 | file := path.Join(dirname, entry.Name()) 93 | if !strings.HasSuffix(file, ".ref") { 94 | out := strings.Join(collatefile(file), "\n") 95 | ref, err := ioutil.ReadFile(file + ".ref") 96 | if err != nil { 97 | t.Fatal(err) 98 | } 99 | if strings.Trim(string(ref), "\n") != out { 100 | //fmt.Println(string(ref)) 101 | //fmt.Println(string(out)) 102 | t.Fatalf("sort mismatch in %v", file) 103 | } 104 | } 105 | } 106 | } 107 | 108 | func collatefile(filename string) (outs []string) { 109 | s, err := ioutil.ReadFile(filename) 110 | if err != nil { 111 | panic(err.Error()) 112 | } 113 | config := NewDefaultConfig() 114 | if strings.Contains(filename, "numbers") { 115 | config = config.SetNumberKind(SmartNumber) 116 | } 117 | return collateLines(config, s) 118 | } 119 | 120 | func collateLines(config *Config, s []byte) []string { 121 | texts, values := lines(s), make(valueList, 0) 122 | for i, text := range texts { 123 | jsn := config.NewJson(text) 124 | _, val := jsn.Tovalue() 125 | values = append(values, valObj{i, config.NewValue(val)}) 126 | } 127 | outs := doSort(texts, values) 128 | return outs 129 | } 130 | 131 | func doSort(texts [][]byte, values valueList) (outs []string) { 132 | sort.Sort(values) 133 | outs = make([]string, 0) 134 | for _, value := range values { 135 | outs = append(outs, string(texts[value.off])) 136 | } 137 | return 138 | } 139 | 140 | func lines(content []byte) [][]byte { 141 | content = bytes.Trim(content, "\r\n") 142 | return bytes.Split(content, []byte("\n")) 143 | } 144 | 145 | type valObj struct { 146 | off int 147 | val *Value 148 | } 149 | 150 | type valueList []valObj 151 | 152 | func (values valueList) Len() int { 153 | return len(values) 154 | } 155 | 156 | func (values valueList) Less(i, j int) bool { 157 | return values[i].val.Compare(values[j].val) < 0 158 | } 159 | 160 | func (values valueList) Swap(i, j int) { 161 | values[i], values[j] = values[j], values[i] 162 | } 163 | -------------------------------------------------------------------------------- /value_collate_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "sort" 4 | import "reflect" 5 | import "testing" 6 | import "encoding/json" 7 | 8 | // All test cases are folded into collate_value_test.go, contains only few 9 | // missing testcases (if any) and benchmarks. 10 | 11 | func TestValNumber2Coll(t *testing.T) { 12 | testcases := [][2]interface{}{ 13 | {json.Number("0"), float64(0)}, 14 | {json.Number("-9223372036854775808"), int64(-9223372036854775808)}, 15 | {json.Number("24"), float64(24)}, 16 | {json.Number("9223372036854775808"), uint64(9223372036854775808)}, 17 | {json.Number("-24"), float64(-24)}, 18 | } 19 | 20 | var items ByteSlices 21 | 22 | config := NewDefaultConfig().SetNumberKind(SmartNumber) 23 | col := config.NewCollate(make([]byte, 0, 1024)) 24 | 25 | for _, tcase := range testcases { 26 | nums := tcase[0].(json.Number) 27 | config.NewValue(nums).Tocollate(col.Reset(nil)) 28 | value := col.Tovalue() 29 | if reflect.DeepEqual(value, tcase[1]) == false { 30 | t.Errorf("expected %v, got %v", tcase[1], value) 31 | } 32 | items = append(items, append(make([]byte, 0), col.Bytes()...)) 33 | } 34 | 35 | // do a sort 36 | sort.Sort(items) 37 | refs := []interface{}{testcases[1][1], testcases[4][1], testcases[0][1], 38 | testcases[2][1], testcases[3][1]} 39 | outs := []interface{}{} 40 | for _, item := range items { 41 | outs = append(outs, config.NewCollate(item).Tovalue()) 42 | } 43 | if reflect.DeepEqual(outs, refs) == false { 44 | t.Errorf("expected %v, got %v", refs, outs) 45 | } 46 | } 47 | 48 | func BenchmarkVal2CollNil(b *testing.B) { 49 | config := NewDefaultConfig() 50 | clt := config.NewCollate(make([]byte, 0, 1024)) 51 | val := config.NewValue(nil) 52 | 53 | for i := 0; i < b.N; i++ { 54 | val.Tocollate(clt.Reset(nil)) 55 | } 56 | } 57 | 58 | func BenchmarkVal2CollTrue(b *testing.B) { 59 | config := NewDefaultConfig() 60 | clt := config.NewCollate(make([]byte, 0, 1024)) 61 | val := config.NewValue(interface{}(true)) 62 | 63 | for i := 0; i < b.N; i++ { 64 | val.Tocollate(clt.Reset(nil)) 65 | } 66 | } 67 | 68 | func BenchmarkVal2CollFalse(b *testing.B) { 69 | config := NewDefaultConfig() 70 | clt := config.NewCollate(make([]byte, 0, 1024)) 71 | val := config.NewValue(interface{}(false)) 72 | 73 | for i := 0; i < b.N; i++ { 74 | val.Tocollate(clt.Reset(nil)) 75 | } 76 | } 77 | 78 | func BenchmarkVal2CollF64(b *testing.B) { 79 | config := NewDefaultConfig() 80 | clt := config.NewCollate(make([]byte, 0, 1024)) 81 | val := config.NewValue(interface{}(float64(10.121312213123123))) 82 | 83 | for i := 0; i < b.N; i++ { 84 | val.Tocollate(clt.Reset(nil)) 85 | } 86 | } 87 | 88 | func BenchmarkVal2CollI64(b *testing.B) { 89 | config := NewDefaultConfig() 90 | clt := config.NewCollate(make([]byte, 0, 1024)) 91 | val := config.NewValue(interface{}(int64(123456789))) 92 | 93 | for i := 0; i < b.N; i++ { 94 | val.Tocollate(clt.Reset(nil)) 95 | } 96 | } 97 | 98 | func BenchmarkVal2CollINum(b *testing.B) { 99 | config := NewDefaultConfig() 100 | col := config.NewCollate(nil) 101 | val := config.NewValue(json.Number("-9223372036854775808")) 102 | 103 | for i := 0; i < b.N; i++ { 104 | val.Tocollate(col.Reset(nil)) 105 | } 106 | } 107 | 108 | func BenchmarkVal2CollUNum(b *testing.B) { 109 | config := NewDefaultConfig() 110 | col := config.NewCollate(nil) 111 | val := config.NewValue(json.Number("9223372036854775808")) 112 | 113 | for i := 0; i < b.N; i++ { 114 | val.Tocollate(col.Reset(nil)) 115 | } 116 | } 117 | 118 | func BenchmarkVal2CollMiss(b *testing.B) { 119 | config := NewDefaultConfig() 120 | clt := config.NewCollate(make([]byte, 0, 1024)) 121 | val := config.NewValue(interface{}(MissingLiteral)) 122 | 123 | for i := 0; i < b.N; i++ { 124 | val.Tocollate(clt.Reset(nil)) 125 | } 126 | } 127 | 128 | func BenchmarkVal2CollStr(b *testing.B) { 129 | config := NewDefaultConfig() 130 | clt := config.NewCollate(make([]byte, 0, 1024)) 131 | val := config.NewValue(interface{}("hello world")) 132 | 133 | for i := 0; i < b.N; i++ { 134 | val.Tocollate(clt.Reset(nil)) 135 | } 136 | } 137 | 138 | func BenchmarkVal2CollArr(b *testing.B) { 139 | arr := []interface{}{nil, true, false, "hello world", 10.23122312} 140 | config := NewDefaultConfig() 141 | clt := config.NewCollate(make([]byte, 0, 1024)) 142 | val := config.NewValue(interface{}(arr)) 143 | 144 | for i := 0; i < b.N; i++ { 145 | val.Tocollate(clt.Reset(nil)) 146 | } 147 | } 148 | 149 | func BenchmarkVal2CollMap(b *testing.B) { 150 | obj := map[string]interface{}{ 151 | "key1": nil, "key2": true, "key3": false, "key4": "hello world", 152 | "key5": 10.23122312, 153 | } 154 | config := NewDefaultConfig() 155 | clt := config.NewCollate(make([]byte, 0, 1024)) 156 | val := config.NewValue(interface{}(obj)) 157 | 158 | for i := 0; i < b.N; i++ { 159 | val.Tocollate(clt.Reset(nil)) 160 | } 161 | } 162 | 163 | func BenchmarkVal2CollTyp(b *testing.B) { 164 | config := NewDefaultConfig() 165 | jsn := config.NewJson(testdataFile("testdata/typical.json")) 166 | clt := config.NewCollate(make([]byte, 0, 10*1024)) 167 | _, value := jsn.Tovalue() 168 | val := config.NewValue(value) 169 | 170 | b.ResetTimer() 171 | for i := 0; i < b.N; i++ { 172 | val.Tocollate(clt.Reset(nil)) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /json_collate.go: -------------------------------------------------------------------------------- 1 | // transform collated value into json encoding. 2 | // cnf: SpaceKind, NumberKind, doMissing, arrayLenPrefix, propertyLenPrefix 3 | 4 | package gson 5 | 6 | import "strconv" 7 | 8 | func json2collate(txt string, code []byte, config *Config) (string, int) { 9 | txt = skipWS(txt, config.ws) 10 | if len(txt) < 1 { 11 | panic("collate scanner jsonEmpty") 12 | } 13 | 14 | n := 0 15 | 16 | if digitCheck[txt[0]] == 1 { 17 | code[n] = TypeNumber 18 | n++ 19 | m, remtxt := jsonnum2collate(txt, code[n:], config) 20 | n += m 21 | code[n] = Terminator 22 | n++ 23 | return remtxt, n 24 | } 25 | 26 | switch txt[0] { 27 | case 'n': 28 | if len(txt) >= 4 && txt[:4] == "null" { 29 | code[n], code[n+1] = TypeNull, Terminator 30 | return txt[4:], n + 2 31 | } 32 | panic("collate scanner expectedNil") 33 | 34 | case 't': 35 | if len(txt) >= 4 && txt[:4] == "true" { 36 | code[n], code[n+1] = TypeTrue, Terminator 37 | return txt[4:], n + 2 38 | } 39 | panic("collate scanner expectedTrue") 40 | 41 | case 'f': 42 | if len(txt) >= 5 && txt[:5] == "false" { 43 | code[n], code[n+1] = TypeFalse, Terminator 44 | return txt[5:], n + 2 45 | } 46 | panic("collate scanner expectedFalse") 47 | 48 | case '"': 49 | bufn := config.bufferh.getbuffer(len(txt) * 5) 50 | scratch := bufn.data 51 | txt, p := scanString(txt, scratch) 52 | str := bytes2str(scratch[:p]) 53 | n += collateString(str, code[n:], config) 54 | config.bufferh.putbuffer(bufn) 55 | return txt, n 56 | 57 | case '[': 58 | var x int 59 | 60 | code[n] = TypeArray 61 | n++ 62 | nn, nnn, ln := n, n, 0 63 | if config.arrayLenPrefix { 64 | nn, nnn = (nn + 32), (nnn + 32) // prealloc space for Len encoding 65 | } 66 | 67 | if txt = skipWS(txt[1:], config.ws); len(txt) == 0 { 68 | panic("collate scanner expectedCloseArray") 69 | 70 | } else if txt[0] != ']' { 71 | for { 72 | txt, x = json2collate(txt, code[nnn:], config) 73 | nnn += x 74 | ln++ 75 | if txt = skipWS(txt, config.ws); len(txt) == 0 { 76 | panic("gson scanner expectedCloseArray") 77 | } else if txt[0] == ',' { 78 | txt = skipWS(txt[1:], config.ws) 79 | } else if txt[0] == ']' { 80 | break 81 | } else { 82 | panic("collate scanner expectedCloseArray") 83 | } 84 | } 85 | } 86 | if config.arrayLenPrefix { 87 | n += collateLength(ln, code[n:]) 88 | n += copy(code[n:], code[nn:nnn]) 89 | } else { 90 | n = nnn 91 | } 92 | code[n] = Terminator 93 | n++ 94 | return txt[1:], n 95 | 96 | case '{': 97 | var x, p, ln int 98 | 99 | code[n] = TypeObj 100 | n++ 101 | 102 | bufn := config.bufferh.getbuffer(len(txt) * 5) 103 | altcode := bufn.data 104 | 105 | kv := config.kvh.getkv(config.numkeys) 106 | 107 | if txt = skipWS(txt[1:], config.ws); len(txt) == 0 { 108 | panic("collate scanner expectedCloseobject") 109 | } else if txt[0] != '}' && txt[0] != '"' { 110 | panic("collate scanner expectedKey") 111 | } else if txt[0] != '}' { 112 | for { 113 | // NOTE: empty string is also a valid key 114 | txt, x = scanString(txt, altcode[p:]) 115 | txt = skipWS(txt, config.ws) 116 | if len(txt) == 0 || txt[0] != ':' { 117 | panic("collate scanner expectedColon") 118 | } 119 | key := bytes2str(altcode[p : p+x]) 120 | p += x 121 | 122 | txt = skipWS(txt[1:], config.ws) 123 | txt, x = json2collate(txt, altcode[p:], config) 124 | kv.refs = append(kv.refs, kvref{key, altcode[p : p+x]}) 125 | p += x 126 | ln++ 127 | 128 | if txt = skipWS(txt, config.ws); len(txt) == 0 { 129 | panic("collate scanner expectedCloseobject") 130 | } else if txt[0] == ',' { 131 | txt = skipWS(txt[1:], config.ws) 132 | } else if txt[0] == '}' { 133 | break 134 | } else { 135 | panic("collate scanner expectedCloseobject") 136 | } 137 | } 138 | 139 | (kv.refs[:ln]).sort() 140 | } 141 | if config.propertyLenPrefix { 142 | n += collateLength(ln, code[n:]) 143 | } 144 | for j := 0; j < ln; j++ { 145 | ref := kv.refs[j] 146 | n += collateString(ref.key, code[n:], config) // encode key 147 | n += copy(code[n:], ref.code) 148 | } 149 | code[n] = Terminator 150 | n++ 151 | 152 | config.bufferh.putbuffer(bufn) 153 | config.kvh.putkv(kv) 154 | return txt[1:], n 155 | } 156 | panic("collate scanner expectedToken") 157 | } 158 | 159 | func jsonnum2collate(txt string, code []byte, config *Config) (int, string) { 160 | nk, s, e, l := config.nk, 0, 1, len(txt) 161 | if len(txt) > 1 { 162 | for ; e < l && intCheck[txt[e]] == 1; e++ { 163 | } 164 | } 165 | switch nk { 166 | case FloatNumber: 167 | f, err := strconv.ParseFloat(txt[s:e], 64) 168 | if err != nil { 169 | panic(err) 170 | } 171 | n := collateFloat64(f, code) 172 | return n, txt[e:] 173 | 174 | case SmartNumber: 175 | if i, err := strconv.ParseInt(txt[s:e], 10, 64); err == nil { 176 | n := collateInt64(i, code, config) 177 | return n, txt[e:] 178 | } else if ui, err := strconv.ParseUint(txt[s:e], 10, 64); err == nil { 179 | n := collateUint64(ui, code, config) 180 | return n, txt[e:] 181 | } 182 | f, err := strconv.ParseFloat(txt[s:e], 64) 183 | if err != nil { 184 | panic(err) 185 | } 186 | n := collateFloat64(f, code) 187 | return n, txt[e:] 188 | } 189 | panic("unreachable code") 190 | } 191 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "fmt" 4 | 5 | func ExampleConfig() { 6 | config := NewDefaultConfig() 7 | // override default configuration options. 8 | // IMPORTANT: config objects are immutable, so assign back 9 | // the new object returned by each of the settings method. 10 | config = config.SetContainerEncoding(LengthPrefix) 11 | config = config.SetJptrlen(1024).SetMaxkeys(10000) 12 | config = config.SetNumberKind(FloatNumber).SetSpaceKind(AnsiSpace) 13 | config = config.SortbyArrayLen(true).SortbyPropertyLen(true) 14 | config = config.UseMissing(false) 15 | fmt.Println(config) 16 | // Output: 17 | // nk:FloatNumber, ws:AnsiSpace, ct:LengthPrefix, arrayLenPrefix:true, propertyLenPrefix:true, doMissing:false 18 | } 19 | 20 | func ExampleCbor() { 21 | config := NewDefaultConfig() 22 | cbr := config.NewCbor(make([]byte, 0, 128)) 23 | 24 | val1 := [][]byte{[]byte("hello"), []byte("world")} 25 | cbr.EncodeBytechunks(val1) 26 | fmt.Printf("value: %v cbor: %q\n", val1, cbr.Bytes()) 27 | cbr.Reset(nil) 28 | 29 | val2 := [][2]interface{}{{"first", true}} 30 | cbr.EncodeMapslice(val2) 31 | fmt.Printf("value: %v cbor: %q\n", val2, cbr.Bytes()) 32 | cbr.Reset(nil) 33 | 34 | val3, val4 := byte(128), int8(-10) 35 | cbr.EncodeSimpletype(val3).EncodeSmallint(val4) 36 | fmt.Printf("value: {%v,%v} cbor: %q\n", val3, val4, cbr.Bytes()) 37 | cbr.Reset(nil) 38 | 39 | val5 := []string{"sound", "ok", "horn"} 40 | cbr.EncodeTextchunks(val5) 41 | fmt.Printf("value: %v cbor: %q\n", val5, cbr.Bytes()) 42 | cbr.Reset(nil) 43 | 44 | config = NewDefaultConfig() 45 | cbr = config.NewCbor(make([]byte, 0, 1024)) 46 | jsn := config.NewJson(make([]byte, 0, 1024)) 47 | clt := config.NewCollate(make([]byte, 0, 1024)) 48 | 49 | config.NewValue([]interface{}{10, 20, 100}).Tocbor(cbr) 50 | fmt.Printf("to json : %q\n", cbr.Tojson(jsn).Bytes()) 51 | fmt.Printf("to collate: %q\n", cbr.Tocollate(clt).Bytes()) 52 | fmt.Printf("to value : %v\n", cbr.Tovalue()) 53 | 54 | // Output: 55 | // value: [[104 101 108 108 111] [119 111 114 108 100]] cbor: "_EhelloEworld\xff" 56 | // value: [[first true]] cbor: "efirst\xf5" 57 | // value: {128,-10} cbor: "\xf8\x80)" 58 | // value: [sound ok horn] cbor: "\u007fesoundbokdhorn\xff" 59 | // to json : "[10,20,100]" 60 | // to collate: "nP>>21-\x00P>>22-\x00P>>31-\x00\x00" 61 | // to value : [10 20 100] 62 | } 63 | 64 | func ExampleCbor_Append() { 65 | config := NewDefaultConfig() 66 | cbr1 := config.NewCbor(make([]byte, 0, 1024)) 67 | cbr2 := config.NewCbor(make([]byte, 0, 1024)) 68 | cbritem := config.NewCbor(make([]byte, 0, 1024)) 69 | olditem := config.NewCbor(make([]byte, 0, 1024)) 70 | 71 | config.NewJson([]byte(`[]`)).Tocbor(cbr1) 72 | fmt.Println("start with `[]`") 73 | 74 | ptr := config.NewJsonpointer("") 75 | config.NewValue(10.0).Tocbor(cbritem.Reset(nil)) 76 | cbr1.Append(ptr, cbritem, cbr2) 77 | fmt.Printf("after appending 10 %v\n", cbr2.Tovalue()) 78 | cbr1.Reset(nil) 79 | 80 | ptr = config.NewJsonpointer("") 81 | config.NewValue(20.0).Tocbor(cbritem.Reset(nil)) 82 | cbr2.Prepend(ptr, cbritem, cbr1) 83 | fmt.Printf("after prepending 20 %v\n", cbr1.Tovalue()) 84 | cbr2.Reset(nil) 85 | 86 | ptr = config.NewJsonpointer("/1") 87 | config.NewValue(30.0).Tocbor(cbritem.Reset(nil)) 88 | cbr1.Set(ptr, cbritem, cbr2, olditem) 89 | fmsg := "after setting 30 to second item %v old value %v\n" 90 | fmt.Printf(fmsg, cbr2.Tovalue(), olditem.Tovalue()) 91 | cbr1.Reset(nil) 92 | 93 | ptr = config.NewJsonpointer("/1") 94 | cbr2.Get(ptr, cbritem.Reset(nil)) 95 | fmt.Printf("get second item %v\n", cbritem.Tovalue()) 96 | 97 | ptr = config.NewJsonpointer("/0") 98 | cbr2.Delete(ptr, cbr1, cbritem.Reset(nil)) 99 | fmsg = "after deleting first item %v, deleted value %v\n" 100 | fmt.Printf(fmsg, cbr1.Tovalue(), cbritem.Tovalue()) 101 | cbr2.Reset(nil) 102 | 103 | // Output: 104 | // start with `[]` 105 | // after appending 10 [10] 106 | // after prepending 20 [20 10] 107 | // after setting 30 to second item [20 30] old value 10 108 | // get second item 30 109 | // after deleting first item [30], deleted value 20 110 | } 111 | 112 | func ExampleCollate() { 113 | config := NewDefaultConfig() 114 | cbr := config.NewCbor(make([]byte, 0, 1024)) 115 | jsn := config.NewJson(make([]byte, 0, 1024)) 116 | clt := config.NewCollate(make([]byte, 0, 1024)) 117 | 118 | config.NewValue([]interface{}{10, 20, 100}).Tocollate(clt) 119 | fmt.Printf("json : %q\n", clt.Tojson(jsn).Bytes()) 120 | fmt.Printf("cbor : %q\n", clt.Tocbor(cbr).Bytes()) 121 | fmt.Printf("value: %v\n", clt.Tovalue()) 122 | // Output: 123 | // json : "[1e+01,2e+01,1e+02]" 124 | // cbor : "\x9f\xfb@$\x00\x00\x00\x00\x00\x00\xfb@4\x00\x00\x00\x00\x00\x00\xfb@Y\x00\x00\x00\x00\x00\x00\xff" 125 | // value: [10 20 100] 126 | } 127 | 128 | func ExampleJson() { 129 | config := NewDefaultConfig() 130 | cbr := config.NewCbor(make([]byte, 0, 1024)) 131 | jsn := config.NewJson(make([]byte, 0, 1024)) 132 | clt := config.NewCollate(make([]byte, 0, 1024)) 133 | 134 | config.NewValue([]interface{}{10, 20, 100}).Tojson(jsn) 135 | fmt.Printf("collate : %q\n", jsn.Tocollate(clt).Bytes()) 136 | fmt.Printf("cbor : %q\n", jsn.Tocbor(cbr).Bytes()) 137 | _, value := jsn.Tovalue() 138 | fmt.Printf("value: %v\n", value) 139 | // Output: 140 | // collate : "nP>>21-\x00P>>22-\x00P>>31-\x00\x00" 141 | // cbor : "\x9f\xfb@$\x00\x00\x00\x00\x00\x00\xfb@4\x00\x00\x00\x00\x00\x00\xfb@Y\x00\x00\x00\x00\x00\x00\xff" 142 | // value: [10 20 100] 143 | } 144 | -------------------------------------------------------------------------------- /util_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "encoding/json" 5 | import "sort" 6 | import "reflect" 7 | import "fmt" 8 | 9 | func TestBytes2Str(t *testing.T) { 10 | if bytes2str(nil) != "" { 11 | t.Errorf("fail bytes2str(nil)") 12 | } 13 | } 14 | 15 | func TestStr2Bytes(t *testing.T) { 16 | if str2bytes("") != nil { 17 | t.Errorf(`fail str2bytes("")`) 18 | } 19 | } 20 | 21 | func TestCborMap2Golang(t *testing.T) { 22 | ref := `{"a":10,"b":[true,false,null]}` 23 | config := NewDefaultConfig() 24 | jsn := config.NewJson([]byte(ref)) 25 | cbr := config.NewCbor(make([]byte, 0, 1024)) 26 | 27 | _, val1 := jsn.Tovalue() 28 | value := config.NewValue(GolangMap2cborMap(val1)) 29 | value.Tocbor(cbr) 30 | val2 := cbr.Tovalue() 31 | data, err := json.Marshal(CborMap2golangMap(val2)) 32 | if err != nil { 33 | t.Fatalf("json parsing: %v\n %v", val2, err) 34 | } 35 | if s := string(data); s != ref { 36 | t.Errorf("expected %q, got %q", ref, s) 37 | } 38 | } 39 | 40 | func TestKvrefs(t *testing.T) { 41 | items := make(kvrefs, 4) 42 | items[0] = kvref{"1", []byte("1")} 43 | items[2] = kvref{"3", []byte("3")} 44 | items[1] = kvref{"2", []byte("2")} 45 | items[3] = kvref{"0", []byte("0")} 46 | sort.Sort(items) 47 | ref := kvrefs{ 48 | kvref{"0", []byte("0")}, 49 | kvref{"1", []byte("1")}, 50 | kvref{"2", []byte("2")}, 51 | kvref{"3", []byte("3")}, 52 | } 53 | if !reflect.DeepEqual(ref, items) { 54 | t.Errorf("expected %v, got %v", ref, items) 55 | } 56 | } 57 | 58 | func TestCollated2Number(t *testing.T) { 59 | tcases := [][]interface{}{ 60 | { 61 | float64(0), 62 | "0", 63 | float64(0), float64(0), 64 | }, 65 | { 66 | uint64(0), 67 | "0", 68 | float64(0), float64(0), 69 | }, 70 | { 71 | int64(0), 72 | "0", 73 | float64(0), float64(0), 74 | }, 75 | { 76 | float64(10.1231131311), 77 | ">>2101231131311-", 78 | float64(10.1231131311), float64(10.1231131311), 79 | }, 80 | { 81 | float64(-10.1231131311), 82 | "--7898768868688>", 83 | float64(-10.1231131311), float64(-10.1231131311), 84 | }, 85 | { 86 | float64(9007199254740992), 87 | ">>>2169007199254740992-", 88 | float64(9.007199254740992e+15), uint64(9007199254740992), 89 | }, 90 | { 91 | float64(-9007199254740992), 92 | "---7830992800745259007>", 93 | float64(-9.007199254740992e+15), int64(-9.007199254740992e+15), 94 | }, 95 | { 96 | int64(9223372036854775807), 97 | ">>>2199223372036854775807-", 98 | float64(9.223372036854776e+18), uint64(9223372036854775807), 99 | }, 100 | { 101 | int64(-9223372036854775808), 102 | "---7800776627963145224191>", 103 | float64(-9.223372036854776e+18), int64(-9223372036854775808), 104 | }, 105 | { 106 | uint64(9223372036854775808), 107 | ">>>2199223372036854775808-", 108 | float64(9.223372036854776e+18), uint64(9223372036854775808), 109 | }, 110 | { 111 | uint64(18446744073709551615), 112 | ">>>22018446744073709551615-", 113 | float64(1.8446744073709552e+19), uint64(18446744073709551615), 114 | }, 115 | } 116 | 117 | var code [64]byte 118 | var n int 119 | config := NewDefaultConfig() 120 | 121 | for _, tcase := range tcases { 122 | t.Logf("%T %v", tcase[0], tcase[0]) 123 | switch val := tcase[0].(type) { 124 | case float64: 125 | n = collateFloat64(val, code[:]) 126 | case uint64: 127 | n = collateUint64(val, code[:], config) 128 | case int64: 129 | n = collateInt64(val, code[:], config) 130 | } 131 | if ref := tcase[1].(string); ref != string(code[:n]) { 132 | t.Errorf("expected %v, got %v", ref, string(code[:n])) 133 | } 134 | 135 | ui, i, f, what := collated2Number(code[:n], FloatNumber) 136 | switch what { 137 | case 1: 138 | if x := uint64(tcase[2].(float64)); ui != x { 139 | t.Errorf("expected uint64 %v, got %v", x, ui) 140 | } 141 | case 2: 142 | if x := int64(tcase[2].(float64)); i != x { 143 | t.Errorf("expected int64 %v, got %v", x, i) 144 | } 145 | case 3: 146 | if x := tcase[2].(float64); f != x { 147 | t.Errorf("expected float64 %v, got %v", x, f) 148 | } 149 | default: 150 | panic("what is unknown") 151 | } 152 | 153 | ui, i, f, what = collated2Number(code[:n], SmartNumber) 154 | switch what { 155 | case 1: 156 | if x := tcase[3].(uint64); ui != x { 157 | t.Errorf("expected uint64 %v, got %v", x, ui) 158 | } 159 | case 2: 160 | if x := tcase[3].(int64); i != x { 161 | t.Errorf("expected int64 %v, got %v", x, i) 162 | } 163 | case 3: 164 | if x := tcase[3].(float64); f != x { 165 | t.Errorf("expected float64 %v, got %v", x, f) 166 | } 167 | default: 168 | panic("what is unknown") 169 | } 170 | } 171 | } 172 | 173 | func BenchmarkBytes2Str(b *testing.B) { 174 | bs := []byte("hello world") 175 | for i := 0; i < b.N; i++ { 176 | bytes2str(bs) 177 | } 178 | } 179 | 180 | func BenchmarkStr2Bytes(b *testing.B) { 181 | s := "hello world" 182 | for i := 0; i < b.N; i++ { 183 | str2bytes(s) 184 | } 185 | } 186 | 187 | func compareJSONs(t *testing.T, json1, json2 string) error { 188 | var m1, m2 interface{} 189 | err := json.Unmarshal(str2bytes(json1), &m1) 190 | if err != nil { 191 | return fmt.Errorf("parsing %v: %v", json1, err) 192 | } 193 | err = json.Unmarshal(str2bytes(json2), &m2) 194 | if err != nil { 195 | return fmt.Errorf("parsing %v: %v", json2, err) 196 | } 197 | if !reflect.DeepEqual(m1, m2) { 198 | return fmt.Errorf("expected %v, got %v", m1, m2) 199 | } 200 | return nil 201 | } 202 | -------------------------------------------------------------------------------- /collate_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "sort" 4 | import "bytes" 5 | import "strings" 6 | import "testing" 7 | import "reflect" 8 | 9 | import "golang.org/x/text/collate" 10 | import "golang.org/x/text/language" 11 | 12 | func TestCollateReset(t *testing.T) { 13 | config := NewDefaultConfig() 14 | clt := config.NewCollate(make([]byte, 0, 1024)) 15 | cltr := config.NewCollate(make([]byte, 0, 1024)) 16 | 17 | ref := []interface{}{"sound", "ok", "horn"} 18 | config.NewValue(ref).Tocollate(clt) 19 | cltr.Reset(clt.Bytes()) 20 | if value := cltr.Tovalue(); !reflect.DeepEqual(value, ref) { 21 | t.Errorf("expected %v, got %v", ref, value) 22 | } 23 | } 24 | 25 | func TestCollateEmpty(t *testing.T) { 26 | config := NewDefaultConfig() 27 | cbr := config.NewCbor(make([]byte, 0, 128)) 28 | jsn := config.NewJson(nil) 29 | clt := config.NewCollate(nil) 30 | 31 | func() { 32 | defer func() { 33 | if r := recover(); r == nil { 34 | t.Errorf("expected panic") 35 | } 36 | }() 37 | clt.Tovalue() 38 | }() 39 | func() { 40 | defer func() { 41 | if r := recover(); r == nil { 42 | t.Errorf("expected panic") 43 | } 44 | }() 45 | clt.Tojson(jsn) 46 | }() 47 | func() { 48 | defer func() { 49 | if r := recover(); r == nil { 50 | t.Errorf("expected panic") 51 | } 52 | }() 53 | clt.Tocbor(cbr) 54 | }() 55 | } 56 | 57 | func TestAlternateSortTypes(t *testing.T) { 58 | testCases := []struct { 59 | lang string 60 | in testtxtclts 61 | want []string 62 | }{{ 63 | lang: "zh,cmn,zh-Hant-u-co-pinyin,zh-HK-u-co-pinyin,zh-pinyin", 64 | in: testtxtclts{ 65 | &testtxtclt{in: "爸爸"}, &testtxtclt{in: "妈妈"}, 66 | &testtxtclt{in: "儿子"}, &testtxtclt{in: "女儿"}, 67 | }, 68 | want: []string{"爸爸", "儿子", "妈妈", "女儿"}, 69 | }, { 70 | lang: "zh-Hant,zh-u-co-stroke,zh-Hant-u-co-stroke", 71 | in: testtxtclts{ 72 | &testtxtclt{in: "爸爸"}, &testtxtclt{in: "妈妈"}, 73 | &testtxtclt{in: "儿子"}, &testtxtclt{in: "女儿"}, 74 | }, 75 | want: []string{"儿子", "女儿", "妈妈", "爸爸"}, 76 | }} 77 | 78 | for _, tc := range testCases { 79 | for _, tag := range strings.Split(tc.lang, ",") { 80 | collator := collate.New(language.MustParse(tag)) 81 | config := NewDefaultConfig().SetTextCollator(collator) 82 | for _, item := range tc.in { 83 | item.collate(config) 84 | } 85 | sort.Sort(tc.in) 86 | got := []string{} 87 | for _, item := range tc.in { 88 | got = append(got, item.in) 89 | } 90 | if !reflect.DeepEqual(got, tc.want) { 91 | t.Errorf("%v %v expected %v; got %v", tag, tc.in, tc.want, got) 92 | } 93 | } 94 | } 95 | } 96 | 97 | func TestTextNocase(t *testing.T) { 98 | testCases := []struct { 99 | lang string 100 | in testtxtclts 101 | want []string 102 | }{{ 103 | lang: "en", 104 | in: testtxtclts{ 105 | &testtxtclt{in: "B"}, &testtxtclt{in: "b"}, 106 | &testtxtclt{in: "a"}, &testtxtclt{in: "A"}, 107 | }, 108 | want: []string{"a", "A", "B", "b"}, 109 | }} 110 | 111 | for _, tc := range testCases { 112 | for _, tag := range strings.Split(tc.lang, ",") { 113 | collator := collate.New(language.MustParse(tag), collate.IgnoreCase) 114 | config := NewDefaultConfig().SetTextCollator(collator) 115 | for _, item := range tc.in { 116 | item.collate(config) 117 | } 118 | sort.Sort(tc.in) 119 | got := []string{} 120 | for _, item := range tc.in { 121 | got = append(got, item.in) 122 | } 123 | if !reflect.DeepEqual(got, tc.want) { 124 | t.Errorf("%v %v expected %v; got %v", tag, tc.in, tc.want, got) 125 | } 126 | } 127 | } 128 | } 129 | 130 | func TestTextGermanSwedish(t *testing.T) { 131 | testCases := []struct { 132 | lang string 133 | in testtxtclts 134 | want []string 135 | }{{ 136 | lang: "de", 137 | in: testtxtclts{ 138 | &testtxtclt{in: "a"}, &testtxtclt{in: "z"}, &testtxtclt{in: "ä"}, 139 | }, 140 | want: []string{"a", "ä", "z"}, 141 | }, { 142 | lang: "sv", 143 | in: testtxtclts{ 144 | &testtxtclt{in: "a"}, &testtxtclt{in: "z"}, &testtxtclt{in: "ä"}, 145 | }, 146 | want: []string{"a", "z", "ä"}, 147 | }} 148 | 149 | for _, tc := range testCases { 150 | for _, tag := range strings.Split(tc.lang, ",") { 151 | collator := collate.New(language.MustParse(tag)) 152 | config := NewDefaultConfig().SetTextCollator(collator) 153 | for _, item := range tc.in { 154 | item.collate(config) 155 | } 156 | sort.Sort(tc.in) 157 | got := []string{} 158 | for _, item := range tc.in { 159 | got = append(got, item.in) 160 | } 161 | if !reflect.DeepEqual(got, tc.want) { 162 | t.Errorf("%v %v expected %v; got %v", tag, tc.in, tc.want, got) 163 | } 164 | } 165 | } 166 | } 167 | 168 | // sort type for slice of []byte 169 | 170 | type ByteSlices [][]byte 171 | 172 | func (bs ByteSlices) Len() int { 173 | return len(bs) 174 | } 175 | 176 | func (bs ByteSlices) Less(i, j int) bool { 177 | return bytes.Compare(bs[i], bs[j]) < 0 178 | } 179 | 180 | func (bs ByteSlices) Swap(i, j int) { 181 | bs[i], bs[j] = bs[j], bs[i] 182 | } 183 | 184 | type testtxtclt struct { 185 | in string 186 | clt []byte 187 | } 188 | 189 | func (item *testtxtclt) collate(config *Config) { 190 | val := config.NewValue(item.in) 191 | item.clt = val.Tocollate(config.NewCollate(nil)).Bytes() 192 | } 193 | 194 | type testtxtclts []*testtxtclt 195 | 196 | func (items testtxtclts) Len() int { 197 | return len(items) 198 | } 199 | 200 | func (items testtxtclts) Less(i, j int) bool { 201 | return bytes.Compare(items[i].clt, items[j].clt) < 0 202 | } 203 | 204 | func (items testtxtclts) Swap(i, j int) { 205 | items[i], items[j] = items[j], items[i] 206 | } 207 | -------------------------------------------------------------------------------- /jptr.go: -------------------------------------------------------------------------------- 1 | // implements rfc-6901 to parse json-pointer text and 2 | // work with golang arrays and maps 3 | 4 | package gson 5 | 6 | import "strconv" 7 | import "strings" 8 | import "unicode/utf8" 9 | 10 | // MaxJsonpointerLen size of json-pointer path. Affects memory pool. 11 | // Changing this value will affect all new configuration instances. 12 | var MaxJsonpointerLen = 2048 13 | 14 | type jptrConfig struct { 15 | jptrMaxlen int 16 | jptrMaxseg int 17 | } 18 | 19 | // SetJptrlen will set the maximum size for jsonpointer path. 20 | func (config Config) SetJptrlen(n int) *Config { 21 | config.jptrMaxlen = n 22 | config.jptrMaxseg = n / 8 23 | return &config 24 | } 25 | 26 | // Jsonpointer abstracts rfc-6901 into a type. 27 | // allows ~0 and ~1 escapes, property lookup by specifying the key, 28 | // and array lookup by specifying the index. 29 | // Also allows empty "" pointer and empty key "/". 30 | type Jsonpointer struct { 31 | config *Config 32 | path []byte 33 | segments [][]byte 34 | segln int 35 | } 36 | 37 | // ResetPath to reuse the Jsonpointer object for a new path. 38 | func (jptr *Jsonpointer) ResetPath(path string) *Jsonpointer { 39 | if len(path) > jptr.config.jptrMaxlen { 40 | panic("jsonpointer path exceeds configured length") 41 | } 42 | n := copy(jptr.path[:cap(jptr.path)], path) 43 | jptr.path = jptr.path[:n] 44 | jptr.segln = 0 45 | return jptr 46 | } 47 | 48 | // ResetSegments variant of ResetPath to reconstruct the path from segments. 49 | func (jptr *Jsonpointer) ResetSegments(segments []string) *Jsonpointer { 50 | if len(segments) > jptr.config.jptrMaxseg { 51 | panic("no. of segments in jsonpointer-path exceeds configured limit") 52 | } 53 | n := encodePointer(segments, jptr.path[:cap(jptr.path)]) 54 | jptr.path = jptr.path[:n] 55 | for i, segment := range segments { 56 | jptr.segments[i] = append(jptr.segments[i][:0], segment...) 57 | } 58 | jptr.segln = len(segments) 59 | return jptr 60 | } 61 | 62 | // Segments return path segments, segments in a path are separated by "/" 63 | func (jptr *Jsonpointer) Segments() [][]byte { 64 | if len(jptr.path) > 0 && jptr.segln == 0 { 65 | jptr.segln = parsePointer(jptr.path, jptr.segments) 66 | } 67 | return jptr.segments[:jptr.segln] 68 | } 69 | 70 | // Path return the path value. 71 | func (jptr *Jsonpointer) Path() []byte { 72 | return jptr.path 73 | } 74 | 75 | //---- local functions 76 | 77 | func parsePointer(in []byte, segments [][]byte) int { 78 | j := 0 79 | 80 | if len(in) == 0 { 81 | return 0 82 | } else if len(in) == 1 && in[0] == '/' { 83 | segments[0] = segments[0][:0] 84 | return 1 85 | } 86 | 87 | updateseg := func(segment []byte, j int) ([]byte, int) { 88 | segments[j] = segment 89 | j++ 90 | return segments[j][:0], j 91 | } 92 | 93 | var ch rune 94 | 95 | u, segment, escape := [6]byte{}, segments[j][:0], false 96 | for _, ch = range bytes2str(in[1:]) { 97 | if ch == '~' { 98 | escape = true 99 | 100 | } else if escape { 101 | switch ch { 102 | case '1': 103 | segment = append(segment, '/') 104 | case '0': 105 | segment = append(segment, '~') 106 | } 107 | escape = false 108 | 109 | } else if ch == '/' { 110 | segment, j = updateseg(segment, j) 111 | 112 | } else if ch < utf8.RuneSelf { 113 | segment = append(segment, byte(ch)) 114 | 115 | } else { 116 | sz := utf8.EncodeRune(u[:], ch) 117 | segment = append(segment, u[:sz]...) 118 | } 119 | } 120 | if len(segment) > 0 { 121 | segment, j = updateseg(segment, j) 122 | } 123 | if in[len(in)-1] == '/' { 124 | _, j = updateseg(segment, j) 125 | } 126 | return j 127 | } 128 | 129 | func encodePointer(p []string, out []byte) int { 130 | n := 0 131 | for _, s := range p { 132 | out[n] = '/' 133 | n++ 134 | for _, c := range str2bytes(s) { 135 | switch c { 136 | case '/': 137 | out[n] = '~' 138 | out[n+1] = '1' 139 | n += 2 140 | case '~': 141 | out[n] = '~' 142 | out[n+1] = '0' 143 | n += 2 144 | default: 145 | out[n] = c 146 | n++ 147 | } 148 | } 149 | } 150 | 151 | // to json string 152 | var jsonstr [2048]byte 153 | bs, err := encodeString(out[:n], jsonstr[:0]) 154 | if err != nil { 155 | panic(err) 156 | } 157 | return copy(out, bs[1:len(bs)-1]) 158 | } 159 | 160 | func allpaths(doc interface{}, pointers []string, prefix []byte) []string { 161 | var scratch [64]byte 162 | 163 | n := len(prefix) 164 | prefix = append(prefix, '/', '-') 165 | switch v := doc.(type) { 166 | case []interface{}: 167 | pointers = append(pointers, string(prefix)) // new allocation 168 | if len(v) > 0 { 169 | for i, val := range v { 170 | prefix = prefix[:n] 171 | dst := strconv.AppendInt(scratch[:0], int64(i), 10) 172 | prefix = append(prefix, '/') 173 | prefix = append(prefix, dst...) 174 | pointers = append(pointers, string(prefix)) // new allocation 175 | pointers = allpaths(val, pointers, prefix) 176 | } 177 | } 178 | 179 | case map[string]interface{}: 180 | pointers = append(pointers, string(prefix)) // new allocation 181 | if len(v) > 0 { 182 | for key, val := range v { 183 | prefix = prefix[:n] 184 | prefix = append(prefix, '/') 185 | prefix = append(prefix, escapeJp(key)...) 186 | pointers = append(pointers, string(prefix)) // new allocation 187 | pointers = allpaths(val, pointers, prefix) 188 | } 189 | } 190 | 191 | case [][2]interface{}: 192 | pointers = append(pointers, string(prefix)) // new allocation 193 | if len(v) > 0 { 194 | for _, pairs := range v { 195 | prefix = prefix[:n] 196 | key, val := pairs[0].(string), pairs[1] 197 | prefix = append(prefix, '/') 198 | prefix = append(prefix, escapeJp(key)...) 199 | pointers = append(pointers, string(prefix)) // new allocation 200 | pointers = allpaths(val, pointers, prefix) 201 | } 202 | } 203 | 204 | } 205 | return pointers 206 | } 207 | 208 | func escapeJp(key string) string { 209 | if strings.ContainsAny(key, "~/") { 210 | return strings.Replace(strings.Replace(key, "~", "~0", -1), "/", "~1", -1) 211 | } 212 | return key 213 | } 214 | -------------------------------------------------------------------------------- /cbor_test.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "testing" 4 | import "reflect" 5 | 6 | func TestCborMajor(t *testing.T) { 7 | if typ := cborMajor(0xff); typ != 0xe0 { 8 | t.Errorf("fail major() got %v wanted 0xe0", typ) 9 | } 10 | } 11 | 12 | func TestCborSmallInt(t *testing.T) { 13 | config := NewDefaultConfig() 14 | cbr := config.NewCbor(make([]byte, 0, 128)) 15 | 16 | for i := int8(-24); i < 24; i++ { // SmallInt is -24..23 17 | cbr.EncodeSmallint(i) 18 | item := cbr.Tovalue() 19 | if val1, ok := item.(int64); ok && val1 != int64(i) { 20 | t.Errorf("fail decode on SmallInt: %x, want %x", val1, i) 21 | } else if val2, ok := item.(uint64); ok && val2 != uint64(i) { 22 | t.Errorf("fail decode on SmallInt: %x, want %x", val2, i) 23 | } 24 | cbr.Reset(nil) 25 | } 26 | } 27 | 28 | func TestCborSimpleType(t *testing.T) { 29 | config := NewDefaultConfig() 30 | cbr := config.NewCbor(make([]byte, 0, 128)) 31 | 32 | // test encoding type7/simpletype < 20 33 | for i := 0; i < 20; i++ { 34 | cbr.EncodeSimpletype(byte(i)) 35 | item := cbr.Tovalue() 36 | if item.(byte) != byte(i) { 37 | t.Errorf("fail decode on simple-type: %v want %v", item, i) 38 | } 39 | cbr.Reset(nil) 40 | } 41 | 42 | // test decoding typ7/simpletype extended byte 43 | for i := 32; i < 255; i++ { 44 | cbr.EncodeSimpletype(byte(i)) 45 | if item := cbr.Tovalue(); item.(byte) != byte(i) { 46 | t.Errorf("fail codec simpletype extended: %v", item) 47 | } 48 | cbr.Reset(nil) 49 | } 50 | } 51 | 52 | func TestCborMapslice(t *testing.T) { 53 | config := NewDefaultConfig() 54 | cbr := config.NewCbor(make([]byte, 0, 1024)) 55 | 56 | items := [][2]interface{}{ 57 | {"first", true}, 58 | {"second", 12.2}, 59 | {"third", []interface{}{true, false, 10.2}}, 60 | { 61 | "fourth", 62 | [][2]interface{}{ 63 | {"a", 10.2}, 64 | {"b", 11.2}, 65 | }, 66 | }, 67 | } 68 | 69 | cbr.data = cbr.data[:cbr.n+1] 70 | cbr.data[0] = cborType5 | cborIndefiniteLength 71 | cbr.n++ 72 | cbr.EncodeMapslice(items) 73 | cbr.data = cbr.data[:cbr.n+1] 74 | cbr.data[cbr.n] = cborType7 | cborItemBreak 75 | cbr.n++ 76 | value, ref := cbr.Tovalue(), CborMap2golangMap(items) 77 | if !reflect.DeepEqual(value, ref) { 78 | t.Errorf("expected %v, got %v", ref, value) 79 | } 80 | } 81 | 82 | func TestCborItem(t *testing.T) { 83 | txt := `{"a": 10, "b": 1024, "c": 1048576, "d": 8589934592, ` + 84 | `"an": -10, "bn": -1024, "cn": -1048576, "dn": -8589934592, ` + 85 | `"arr": [1,2], "nestd":[[23]], ` + 86 | `"dict": {"a":10, "b":20, "": 2}, "": 1}` 87 | 88 | testcases := [][2]interface{}{ 89 | {"/a", 10}, 90 | {"/b", 1024}, 91 | {"/c", 1048576}, 92 | {"/d", 8589934592}, 93 | {"/an", -10}, 94 | {"/bn", -1024}, 95 | {"/cn", -1048576}, 96 | {"/dn", -8589934592}, 97 | {"/arr", []interface{}{1, 2}}, 98 | { 99 | "/dict", 100 | map[string]interface{}{"a": 10, "b": 20, "": 2}, 101 | }, 102 | } 103 | fn := func(ptr *Jsonpointer, ref interface{}, cbr, item *Cbor) { 104 | t.Logf("%v", string(ptr.Path())) 105 | 106 | cbr.Get(ptr, item) 107 | if value := item.Tovalue(); reflect.DeepEqual(value, ref) { 108 | t.Errorf("expected %v, got %v", ref, value) 109 | } 110 | } 111 | 112 | config := NewDefaultConfig().SetNumberKind(SmartNumber) 113 | config = config.SetContainerEncoding(Stream) 114 | cbr := config.NewCbor(make([]byte, 0, 1024)) 115 | item := config.NewCbor(make([]byte, 0, 1024)) 116 | config.NewJson([]byte(txt)).Tocbor(cbr) 117 | for _, tcase := range testcases { 118 | ptr := config.NewJsonpointer(tcase[0].(string)) 119 | fn(ptr, tcase[1], cbr, item.Reset(nil)) 120 | } 121 | 122 | config = NewDefaultConfig().SetNumberKind(SmartNumber) 123 | config = config.SetContainerEncoding(LengthPrefix) 124 | cbr = config.NewCbor(make([]byte, 0, 1024)) 125 | item = config.NewCbor(make([]byte, 0, 1024)) 126 | config.NewJson([]byte(txt)).Tocbor(cbr) 127 | for _, tcase := range testcases { 128 | ptr := config.NewJsonpointer(tcase[0].(string)) 129 | fn(ptr, tcase[1], cbr, item.Reset(nil)) 130 | } 131 | 132 | // special cases 133 | config = NewDefaultConfig().SetContainerEncoding(Stream) 134 | cbr = config.NewCbor(make([]byte, 0, 1024)) 135 | item = config.NewCbor(make([]byte, 0, 1024)) 136 | 137 | cbr.data = cbr.data[:cbr.n+1] 138 | cbr.data[0] = cborType4 | cborIndefiniteLength 139 | cbr.n++ 140 | cbr.EncodeSmallint(10).EncodeSmallint(-10).EncodeSimpletype(128) 141 | config.NewValue(uint8(100)).Tocbor(cbr) 142 | config.NewValue(float32(10.2)).Tocbor(cbr) 143 | config.NewValue(CborTagEpoch(1234567890)).Tocbor(cbr) 144 | cbr.EncodeBytechunks([][]byte{[]byte("hello"), []byte("world")}) 145 | cbr.EncodeTextchunks([]string{"sound", "ok", "horn"}) 146 | cbr.data = cbr.data[:cbr.n+1] 147 | cbr.data[cbr.n] = brkstp 148 | cbr.n++ 149 | 150 | testcases = [][2]interface{}{ 151 | {"/0", uint64(10)}, 152 | {"/1", int64(-10)}, 153 | {"/2", uint8(128)}, 154 | {"/3", uint64(100)}, 155 | {"/4", float32(10.2)}, 156 | {"/5", CborTagEpoch(1234567890)}, 157 | {"/6", [][]byte{[]byte("hello"), []byte("world")}}, 158 | {"/7", []string{"sound", "ok", "horn"}}, 159 | } 160 | 161 | t.Logf("%v", string(cbr.Bytes())) 162 | 163 | for _, tcase := range testcases { 164 | t.Logf("%v", tcase[0].(string)) 165 | 166 | ptr := config.NewJsonpointer(tcase[0].(string)) 167 | value := cbr.Get(ptr, item.Reset(nil)).Tovalue() 168 | if !reflect.DeepEqual(value, tcase[1]) { 169 | t.Errorf("expected %T, got %T", tcase[1], value) 170 | } 171 | } 172 | } 173 | 174 | func TestCborEmpty(t *testing.T) { 175 | config := NewDefaultConfig() 176 | cbr := config.NewCbor(make([]byte, 0, 128)) 177 | jsn := config.NewJson(nil) 178 | clt := config.NewCollate(nil) 179 | 180 | func() { 181 | defer func() { 182 | if r := recover(); r == nil { 183 | t.Errorf("expected panic") 184 | } 185 | }() 186 | cbr.Tovalue() 187 | }() 188 | func() { 189 | defer func() { 190 | if r := recover(); r == nil { 191 | t.Errorf("expected panic") 192 | } 193 | }() 194 | cbr.Tojson(jsn) 195 | }() 196 | func() { 197 | defer func() { 198 | if r := recover(); r == nil { 199 | t.Errorf("expected panic") 200 | } 201 | }() 202 | cbr.Tocollate(clt) 203 | }() 204 | } 205 | -------------------------------------------------------------------------------- /cmd/cmd_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "strings" 5 | import "testing" 6 | import "bytes" 7 | import "io/ioutil" 8 | import "os/exec" 9 | import "compress/gzip" 10 | 11 | var CMDEXEC = "./gson" 12 | 13 | var updateref = false 14 | 15 | func TestCmdArgs(t *testing.T) { 16 | testcases := [][]interface{}{ 17 | // json transformations 18 | { 19 | []string{"-inpfile", "example.json", "-json2value"}, 20 | []byte("Json: \"hello world\"\nValu: hello world\n"), 21 | }, 22 | { 23 | []string{"-inptxt", `"hello world"`, "-json2value"}, 24 | []byte("Json: \"hello world\"\nValu: hello world\n"), 25 | }, 26 | { 27 | []string{"-inpfile", "example.json", "-json2cbor"}, 28 | []byte("Json: \"hello world\"\n" + 29 | "Cbor: [107 104 101 108 108 111 32 119 111 114 108 100]\n" + 30 | "Cbor: \"khello world\"\n" + 31 | "Json: \"hello world\"\n"), 32 | }, 33 | { 34 | []string{"-inptxt", `"hello world"`, "-json2cbor"}, 35 | []byte("Json: \"hello world\"\n" + 36 | "Cbor: [107 104 101 108 108 111 32 119 111 114 108 100]\n" + 37 | "Cbor: \"khello world\"\n" + 38 | "Json: \"hello world\"\n"), 39 | }, 40 | { 41 | []string{"-inpfile", "example.json", "-json2collate"}, 42 | []byte("Json: \"hello world\"\n" + 43 | "Coll: \"Zhello world\\x00\\x00\"\n" + 44 | "Coll: [90 104 101 108 108 111 32 119 111 114 108 100 0 0]\n"), 45 | }, 46 | { 47 | []string{"-inptxt", `"hello world"`, "-json2collate"}, 48 | []byte("Json: \"hello world\"\n" + 49 | "Coll: \"Zhello world\\x00\\x00\"\n" + 50 | "Coll: [90 104 101 108 108 111 32 119 111 114 108 100 0 0]\n"), 51 | }, 52 | // json options 53 | { 54 | []string{"-inpfile", "../testdata/typical.json", "-pointers"}, 55 | testdataFile("../testdata/typical_pointers"), 56 | }, 57 | // cbor transformations 58 | { 59 | []string{"-inpfile", "example.cbor", "-cbor2value"}, 60 | []byte("Cbor: \"khello world\"\n" + 61 | "Cbor: [107 104 101 108 108 111 32 119 111 114 108 100]\n" + 62 | "Valu: hello world\n"), 63 | }, 64 | { 65 | []string{"-inptxt", "khello world", "-cbor2value"}, 66 | []byte("Cbor: \"khello world\"\n" + 67 | "Cbor: [107 104 101 108 108 111 32 119 111 114 108 100]\n" + 68 | "Valu: hello world\n"), 69 | }, 70 | { 71 | []string{"-inpfile", "example.cbor", "-cbor2json"}, 72 | []byte("Cbor: \"khello world\"\nJson: \"hello world\"\n"), 73 | }, 74 | { 75 | []string{"-inptxt", "khello world", "-cbor2json"}, 76 | []byte("Cbor: \"khello world\"\nJson: \"hello world\"\n"), 77 | }, 78 | { 79 | []string{"-inpfile", "example.cbor", "-cbor2collate"}, 80 | []byte("Cbor: \"khello world\"\n" + 81 | "Coll: \"Zhello world\\x00\\x00\"\n" + 82 | "Coll: [90 104 101 108 108 111 32 119 111 114 108 100 0 0]\n"), 83 | }, 84 | { 85 | []string{"-inptxt", "khello world", "-cbor2collate"}, 86 | []byte("Cbor: \"khello world\"\n" + 87 | "Coll: \"Zhello world\\x00\\x00\"\n" + 88 | "Coll: [90 104 101 108 108 111 32 119 111 114 108 100 0 0]\n"), 89 | }, 90 | { 91 | []string{"-inptxt", "khello world", "-cbor2collate"}, 92 | []byte("Cbor: \"khello world\"\n" + 93 | "Coll: \"Zhello world\\x00\\x00\"\n" + 94 | "Coll: [90 104 101 108 108 111 32 119 111 114 108 100 0 0]\n"), 95 | }, 96 | // cbor options 97 | { 98 | []string{"-inptxt", `[10,20]`, "-ct", "stream", "-json2cbor"}, 99 | []byte( 100 | "Json: [10,20]\n" + 101 | "Cbor: [159 251 64 36 0 0 0 0 0 0 251 64 52 0 0 0 0 0 0 255]\n" + 102 | "Cbor: \"\\x9f\\xfb@$\\x00\\x00\\x00\\x00\\x00\\x00\\xfb@4\\x00\\x00\\x00\\x00\\x00\\x00\\xff\"\n" + 103 | "Json: [10,20]\n"), 104 | }, 105 | { 106 | []string{"-inptxt", `[10,20]`, "-ct", "lenprefix", "-json2cbor"}, 107 | []byte( 108 | "Json: [10,20]\n" + 109 | "Cbor: [130 251 64 36 0 0 0 0 0 0 251 64 52 0 0 0 0 0 0]\n" + 110 | "Cbor: \"\\x82\\xfb@$\\x00\\x00\\x00\\x00\\x00\\x00\\xfb@4\\x00\\x00\\x00\\x00\\x00\\x00\"\n" + 111 | "Json: [10,20]\n"), 112 | }, 113 | // collate transformations 114 | { 115 | []string{"-inpfile", "example.coll", "-collate2value"}, 116 | []byte("Coll: \"Zhello world\\x00\\x00\"\nValu: hello world\n"), 117 | }, 118 | { 119 | []string{"-inpfile", "example.coll", "-collate2json"}, 120 | []byte("Coll: \"Zhello world\\x00\\x00\"\nJson: \"hello world\"\n"), 121 | }, 122 | { 123 | []string{"-inpfile", "example.coll", "-collate2cbor"}, 124 | []byte( 125 | "Coll: \"Zhello world\\x00\\x00\"\n" + 126 | "Cbor: \"khello world\"\n" + 127 | "Cbor: [107 104 101 108 108 111 32 119 111 114 108 100]\n"), 128 | }, 129 | // value transformations 130 | { 131 | []string{"-inptxt", `"hello world"`, "-value2json"}, 132 | []byte("Valu: hello world\nJson: \"hello world\"\n"), 133 | }, 134 | { 135 | []string{"-inptxt", `"hello world"`, "-value2cbor"}, 136 | []byte("Valu: hello world\nCbor: \"khello world\"\n" + 137 | "Cbor: [107 104 101 108 108 111 32 119 111 114 108 100]\n"), 138 | }, 139 | { 140 | []string{"-inptxt", `"hello world"`, "-value2collate"}, 141 | []byte("Valu: hello world\n" + 142 | "Coll: \"Zhello world\\x00\\x00\"\n" + 143 | "Coll: [90 104 101 108 108 111 32 119 111 114 108 100 0 0]\n"), 144 | }, 145 | } 146 | for _, testcase := range testcases { 147 | args := testcase[0].([]string) 148 | cmd := exec.Command(CMDEXEC, args...) 149 | out, err := cmd.CombinedOutput() 150 | if err != nil { 151 | t.Error(err) 152 | } 153 | ref := testcase[1].([]byte) 154 | if bytes.Compare(out, ref) != 0 { 155 | t.Logf(strings.Join(args, " ")) 156 | t.Logf("expected %q", ref) 157 | t.Errorf("got %q", out) 158 | } 159 | } 160 | } 161 | 162 | func testdataFile(filename string) []byte { 163 | f, err := os.Open(filename) 164 | if err != nil { 165 | panic(err) 166 | } 167 | defer f.Close() 168 | 169 | var data []byte 170 | if strings.HasSuffix(filename, ".gz") { 171 | gz, err := gzip.NewReader(f) 172 | if err != nil { 173 | panic(err) 174 | } 175 | data, err = ioutil.ReadAll(gz) 176 | if err != nil { 177 | panic(err) 178 | } 179 | } else { 180 | data, err = ioutil.ReadAll(f) 181 | if err != nil { 182 | panic(err) 183 | } 184 | } 185 | return data 186 | } 187 | -------------------------------------------------------------------------------- /lookup_cbor.go: -------------------------------------------------------------------------------- 1 | package gson 2 | 3 | import "strconv" 4 | import "bytes" 5 | 6 | import "fmt" 7 | 8 | func cborGet(doc []byte, segments [][]byte, item []byte, config *Config) int { 9 | _, _, start, end := cborLookup(doc, segments) 10 | if start < 0 { 11 | key := bytes2str(segments[len(segments)-1]) 12 | panic(fmt.Sprintf("key %v not found", key)) 13 | } 14 | return copy(item, doc[start:end]) 15 | } 16 | 17 | func cborSet( 18 | doc []byte, segments [][]byte, item, newdoc, olditem []byte, 19 | config *Config) (int, int) { 20 | 21 | var x int 22 | 23 | cont, _, start, end := cborLookup(doc, segments) 24 | 25 | m := copy(newdoc, doc[:cont]) 26 | 27 | if start < 0 { 28 | x, m = addlength(cont, m, doc, newdoc) 29 | key := bytes2str(segments[len(segments)-1]) 30 | m += valtext2cbor(key, newdoc[m:]) 31 | m += copy(newdoc[m:], item) 32 | m += copy(newdoc[m:], doc[x:]) 33 | n := copy(olditem, item) 34 | return m, n 35 | } 36 | m += copy(newdoc[m:], doc[cont:start]) 37 | m += copy(newdoc[m:], item) 38 | m += copy(newdoc[m:], doc[end:]) 39 | n := copy(olditem, doc[start:end]) 40 | return m, n 41 | } 42 | 43 | func cborPrepend( 44 | doc []byte, segments [][]byte, item, newdoc []byte, config *Config) int { 45 | 46 | var x int 47 | 48 | _, _, start, _ := cborLookup(doc, segments) 49 | major, _ := cborMajor(doc[start]), cborInfo(doc[start]) 50 | if major != cborType4 { 51 | panic("cannot prepend to non array containers") 52 | } 53 | 54 | m := copy(newdoc, doc[:start]) 55 | x, m = addlength(start, m, doc, newdoc) 56 | m += copy(newdoc[m:], item) 57 | m += copy(newdoc[m:], doc[x:]) 58 | return m 59 | } 60 | 61 | func cborAppend( 62 | doc []byte, segments [][]byte, item, newdoc []byte, config *Config) int { 63 | 64 | var x int 65 | 66 | _, _, start, end := cborLookup(doc, segments) 67 | major, info := cborMajor(doc[start]), cborInfo(doc[start]) 68 | if major != cborType4 { 69 | panic("cannot append to non array containers") 70 | } 71 | 72 | m := copy(newdoc, doc[:start]) 73 | x, m = addlength(start, m, doc, newdoc) 74 | if info == cborIndefiniteLength { 75 | m += copy(newdoc[m:], doc[x:end-1]) 76 | m += copy(newdoc[m:], item) 77 | m += copy(newdoc[m:], doc[end-1:]) 78 | return m 79 | } 80 | m += copy(newdoc[m:], doc[x:end]) 81 | m += copy(newdoc[m:], item) 82 | m += copy(newdoc[m:], doc[end:]) 83 | return m 84 | } 85 | 86 | func cborDel( 87 | doc []byte, segments [][]byte, newdoc, deleted []byte, 88 | config *Config) (int, int) { 89 | 90 | var x int 91 | 92 | cont, keyn, start, end := cborLookup(doc, segments) 93 | 94 | m := copy(newdoc, doc[:cont]) 95 | 96 | major, _ := cborMajor(doc[cont]), cborInfo(doc[cont]) 97 | switch major { 98 | case cborType4: 99 | if keyn >= 0 { 100 | panic("cborType4 expected keyn to be -1") 101 | } 102 | x, m = deletelength(cont, m, doc, newdoc) 103 | m += copy(newdoc[m:], doc[x:start]) 104 | m += copy(newdoc[m:], doc[end:]) 105 | n := copy(deleted, doc[start:end]) 106 | return m, n 107 | 108 | case cborType5: 109 | if keyn < 0 { 110 | panic("cborType5 expected keyn to be > 0") 111 | } 112 | x, m = deletelength(cont, m, doc, newdoc) 113 | m += copy(newdoc[m:], doc[x:keyn]) 114 | m += copy(newdoc[m:], doc[end:]) 115 | n := copy(deleted, doc[start:end]) 116 | return m, n 117 | } 118 | panic("unreachable code") 119 | } 120 | 121 | func cborLookup(doc []byte, segments [][]byte) (cont, keyn, start, end int) { 122 | var ln int 123 | end = len(doc) 124 | 125 | nextseg: 126 | for i, segment := range segments { 127 | major, info := cborMajor(doc[start]), cborInfo(doc[start]) 128 | switch major { 129 | case cborType4: 130 | idx, count := segment2idx(segment), 0 131 | cont, keyn = start, -1 132 | if info == cborIndefiniteLength { 133 | for end = start + 1; doc[end] != brkstp; count++ { 134 | _, n := cborItem(doc[end:]) 135 | start, end = end, end+n 136 | if count == idx { 137 | continue nextseg 138 | } 139 | } 140 | panic(fmt.Sprintf("index %v overflow", idx)) 141 | } 142 | ln, end = cborItemLength(doc[start:]) 143 | end += start 144 | for ; count < ln; count++ { 145 | _, n := cborItem(doc[end:]) 146 | start, end = end, end+n 147 | if count == idx { 148 | continue nextseg 149 | } 150 | } 151 | panic(fmt.Sprintf("index %v overflow", idx)) 152 | 153 | case cborType5: 154 | cont = start 155 | if info == cborIndefiniteLength { 156 | for end = start + 1; doc[end] != brkstp; { 157 | _, m := cborItem(doc[end:]) 158 | _, n := cborItem(doc[end+m:]) 159 | keyn, start, end = end, end+m, end+m+n 160 | x, y := cborItemLength(doc[keyn:]) 161 | if bytes.Compare(doc[keyn+y:keyn+y+x], segment) == 0 { 162 | continue nextseg 163 | } 164 | } 165 | if i == (len(segments) - 1) { // leaf 166 | return cont, -1, -1, -1 167 | } 168 | panic(fmt.Sprintf("key %v not found", bytes2str(segment))) 169 | } 170 | ln, end = cborItemLength(doc[start:]) 171 | end += start 172 | for i := 0; i < ln; i++ { 173 | _, m := cborItem(doc[end:]) 174 | _, n := cborItem(doc[end+m:]) 175 | keyn, start, end = end, end+m, end+m+n 176 | x, y := cborItemLength(doc[keyn:]) 177 | if bytes.Compare(doc[keyn+y:keyn+y+x], segment) == 0 { 178 | continue nextseg 179 | } 180 | } 181 | if i == (len(segments) - 1) { // missing 182 | return cont, -1, -1, -1 183 | } 184 | panic(fmt.Sprintf("key %v not found", bytes2str(segment))) 185 | } 186 | } 187 | return 188 | } 189 | 190 | func segment2idx(segment []byte) int { 191 | idx, err := strconv.Atoi(bytes2str(segment)) 192 | if err != nil { 193 | fmsg := "pointer %v expected to be array index" 194 | panic(fmt.Sprintf(fmsg, bytes2str(segment))) 195 | } else if idx < 0 { 196 | panic(fmt.Sprintf("array index %v can be < 0", idx)) 197 | } 198 | return idx 199 | } 200 | 201 | func addlength(cont, m int, doc, newdoc []byte) (int, int) { 202 | var x, ln int 203 | 204 | major, info := cborMajor(doc[cont]), cborInfo(doc[cont]) 205 | 206 | if info == cborIndefiniteLength { 207 | newdoc[m] = doc[cont] 208 | return cont + 1, m + 1 209 | } 210 | ln, x = cborItemLength(doc[cont:]) 211 | y := valuint642cbor(uint64(ln+1), newdoc[m:]) 212 | newdoc[m] = (newdoc[m] & 0x1f) | major // fix the type from type0->type4 213 | return cont + x, m + y 214 | } 215 | 216 | func deletelength(cont, m int, doc, newdoc []byte) (int, int) { 217 | var x, ln int 218 | 219 | major, info := cborMajor(doc[cont]), cborInfo(doc[cont]) 220 | 221 | if info == cborIndefiniteLength { 222 | newdoc[m] = doc[cont] 223 | return cont + 1, m + 1 224 | } 225 | ln, x = cborItemLength(doc[cont:]) 226 | y := valuint642cbor(uint64(ln-1), newdoc[m:]) 227 | newdoc[m] = (newdoc[m] & 0x1f) | major // fix the type from type0->type4 228 | return x + cont, m + y 229 | } 230 | -------------------------------------------------------------------------------- /bench/msgpack_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "bytes" 4 | import "testing" 5 | 6 | import "github.com/vmihailenco/msgpack" 7 | 8 | func BenchmarkMPEncNil(b *testing.B) { 9 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 10 | enc := msgpack.NewEncoder(buf) 11 | for i := 0; i < b.N; i++ { 12 | buf.Reset() 13 | enc.Encode(nil) 14 | } 15 | b.SetBytes(int64(buf.Len())) 16 | } 17 | 18 | func BenchmarkMPEncInt64(b *testing.B) { 19 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 20 | enc := msgpack.NewEncoder(buf) 21 | for i := 0; i < b.N; i++ { 22 | buf.Reset() 23 | enc.Encode(9223372036854775807) 24 | } 25 | b.SetBytes(int64(buf.Len())) 26 | } 27 | 28 | func BenchmarkMPEncUint64(b *testing.B) { 29 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 30 | enc := msgpack.NewEncoder(buf) 31 | for i := 0; i < b.N; i++ { 32 | buf.Reset() 33 | enc.Encode(9223372036854775807) 34 | } 35 | b.SetBytes(int64(buf.Len())) 36 | } 37 | 38 | func BenchmarkMPEncFloat64(b *testing.B) { 39 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 40 | enc := msgpack.NewEncoder(buf) 41 | for i := 0; i < b.N; i++ { 42 | buf.Reset() 43 | enc.Encode(123456.123456) 44 | } 45 | b.SetBytes(int64(buf.Len())) 46 | } 47 | 48 | func BenchmarkMPEncBool(b *testing.B) { 49 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 50 | enc := msgpack.NewEncoder(buf) 51 | for i := 0; i < b.N; i++ { 52 | buf.Reset() 53 | enc.Encode(true) 54 | } 55 | b.SetBytes(int64(buf.Len())) 56 | } 57 | 58 | func BenchmarkMPEncArr(b *testing.B) { 59 | val := []interface{}{5, 5.0, "hello world", true, nil} 60 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 61 | enc := msgpack.NewEncoder(buf) 62 | for i := 0; i < b.N; i++ { 63 | buf.Reset() 64 | enc.Encode(val) 65 | } 66 | b.SetBytes(int64(buf.Len())) 67 | } 68 | 69 | func BenchmarkMPEncMap(b *testing.B) { 70 | val := map[string]interface{}{ 71 | "key0": 5, 72 | "key1": 5.0, 73 | "key2": "hello world", 74 | "key3": true, 75 | "key4": nil, 76 | } 77 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 78 | enc := msgpack.NewEncoder(buf) 79 | for i := 0; i < b.N; i++ { 80 | buf.Reset() 81 | enc.Encode(val) 82 | } 83 | b.SetBytes(int64(buf.Len())) 84 | } 85 | 86 | func BenchmarkMPEncBytes(b *testing.B) { 87 | val := []byte("hello world") 88 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 89 | enc := msgpack.NewEncoder(buf) 90 | for i := 0; i < b.N; i++ { 91 | buf.Reset() 92 | enc.Encode(val) 93 | } 94 | b.SetBytes(int64(buf.Len())) 95 | } 96 | 97 | func BenchmarkMPEncString(b *testing.B) { 98 | val := "hello world" 99 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 100 | enc := msgpack.NewEncoder(buf) 101 | for i := 0; i < b.N; i++ { 102 | buf.Reset() 103 | enc.Encode(val) 104 | } 105 | b.SetBytes(int64(buf.Len())) 106 | } 107 | 108 | func BenchmarkMPDecNil(b *testing.B) { 109 | var val interface{} 110 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 111 | enc := msgpack.NewEncoder(buf) 112 | enc.Encode(nil) 113 | 114 | out := make([]byte, 1024) 115 | out = out[:copy(out, buf.Bytes())] 116 | dec := msgpack.NewDecoder(buf) 117 | for i := 0; i < b.N; i++ { 118 | buf.Reset() 119 | buf.Write(out) 120 | dec.Decode(val) 121 | } 122 | } 123 | 124 | func BenchmarkMPDecInt64(b *testing.B) { 125 | var val int64 126 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 127 | enc := msgpack.NewEncoder(buf) 128 | enc.Encode(9223372036854775807) 129 | 130 | out := make([]byte, 1024) 131 | out = out[:copy(out, buf.Bytes())] 132 | dec := msgpack.NewDecoder(buf) 133 | for i := 0; i < b.N; i++ { 134 | buf.Reset() 135 | buf.Write(out) 136 | dec.Decode(&val) 137 | } 138 | } 139 | 140 | func BenchmarkMPDecUint64(b *testing.B) { 141 | var val uint64 142 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 143 | enc := msgpack.NewEncoder(buf) 144 | enc.Encode(9223372036854775807) 145 | 146 | out := make([]byte, 1024) 147 | out = out[:copy(out, buf.Bytes())] 148 | dec := msgpack.NewDecoder(buf) 149 | for i := 0; i < b.N; i++ { 150 | buf.Reset() 151 | buf.Write(out) 152 | dec.Decode(&val) 153 | } 154 | } 155 | 156 | func BenchmarkMPDecFloat64(b *testing.B) { 157 | var val float64 158 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 159 | enc := msgpack.NewEncoder(buf) 160 | enc.Encode(123456.123456) 161 | 162 | out := make([]byte, 1024) 163 | out = out[:copy(out, buf.Bytes())] 164 | dec := msgpack.NewDecoder(buf) 165 | for i := 0; i < b.N; i++ { 166 | buf.Reset() 167 | buf.Write(out) 168 | dec.Decode(&val) 169 | } 170 | } 171 | 172 | func BenchmarkMPDecBool(b *testing.B) { 173 | var val bool 174 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 175 | enc := msgpack.NewEncoder(buf) 176 | enc.Encode(true) 177 | 178 | out := make([]byte, 1024) 179 | out = out[:copy(out, buf.Bytes())] 180 | dec := msgpack.NewDecoder(buf) 181 | for i := 0; i < b.N; i++ { 182 | buf.Reset() 183 | buf.Write(out) 184 | dec.Decode(&val) 185 | } 186 | } 187 | 188 | func BenchmarkMPDecArr(b *testing.B) { 189 | var val []interface{} 190 | inp := []interface{}{5, 5.0, "hello world", true, nil} 191 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 192 | enc := msgpack.NewEncoder(buf) 193 | enc.Encode(inp) 194 | 195 | out := make([]byte, 1024) 196 | out = out[:copy(out, buf.Bytes())] 197 | dec := msgpack.NewDecoder(buf) 198 | for i := 0; i < b.N; i++ { 199 | buf.Reset() 200 | buf.Write(out) 201 | dec.Decode(&val) 202 | val = nil 203 | } 204 | } 205 | 206 | func BenchmarkMPDecMap(b *testing.B) { 207 | var val map[string]interface{} 208 | inp := map[string]interface{}{ 209 | "key0": 5, 210 | "key1": 5.0, 211 | "key2": "hello world", 212 | "key3": true, 213 | "key4": nil, 214 | } 215 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 216 | enc := msgpack.NewEncoder(buf) 217 | enc.Encode(inp) 218 | 219 | out := make([]byte, 1024) 220 | out = out[:copy(out, buf.Bytes())] 221 | dec := msgpack.NewDecoder(buf) 222 | for i := 0; i < b.N; i++ { 223 | buf.Reset() 224 | buf.Write(out) 225 | dec.Decode(&val) 226 | val = nil 227 | } 228 | } 229 | 230 | func BenchmarkMPDecBytes(b *testing.B) { 231 | var val []byte 232 | inp := []byte("hello world") 233 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 234 | enc := msgpack.NewEncoder(buf) 235 | enc.Encode(inp) 236 | 237 | out := make([]byte, 1024) 238 | out = out[:copy(out, buf.Bytes())] 239 | dec := msgpack.NewDecoder(buf) 240 | for i := 0; i < b.N; i++ { 241 | buf.Reset() 242 | buf.Write(out) 243 | dec.Decode(&val) 244 | } 245 | } 246 | 247 | func BenchmarkMPDecString(b *testing.B) { 248 | var val string 249 | inp := "hello world" 250 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) 251 | enc := msgpack.NewEncoder(buf) 252 | enc.Encode(inp) 253 | 254 | out := make([]byte, 1024) 255 | out = out[:copy(out, buf.Bytes())] 256 | dec := msgpack.NewDecoder(buf) 257 | for i := 0; i < b.N; i++ { 258 | buf.Reset() 259 | buf.Write(out) 260 | dec.Decode(&val) 261 | } 262 | } 263 | --------------------------------------------------------------------------------