1
2
3
4
5
6
7 package jsonopts
8
9 import (
10 "encoding/json/internal"
11 "encoding/json/internal/jsonflags"
12 )
13
14
15 type Options interface {
16
17 JSONOptions(internal.NotForPublicUse)
18 }
19
20
21
22
23 type experimentalFormatTagSupporter interface{ ExperimentalSupportFormatTag() bool }
24
25
26
27 type Struct struct {
28 Flags jsonflags.Flags
29
30 CoderValues
31 ArshalValues
32 }
33
34 type CoderValues struct {
35 Indent string
36 IndentPrefix string
37 ByteLimit int64
38 DepthLimit int
39 }
40
41 type ArshalValues struct {
42
43
44
45
46 Marshalers any
47 Unmarshalers any
48
49 Format string
50 }
51
52
53 var DefaultOptionsV2 = Struct{
54 Flags: jsonflags.Flags{
55 Presence: uint64(jsonflags.DefaultV1Flags),
56 Values: uint64(0),
57 },
58 }
59
60
61 var DefaultOptionsV1 = Struct{
62 Flags: jsonflags.Flags{
63 Presence: uint64(jsonflags.DefaultV1Flags),
64 Values: uint64(jsonflags.DefaultV1Flags),
65 },
66 }
67
68 func (*Struct) JSONOptions(internal.NotForPublicUse) {}
69
70
71
72 var GetUnknownOption = func(Struct, Options) (any, bool) { panic("unknown option") }
73
74 func GetOption[T any](opts Options, setter func(T) Options) (T, bool) {
75
76 structOpts, ok := opts.(*Struct)
77 if !ok {
78 var structOpts2 Struct
79 structOpts2.Join(opts)
80 structOpts = &structOpts2
81 }
82
83
84 var zero T
85 switch opt := setter(zero).(type) {
86 case jsonflags.Bools:
87 v := structOpts.Flags.Get(opt)
88 ok := structOpts.Flags.Has(opt)
89 if !ok && opt == jsonflags.StringifyNumbers && structOpts.Flags.Get(jsonflags.StringTag) {
90 return any(true).(T), true
91 }
92 return any(v).(T), ok
93 case experimentalFormatTagSupporter:
94 v := structOpts.Flags.Get(jsonflags.FormatTagSupported)
95 ok := structOpts.Flags.Has(jsonflags.FormatTagSupported)
96 return any(v).(T), ok
97 case Indent:
98 if !structOpts.Flags.Has(jsonflags.Indent) {
99 return zero, false
100 }
101 return any(structOpts.Indent).(T), true
102 case IndentPrefix:
103 if !structOpts.Flags.Has(jsonflags.IndentPrefix) {
104 return zero, false
105 }
106 return any(structOpts.IndentPrefix).(T), true
107 case ByteLimit:
108 if !structOpts.Flags.Has(jsonflags.ByteLimit) {
109 return zero, false
110 }
111 return any(structOpts.ByteLimit).(T), true
112 case DepthLimit:
113 if !structOpts.Flags.Has(jsonflags.DepthLimit) {
114 return zero, false
115 }
116 return any(structOpts.DepthLimit).(T), true
117 default:
118 v, ok := GetUnknownOption(*structOpts, opt)
119 return v.(T), ok
120 }
121 }
122
123
124
125 var JoinUnknownOption = func(Struct, Options) Struct { panic("unknown option") }
126
127 func (dst *Struct) Join(srcs ...Options) {
128 for _, src := range srcs {
129 switch src := src.(type) {
130 case nil:
131 continue
132 case jsonflags.Bools:
133 dst.Flags.Set(src)
134 case experimentalFormatTagSupporter:
135 if src.ExperimentalSupportFormatTag() {
136 dst.Flags.Set(jsonflags.FormatTagSupported | 1)
137 } else {
138 dst.Flags.Set(jsonflags.FormatTagSupported | 0)
139 }
140 case Indent:
141 dst.Flags.Set(jsonflags.Multiline | jsonflags.Indent | 1)
142 dst.Indent = string(src)
143 case IndentPrefix:
144 dst.Flags.Set(jsonflags.Multiline | jsonflags.IndentPrefix | 1)
145 dst.IndentPrefix = string(src)
146 case ByteLimit:
147 dst.Flags.Set(jsonflags.ByteLimit | 1)
148 dst.ByteLimit = int64(src)
149 case DepthLimit:
150 dst.Flags.Set(jsonflags.DepthLimit | 1)
151 dst.DepthLimit = int(src)
152 case *Struct:
153 dst.Flags.Join(src.Flags)
154 if src.Flags.Has(jsonflags.NonBooleanFlags) {
155 if src.Flags.Has(jsonflags.Indent) {
156 dst.Indent = src.Indent
157 }
158 if src.Flags.Has(jsonflags.IndentPrefix) {
159 dst.IndentPrefix = src.IndentPrefix
160 }
161 if src.Flags.Has(jsonflags.ByteLimit) {
162 dst.ByteLimit = src.ByteLimit
163 }
164 if src.Flags.Has(jsonflags.DepthLimit) {
165 dst.DepthLimit = src.DepthLimit
166 }
167 if src.Flags.Has(jsonflags.Marshalers) {
168 dst.Marshalers = src.Marshalers
169 }
170 if src.Flags.Has(jsonflags.Unmarshalers) {
171 dst.Unmarshalers = src.Unmarshalers
172 }
173 if src.Flags.Has(jsonflags.FormatTag) {
174 dst.Format = src.Format
175 }
176 }
177 default:
178 *dst = JoinUnknownOption(*dst, src)
179 }
180 }
181 }
182
183
184 func (s *Struct) InitializeMultiline() {
185 if !s.Flags.Has(jsonflags.SpaceAfterColon) {
186 s.Flags.Set(jsonflags.SpaceAfterColon | 1)
187 }
188 if !s.Flags.Has(jsonflags.SpaceAfterComma) {
189 s.Flags.Set(jsonflags.SpaceAfterComma | 0)
190 }
191 if !s.Flags.Has(jsonflags.Indent) {
192 s.Flags.Set(jsonflags.Indent | 1)
193 s.Indent = "\t"
194 }
195 }
196
197
198 func ChangedWhitespace(s1, s2 Struct) bool {
199 return s1.Flags.Get(jsonflags.Multiline) != s2.Flags.Get(jsonflags.Multiline) ||
200 s1.Flags.Get(jsonflags.SpaceAfterColon) != s2.Flags.Get(jsonflags.SpaceAfterColon) ||
201 s1.Flags.Get(jsonflags.SpaceAfterComma) != s2.Flags.Get(jsonflags.SpaceAfterComma) ||
202 (s2.Flags.Get(jsonflags.Multiline) && (s1.Indent != s2.Indent || s1.IndentPrefix != s2.IndentPrefix))
203 }
204
205 type (
206 Indent string
207 IndentPrefix string
208 ByteLimit int64
209 DepthLimit int
210
211
212 )
213
214 func (Indent) JSONOptions(internal.NotForPublicUse) {}
215 func (IndentPrefix) JSONOptions(internal.NotForPublicUse) {}
216 func (ByteLimit) JSONOptions(internal.NotForPublicUse) {}
217 func (DepthLimit) JSONOptions(internal.NotForPublicUse) {}
218
View as plain text