diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-30 02:36:25 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-08-17 22:50:57 -0600 |
commit | 13b65d51ffc9768464e8330fdb73b6febd7410af (patch) | |
tree | 271fe78abc75573a330353632171284ccf2ecd47 | |
parent | eb4e771e2a99edeb5cc3a1511ab611480f98255d (diff) |
json: Implement a bunch of streaming JSON encoding/decoding
-rw-r--r-- | go.mod | 5 | ||||
-rw-r--r-- | go.sum | 10 | ||||
-rw-r--r-- | lib/btrfs/btrfsitem/item_extentcsum.go | 34 | ||||
-rw-r--r-- | lib/btrfs/btrfssum/csum.go | 20 | ||||
-rw-r--r-- | lib/btrfsprogs/btrfsinspect/csums.go | 80 | ||||
-rw-r--r-- | lib/containers/optional.go | 26 |
6 files changed, 170 insertions, 5 deletions
@@ -7,6 +7,7 @@ module git.lukeshu.com/btrfs-progs-ng go 1.19 require ( + git.lukeshu.com/go/lowmemjson v0.0.0-20220818015700-3bd2e0e93647 github.com/datawire/dlib v1.3.0 github.com/datawire/ocibuild v0.0.3-0.20220423003204-fc6a4e9f90dc github.com/davecgh/go-spew v1.1.1 @@ -15,7 +16,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.8.0 golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf golang.org/x/text v0.3.7 ) @@ -26,7 +27,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/jacobsa/fuse => github.com/lukeshu/jacobsa-fuse v0.0.0-20220706162300-f42bfdd0fc53 @@ -1,3 +1,5 @@ +git.lukeshu.com/go/lowmemjson v0.0.0-20220818015700-3bd2e0e93647 h1:/gQH3jRZbslWRF5qMvB+jjgvOQCbbS0cDkHy6VSw8v8= +git.lukeshu.com/go/lowmemjson v0.0.0-20220818015700-3bd2e0e93647/go.mod h1:7StdaFpmZNKYJmQ67fGbzcIcnrGjmD54f/2WbeHLaBw= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/datawire/dlib v1.3.0 h1:KkmyXU1kwm3oPBk1ypR70YbcOlEXWzEbx5RE0iRXTGk= github.com/datawire/dlib v1.3.0/go.mod h1:NiGDmetmbkBvtznpWSx6C0vA0s0LK9aHna3LJDqjruk= @@ -32,10 +34,12 @@ github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf h1:oXVg4h2qJDd9htKxb5SCpFBHLipW6hXmL3qpUixS2jw= golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -56,5 +60,5 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lib/btrfs/btrfsitem/item_extentcsum.go b/lib/btrfs/btrfsitem/item_extentcsum.go index b35d333..eedd044 100644 --- a/lib/btrfs/btrfsitem/item_extentcsum.go +++ b/lib/btrfs/btrfsitem/item_extentcsum.go @@ -5,7 +5,11 @@ package btrfsitem import ( + "encoding/hex" "fmt" + "io" + + "git.lukeshu.com/go/lowmemjson" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfssum" ) @@ -43,3 +47,33 @@ func (o ExtentCSum) MarshalBinary() ([]byte, error) { } return dat, nil } + +var ( + _ lowmemjson.Encodable = ExtentCSum{} +) + +func (o ExtentCSum) EncodeJSON(w io.Writer) error { + if _, err := fmt.Fprintf(w, `{"ChecksumSize":%d,"Sums":[`, o.ChecksumSize); err != nil { + return err + } + for i, sum := range o.Sums { + if i > 0 { + if _, err := w.Write([]byte(",")); err != nil { + return err + } + } + if _, err := w.Write([]byte(`"`)); err != nil { + return err + } + if _, err := hex.NewEncoder(w).Write(sum[:o.ChecksumSize]); err != nil { + return err + } + if _, err := w.Write([]byte(`"`)); err != nil { + return err + } + } + if _, err := w.Write([]byte(`]}`)); err != nil { + return err + } + return nil +} diff --git a/lib/btrfs/btrfssum/csum.go b/lib/btrfs/btrfssum/csum.go index 8f9ac1a..c7c1f37 100644 --- a/lib/btrfs/btrfssum/csum.go +++ b/lib/btrfs/btrfssum/csum.go @@ -5,6 +5,7 @@ package btrfssum import ( + "encoding" "encoding/binary" "encoding/hex" "fmt" @@ -15,10 +16,29 @@ import ( type CSum [0x20]byte +var ( + _ fmt.Stringer = CSum{} + _ fmt.Formatter = CSum{} + _ encoding.TextMarshaler = CSum{} + _ encoding.TextUnmarshaler = (*CSum)(nil) +) + func (csum CSum) String() string { return hex.EncodeToString(csum[:]) } +func (csum CSum) MarshalText() ([]byte, error) { + var ret [len(csum) * 2]byte + hex.Encode(ret[:], csum[:]) + return ret[:], nil +} + +func (csum *CSum) UnmarshalText(text []byte) error { + *csum = CSum{} + _, err := hex.Decode(csum[:], text) + return err +} + func (csum CSum) Fmt(typ CSumType) string { return hex.EncodeToString(csum[:typ.Size()]) } diff --git a/lib/btrfsprogs/btrfsinspect/csums.go b/lib/btrfsprogs/btrfsinspect/csums.go index 78bf915..6335cb9 100644 --- a/lib/btrfsprogs/btrfsinspect/csums.go +++ b/lib/btrfsprogs/btrfsinspect/csums.go @@ -6,7 +6,11 @@ package btrfsinspect import ( "context" + "fmt" "io" + "strings" + + "git.lukeshu.com/go/lowmemjson" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsitem" "git.lukeshu.com/btrfs-progs-ng/lib/btrfs/btrfsvol" @@ -17,6 +21,82 @@ import ( type ShortSum string +var ( + _ lowmemjson.Encodable = ShortSum("") + _ lowmemjson.Decodable = (*ShortSum)(nil) +) + +func (sum ShortSum) EncodeJSON(w io.Writer) error { + const hextable = "0123456789abcdef" + var buf [2]byte + buf[0] = '"' + if _, err := w.Write(buf[:1]); err != nil { + return err + } + for i := 0; i < len(sum); i++ { + buf[0] = hextable[sum[i]>>4] + buf[1] = hextable[sum[i]&0x0f] + if _, err := w.Write(buf[:]); err != nil { + return err + } + } + buf[0] = '"' + if _, err := w.Write(buf[:1]); err != nil { + return err + } + return nil +} + +func deHex(r rune) (byte, bool) { + if r > 0xff { + return 0, false + } + c := byte(r) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + default: + return 0, false + } +} + +func (sum *ShortSum) DecodeJSON(r io.RuneScanner) error { + var out strings.Builder + if c, _, err := r.ReadRune(); err != nil { + return err + } else if c != '"' { + return fmt.Errorf("expected %q, got %q", '"', c) + } + for { + a, _, err := r.ReadRune() + if err != nil { + return err + } + if a == '"' { + break + } + aN, ok := deHex(a) + if !ok { + return fmt.Errorf("expected a hex digit, got %q", a) + } + b, _, err := r.ReadRune() + if err != nil { + return err + } + bN, ok := deHex(b) + if !ok { + return fmt.Errorf("expected a hex digit, got %q", b) + } + out.WriteByte(aN<<4 | bN) + } + *sum = ShortSum(out.String()) + return nil +} + // SumRun //////////////////////////////////////////////////////////// type SumRun[Addr btrfsvol.IntAddr[Addr]] struct { diff --git a/lib/containers/optional.go b/lib/containers/optional.go index 3055308..c0e7b32 100644 --- a/lib/containers/optional.go +++ b/lib/containers/optional.go @@ -4,7 +4,33 @@ package containers +import ( + "encoding/json" +) + type Optional[T any] struct { OK bool Val T } + +var ( + _ json.Marshaler = Optional[bool]{} + _ json.Unmarshaler = (*Optional[bool])(nil) +) + +func (o Optional[T]) MarshalJSON() ([]byte, error) { + if o.OK { + return json.Marshal(o.Val) + } else { + return []byte("null"), nil + } +} + +func (o *Optional[T]) UnmarshalJSON(dat []byte) error { + if string(dat) == "null" { + *o = Optional[T]{} + return nil + } + o.OK = true + return json.Unmarshal(dat, &o.Val) +} |