Skip to content

Commit f473b94

Browse files
authored
Public OrderedMap (#53)
1 parent 750d2ec commit f473b94

File tree

5 files changed

+383
-81
lines changed

5 files changed

+383
-81
lines changed

decode.go

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ func DefaultDecoderOptions() DecoderOptions {
4747

4848
type hjsonParser struct {
4949
DecoderOptions
50-
data []byte
51-
at int // The index of the current character
52-
ch byte // The current character
53-
structTypeCache map[reflect.Type]structFieldMap
50+
data []byte
51+
at int // The index of the current character
52+
ch byte // The current character
53+
structTypeCache map[reflect.Type]structFieldMap
54+
willMarshalToJSON bool
5455
}
5556

5657
var unmarshalerText = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
@@ -326,7 +327,7 @@ func (p *hjsonParser) white() {
326327
func (p *hjsonParser) readTfnns(dest reflect.Value, t reflect.Type) (interface{}, error) {
327328

328329
// Hjson strings can be quoteless
329-
// returns string, json.Number, true, false, or null.
330+
// returns string, (json.Number or float64), true, false, or null.
330331

331332
if isPunctuatorChar(p.ch) {
332333
return nil, p.errAt("Found a punctuator character '" + string(p.ch) + "' when expecting a quoteless string (check your syntax)")
@@ -369,8 +370,12 @@ func (p *hjsonParser) readTfnns(dest reflect.Value, t reflect.Type) (interface{}
369370
}
370371
default:
371372
if chf == '-' || chf >= '0' && chf <= '9' {
372-
// Always use json.Number because we will marshal to JSON.
373-
if n, err := tryParseNumber(value.Bytes(), false, true); err == nil {
373+
// Always use json.Number if we will marshal to JSON.
374+
if n, err := tryParseNumber(
375+
value.Bytes(),
376+
false,
377+
p.willMarshalToJSON || p.DecoderOptions.UseJSONNumber,
378+
); err == nil {
374379
return n, nil
375380
}
376381
}
@@ -477,7 +482,7 @@ func (p *hjsonParser) readObject(
477482
) (value interface{}, err error) {
478483
// Parse an object value.
479484

480-
var object orderedMap
485+
object := NewOrderedMap()
481486

482487
if !withoutBraces {
483488
// assuming ch == '{'
@@ -562,7 +567,7 @@ func (p *hjsonParser) readObject(
562567
if val, err = p.readValue(newDest, elemType); err != nil {
563568
return nil, err
564569
}
565-
object = append(object, keyVal{key, val})
570+
object.Set(key, val)
566571
p.white()
567572
// in Hjson the comma is optional and trailing commas are allowed
568573
if p.ch == ',' {
@@ -652,18 +657,27 @@ func Unmarshal(data []byte, v interface{}) error {
652657
return UnmarshalWithOptions(data, v, DefaultDecoderOptions())
653658
}
654659

655-
func orderedUnmarshal(data []byte, v interface{}, options DecoderOptions) (interface{}, error) {
660+
func orderedUnmarshal(
661+
data []byte,
662+
v interface{},
663+
options DecoderOptions,
664+
willMarshalToJSON bool,
665+
) (
666+
interface{},
667+
error,
668+
) {
656669
rv := reflect.ValueOf(v)
657670
if rv.Kind() != reflect.Ptr || rv.IsNil() {
658671
return nil, fmt.Errorf("Cannot unmarshal into non-pointer %v", reflect.TypeOf(v))
659672
}
660673

661674
parser := &hjsonParser{
662-
DecoderOptions: options,
663-
data: data,
664-
at: 0,
665-
ch: ' ',
666-
structTypeCache: map[reflect.Type]structFieldMap{},
675+
DecoderOptions: options,
676+
data: data,
677+
at: 0,
678+
ch: ' ',
679+
structTypeCache: map[reflect.Type]structFieldMap{},
680+
willMarshalToJSON: willMarshalToJSON,
667681
}
668682
parser.resetAt()
669683
value, err := parser.rootValue(rv)
@@ -677,17 +691,37 @@ func orderedUnmarshal(data []byte, v interface{}, options DecoderOptions) (inter
677691
// UnmarshalWithOptions parses the Hjson-encoded data and stores the result
678692
// in the value pointed to by v.
679693
//
680-
// Internally the Hjson input is converted to JSON, which is then used as input
681-
// to the function json.Unmarshal().
694+
// Unless v is of type *hjson.OrderedMap, the Hjson input is internally
695+
// converted to JSON, which is then used as input to the function
696+
// json.Unmarshal().
682697
//
683698
// For more details about the output from this function, see the documentation
684699
// for json.Unmarshal().
685700
func UnmarshalWithOptions(data []byte, v interface{}, options DecoderOptions) error {
686-
value, err := orderedUnmarshal(data, v, options)
701+
inOM, destinationIsOrderedMap := v.(*OrderedMap)
702+
if !destinationIsOrderedMap {
703+
pInOM, ok := v.(**OrderedMap)
704+
if ok {
705+
destinationIsOrderedMap = true
706+
inOM = &OrderedMap{}
707+
*pInOM = inOM
708+
}
709+
}
710+
711+
value, err := orderedUnmarshal(data, v, options, !destinationIsOrderedMap)
687712
if err != nil {
688713
return err
689714
}
690715

716+
if destinationIsOrderedMap {
717+
if outOM, ok := value.(*OrderedMap); ok {
718+
*inOM = *outOM
719+
return nil
720+
}
721+
return fmt.Errorf("Cannot unmarshal into hjson.OrderedMap: Try %v as destination instead",
722+
reflect.TypeOf(v))
723+
}
724+
691725
// Convert to JSON so we can let json.Unmarshal() handle all destination
692726
// types (including interfaces json.Unmarshaler and encoding.TextUnmarshaler)
693727
// and merging.

encode.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ func (e *hjsonEncoder) useMarshalerJSON(
210210
decOpt := DefaultDecoderOptions()
211211
decOpt.UseJSONNumber = true
212212
var dummyDest interface{}
213-
jsonRoot, err := orderedUnmarshal(b, &dummyDest, decOpt)
213+
jsonRoot, err := orderedUnmarshal(b, &dummyDest, decOpt, false)
214214
if err != nil {
215215
return err
216216
}
@@ -262,12 +262,12 @@ func (e *hjsonEncoder) str(value reflect.Value, noIndent bool, separator string,
262262
// Our internal orderedMap implements marshalerJSON. We must therefore place
263263
// this check before checking marshalerJSON. Calling orderedMap.MarshalJSON()
264264
// from this function would cause an infinite loop.
265-
if om, ok := value.Interface().(orderedMap); ok {
265+
if om, ok := value.Interface().(OrderedMap); ok {
266266
var fis []fieldInfo
267-
for _, elem := range om {
267+
for _, key := range om.Keys {
268268
fis = append(fis, fieldInfo{
269-
field: reflect.ValueOf(elem.value),
270-
name: elem.key,
269+
field: reflect.ValueOf(om.Map[key]),
270+
name: key,
271271
})
272272
}
273273
return e.writeFields(fis, noIndent, separator, isRootObject)

0 commit comments

Comments
 (0)