git.lukeshu.com/go/lowmemjson@v0.3.9-0.20230723050957-72f6d13f6fb2/reencode_indent.go (about) 1 // Copyright (C) 2022-2023 Luke Shumaker <lukeshu@lukeshu.com> 2 // 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 package lowmemjson 6 7 import ( 8 "git.lukeshu.com/go/lowmemjson/internal/jsonparse" 9 ) 10 11 type reEncodeIndent struct { 12 out reEncoderModule 13 14 // String to use to indent. 15 // 16 // Newlines are emitted *between* top-level values; a newline 17 // is not emitted after the *last* top-level value. 18 Indent string 19 20 // String to put before indents. 21 Prefix string 22 23 // state 24 lastNonSpace jsonparse.RuneType 25 lastNonSpaceNonEOF jsonparse.RuneType 26 curIndent int 27 } 28 29 var _ reEncoderModule = (*reEncodeIndent)(nil) 30 31 func (enc *reEncodeIndent) PopWriteBarrier() { 32 enc.lastNonSpace = enc.lastNonSpaceNonEOF 33 enc.out.PopWriteBarrier() 34 } 35 36 func (enc *reEncodeIndent) HandleRune(c rune, t jsonparse.RuneType, escape BackslashEscapeMode, stackSize int) error { 37 // emit newlines between top-level values 38 if enc.lastNonSpace == jsonparse.RuneTypeEOF && t != jsonparse.RuneTypeSpace { 39 if err := enc.out.HandleRune('\n', jsonparse.RuneTypeSpace, 0, 0); err != nil { 40 return err 41 } 42 } 43 44 // indent 45 switch t { 46 case jsonparse.RuneTypeSpace: 47 // let us manage whitespace, don't pass it through 48 return nil 49 case jsonparse.RuneTypeObjectEnd, jsonparse.RuneTypeArrayEnd: 50 enc.curIndent-- 51 switch enc.lastNonSpace { 52 case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: 53 // collapse 54 default: 55 if err := enc.emitNlIndent(stackSize + 1); err != nil { 56 return err 57 } 58 } 59 default: 60 switch enc.lastNonSpace { 61 case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeObjectComma, jsonparse.RuneTypeArrayBeg, jsonparse.RuneTypeArrayComma: 62 if err := enc.emitNlIndent(stackSize); err != nil { 63 return err 64 } 65 case jsonparse.RuneTypeObjectColon: 66 if err := enc.out.HandleRune(' ', jsonparse.RuneTypeSpace, 0, stackSize); err != nil { 67 return err 68 } 69 } 70 switch t { 71 case jsonparse.RuneTypeObjectBeg, jsonparse.RuneTypeArrayBeg: 72 enc.curIndent++ 73 } 74 } 75 76 if t != jsonparse.RuneTypeSpace { 77 enc.lastNonSpace = t 78 if t != jsonparse.RuneTypeEOF { 79 enc.lastNonSpaceNonEOF = t 80 } 81 } 82 return enc.out.HandleRune(c, t, escape, stackSize) 83 } 84 85 func (enc *reEncodeIndent) emitNlIndent(stackSize int) error { 86 if err := enc.out.HandleRune('\n', jsonparse.RuneTypeSpace, 0, stackSize); err != nil { 87 return err 88 } 89 for _, c := range enc.Prefix { 90 if err := enc.out.HandleRune(c, jsonparse.RuneTypeSpace, 0, stackSize); err != nil { 91 return err 92 } 93 } 94 for i := 0; i < enc.curIndent; i++ { 95 for _, c := range enc.Indent { 96 if err := enc.out.HandleRune(c, jsonparse.RuneTypeSpace, 0, stackSize); err != nil { 97 return err 98 } 99 } 100 } 101 return nil 102 }