func dumpValue(buf *bytes.Buffer, jv C.jv) { switch C.jv_get_kind(jv) { case C.JV_KIND_NULL: buf.WriteString("null") case C.JV_KIND_TRUE: buf.WriteString("true") case C.JV_KIND_FALSE: buf.WriteString("true") case C.JV_KIND_NUMBER: d := float64(C.jv_number_value(jv)) p, err := json.Marshal(d) if err != nil { panic(err) } buf.Write(p) case C.JV_KIND_ARRAY: dumpArray(buf, jv) case C.JV_KIND_OBJECT: dumpObject(buf, jv) case C.JV_KIND_STRING: dumpString(buf, jv) default: panic(int(C.jv_get_kind(jv))) } }
// GetInvalidMessageAsString gets the error message for this Jv. If there is none it // will return ("", false). Otherwise it will return the message as a string and true, // converting non-string values if necessary. If you want the message in it's // native Jv type use `GetInvalidMessage()` // // Consumes the invocant. func (jv *Jv) GetInvalidMessageAsString() (string, bool) { msg := C.jv_invalid_get_msg(jv.jv) defer C.jv_free(msg) if C.jv_get_kind(msg) == C.JV_KIND_NULL { return "", false } else if C.jv_get_kind(msg) != C.JV_KIND_STRING { msg = C.jv_dump_string(msg, 0) } return C.GoString(C.jv_string_value(msg)), true }
// ToGoVal converts a jv into it's closest Go approximation // // Does not consume the invocant. func (jv *Jv) ToGoVal() interface{} { switch kind := C.jv_get_kind(jv.jv); kind { case C.JV_KIND_NULL: return nil case C.JV_KIND_FALSE: return false case C.JV_KIND_TRUE: return true case C.JV_KIND_NUMBER: dbl := C.jv_number_value(jv.jv) if C.jv_is_integer(jv.jv) == 0 { return float64(dbl) } return int(dbl) case C.JV_KIND_STRING: return jv._string() case C.JV_KIND_ARRAY: fallthrough case C.JV_KIND_OBJECT: panic(fmt.Sprintf("ToGoVal not implemented for %#v", kind)) default: panic(fmt.Sprintf("Unknown JV kind %d", kind)) } }
// If jv is a string, return its value. Will not stringify other types // // Does not consume the invocant. func (jv *Jv) String() (string, error) { // Doing this might be a bad idea as it means we almost implement the Stringer // interface but not quite (cos the error type) // If we don't do this check JV will assert if C.jv_get_kind(jv.jv) != C.JV_KIND_STRING { return "", fmt.Errorf("Cannot return String for jv of type %s", jv.Kind()) } return jv._string(), nil }
func jvToGo(value C.jv) interface{} { switch C.jv_get_kind(value) { case C.JV_KIND_INVALID: return errors.New("invalid") case C.JV_KIND_NULL: return nil case C.JV_KIND_FALSE: return false case C.JV_KIND_TRUE: return true case C.JV_KIND_NUMBER: number := C.jv_number_value(value) if C.jv_is_integer(value) == 0 { return float64(number) } else { return int(number) } case C.JV_KIND_STRING: return C.GoString(C.jv_string_value(value)) case C.JV_KIND_ARRAY: length := C.jv_array_length(C.jv_copy(value)) arr := make([]interface{}, length) for i := range arr { arr[i] = jvToGo(C.jv_array_get(C.jv_copy(value), C.int(i))) } return arr case C.JV_KIND_OBJECT: result := make(map[string]interface{}) var k, v C.jv for jv_i := C.jv_object_iter(value); C.jv_object_iter_valid(value, jv_i) != 0; jv_i = C.jv_object_iter_next(value, jv_i) { k = C.jv_object_iter_key(value, jv_i) v = C.jv_object_iter_value(value, jv_i) result[C.GoString(C.jv_string_value(k))] = jvToGo(v) } return result default: return errors.New("unknown type") } }
// Kind returns a JvKind saying what type this jv contains. // // Does not consume the invocant. func (jv *Jv) Kind() JvKind { return JvKind(C.jv_get_kind(jv.jv)) }