1// Copyright 2015 xeipuuv ( https://github.com/xeipuuv ) 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// author xeipuuv 16// author-github https://github.com/xeipuuv 17// author-mail xeipuuv@gmail.com 18// 19// repository-name gojsonschema 20// repository-desc An implementation of JSON Schema, based on IETF's draft v4 - Go language. 21// 22// description Various utility functions. 23// 24// created 26-02-2013 25 26package gojsonschema 27 28import ( 29 "encoding/json" 30 "fmt" 31 "math" 32 "reflect" 33 "strconv" 34) 35 36func isKind(what interface{}, kind reflect.Kind) bool { 37 target := what 38 if isJsonNumber(what) { 39 // JSON Numbers are strings! 40 target = *mustBeNumber(what) 41 } 42 return reflect.ValueOf(target).Kind() == kind 43} 44 45func existsMapKey(m map[string]interface{}, k string) bool { 46 _, ok := m[k] 47 return ok 48} 49 50func isStringInSlice(s []string, what string) bool { 51 for i := range s { 52 if s[i] == what { 53 return true 54 } 55 } 56 return false 57} 58 59func marshalToJsonString(value interface{}) (*string, error) { 60 61 mBytes, err := json.Marshal(value) 62 if err != nil { 63 return nil, err 64 } 65 66 sBytes := string(mBytes) 67 return &sBytes, nil 68} 69 70func isJsonNumber(what interface{}) bool { 71 72 switch what.(type) { 73 74 case json.Number: 75 return true 76 } 77 78 return false 79} 80 81func checkJsonNumber(what interface{}) (isValidFloat64 bool, isValidInt64 bool, isValidInt32 bool) { 82 83 jsonNumber := what.(json.Number) 84 85 f64, errFloat64 := jsonNumber.Float64() 86 s64 := strconv.FormatFloat(f64, 'f', -1, 64) 87 _, errInt64 := strconv.ParseInt(s64, 10, 64) 88 89 isValidFloat64 = errFloat64 == nil 90 isValidInt64 = errInt64 == nil 91 92 _, errInt32 := strconv.ParseInt(s64, 10, 32) 93 isValidInt32 = isValidInt64 && errInt32 == nil 94 95 return 96 97} 98 99// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER 100const ( 101 max_json_float = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 102 min_json_float = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 103) 104 105func isFloat64AnInteger(f float64) bool { 106 107 if math.IsNaN(f) || math.IsInf(f, 0) || f < min_json_float || f > max_json_float { 108 return false 109 } 110 111 return f == float64(int64(f)) || f == float64(uint64(f)) 112} 113 114func mustBeInteger(what interface{}) *int { 115 116 if isJsonNumber(what) { 117 118 number := what.(json.Number) 119 120 _, _, isValidInt32 := checkJsonNumber(number) 121 122 if isValidInt32 { 123 124 int64Value, err := number.Int64() 125 if err != nil { 126 return nil 127 } 128 129 int32Value := int(int64Value) 130 return &int32Value 131 132 } else { 133 return nil 134 } 135 136 } 137 138 return nil 139} 140 141func mustBeNumber(what interface{}) *float64 { 142 143 if isJsonNumber(what) { 144 145 number := what.(json.Number) 146 float64Value, err := number.Float64() 147 148 if err == nil { 149 return &float64Value 150 } else { 151 return nil 152 } 153 154 } 155 156 return nil 157 158} 159 160// formats a number so that it is displayed as the smallest string possible 161func resultErrorFormatJsonNumber(n json.Number) string { 162 163 if int64Value, err := n.Int64(); err == nil { 164 return fmt.Sprintf("%d", int64Value) 165 } 166 167 float64Value, _ := n.Float64() 168 169 return fmt.Sprintf("%g", float64Value) 170} 171 172// formats a number so that it is displayed as the smallest string possible 173func resultErrorFormatNumber(n float64) string { 174 175 if isFloat64AnInteger(n) { 176 return fmt.Sprintf("%d", int64(n)) 177 } 178 179 return fmt.Sprintf("%g", n) 180} 181 182func convertDocumentNode(val interface{}) interface{} { 183 184 if lval, ok := val.([]interface{}); ok { 185 186 res := []interface{}{} 187 for _, v := range lval { 188 res = append(res, convertDocumentNode(v)) 189 } 190 191 return res 192 193 } 194 195 if mval, ok := val.(map[interface{}]interface{}); ok { 196 197 res := map[string]interface{}{} 198 199 for k, v := range mval { 200 res[k.(string)] = convertDocumentNode(v) 201 } 202 203 return res 204 205 } 206 207 return val 208} 209