File: es6numfmt.go

package info (click to toggle)
golang-webpki-org-jsoncanonicalizer 1.0.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 296 kB
  • sloc: makefile: 2
file content (59 lines) | stat: -rw-r--r-- 1,681 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Copyright 2021 Bret Jordan & Benedikt Thoma, All rights reserved.
// Copyright 2006-2019 WebPKI.org (http://webpki.org).
//
// Use of this source code is governed by an Apache 2.0 license that can be
// found in the LICENSE file in the root of the source tree.

package jcs

import (
	"errors"
	"math"
	"strconv"
	"strings"
)

const invalidPattern uint64 = 0x7ff0000000000000

// NumberToJSON converts numbers in IEEE-754 double precision into the
// format specified for JSON in EcmaScript Version 6 and forward.
// The core application for this is canonicalization per RFC 8785:
func NumberToJSON(ieeeF64 float64) (res string, err error) {
	ieeeU64 := math.Float64bits(ieeeF64)

	// Special case: NaN and Infinity are invalid in JSON
	if (ieeeU64 & invalidPattern) == invalidPattern {
		return "null", errors.New("Invalid JSON number: " + strconv.FormatUint(ieeeU64, 16))
	}

	// Special case: eliminate "-0" as mandated by the ES6-JSON/JCS specifications
	if ieeeF64 == 0 { // Right, this line takes both -0 and 0
		return "0", nil
	}

	// Deal with the sign separately
	var sign string = ""
	if ieeeF64 < 0 {
		ieeeF64 = -ieeeF64
		sign = "-"
	}

	// ES6 has a unique "g" format
	var format byte = 'e'
	if ieeeF64 < 1e+21 && ieeeF64 >= 1e-6 {
		format = 'f'
	}

	// The following should (in "theory") do the trick:
	es6Formatted := strconv.FormatFloat(ieeeF64, format, -1, 64)

	// Ryu version
	exponent := strings.IndexByte(es6Formatted, 'e')
	if exponent > 0 {
		// Go outputs "1e+09" which must be rewritten as "1e+9"
		if es6Formatted[exponent+2] == '0' {
			es6Formatted = es6Formatted[:exponent+2] + es6Formatted[exponent+3:]
		}
	}
	return sign + es6Formatted, nil
}