forked from cedar-policy/cedar-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjson.go
113 lines (103 loc) · 2.18 KB
/
json.go
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package cedar
import (
"bytes"
"encoding/json"
"fmt"
)
var (
errJSONInvalidExtn = fmt.Errorf("invalid extension")
errJSONDecode = fmt.Errorf("error decoding json")
errJSONLongOutOfRange = fmt.Errorf("long out of range")
errJSONUnsupportedType = fmt.Errorf("unsupported type")
errJSONExtFnMatch = fmt.Errorf("json extn mismatch")
errJSONExtNotFound = fmt.Errorf("json extn not found")
errJSONEntityNotFound = fmt.Errorf("json entity not found")
)
type extn struct {
Fn string `json:"fn"`
Arg string `json:"arg"`
}
type extValueJSON struct {
Extn *extn `json:"__extn,omitempty"`
}
type extEntity struct {
Type string `json:"type"`
ID string `json:"id"`
}
type entityValueJSON struct {
Type *string `json:"type,omitempty"`
ID *string `json:"id,omitempty"`
Entity *extEntity `json:"__entity,omitempty"`
}
type explicitValue struct {
Value Value
}
func unmarshalJSON(b []byte, v *Value) error {
// TODO: make this faster if it matters
{
var res EntityUID
ptr := &res
if err := ptr.UnmarshalJSON(b); err == nil {
*v = res
return nil
}
}
{
var res extValueJSON
if err := json.Unmarshal(b, &res); err == nil && res.Extn != nil {
switch res.Extn.Fn {
case "ip":
val, err := ParseIPAddr(res.Extn.Arg)
if err != nil {
return err
}
*v = val
return nil
case "decimal":
val, err := ParseDecimal(res.Extn.Arg)
if err != nil {
return err
}
*v = val
return nil
default:
return errJSONInvalidExtn
}
}
}
if len(b) > 0 {
switch b[0] {
case '[':
var res Set
err := json.Unmarshal(b, &res)
*v = res
return err
case '{':
res := Record{}
err := json.Unmarshal(b, &res)
*v = res
return err
}
}
var res interface{}
dec := json.NewDecoder(bytes.NewBuffer(b))
dec.UseNumber()
if err := dec.Decode(&res); err != nil {
return fmt.Errorf("%w: %w", errJSONDecode, err)
}
switch vv := res.(type) {
case string:
*v = String(vv)
case bool:
*v = Boolean(vv)
case json.Number:
l, err := vv.Int64()
if err != nil {
return fmt.Errorf("%w: %w", errJSONLongOutOfRange, err)
}
*v = Long(l)
default:
return errJSONUnsupportedType
}
return nil
}