| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package io.v.v23.vdl; |
| |
| import io.v.v23.vom.BinaryDecoder; |
| import io.v.v23.vom.BinaryEncoder; |
| import io.v.v23.vom.ConversionException; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.Serializable; |
| import java.lang.reflect.Type; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| |
| /** |
| * Value is the generic representation of any value expressible in Vanadium. All values are typed. |
| */ |
| public abstract class VdlValue implements Serializable { |
| private static final long serialVersionUID = 1L; |
| |
| private final VdlType type; |
| |
| protected VdlValue(VdlType type) { |
| this.type = type; |
| } |
| |
| protected void assertKind(Kind kind) { |
| if (type.getKind() != kind) { |
| throw new IllegalArgumentException("Kind of VDL type should be " + kind); |
| } |
| } |
| |
| /** |
| * Returns the runtime VDL type of this value. |
| * |
| * @return The {@code Type} object that represents the runtime |
| * VDL type of this VDL value. |
| */ |
| public VdlType vdlType() { |
| return type; |
| } |
| |
| /** |
| * Returns the {@code VdlValue} corresponding to the provided Java value of a given |
| * {@code VdlType}. |
| * |
| * @param value Java object to be converted to {@code VdlValue} |
| * @param type type of the value |
| * @return {@code VdlValue} corresponding to the above value |
| * @throws IllegalArgumentException if the provided value cannot be converted |
| */ |
| public static VdlValue valueOf(Object value, VdlType type) { |
| try { |
| // VOM-Encode. |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| BinaryEncoder encoder = new BinaryEncoder(out); |
| encoder.encodeValue(type, value); |
| |
| // VOM-Decode to VdlValue. |
| BinaryDecoder decoder = new BinaryDecoder(new ByteArrayInputStream(out.toByteArray())); |
| return (VdlValue) decoder.decodeValue(VdlValue.class); |
| } catch (IOException e) { |
| throw new IllegalArgumentException(String.format( |
| "IO error while converting value %s of type %s into VdlValue", |
| value, type), e); |
| } catch (ConversionException e) { |
| throw new IllegalArgumentException(String.format( |
| "Couldn't convert value %s of type %s into VdlValue", |
| value, type), e); |
| } |
| } |
| |
| /** |
| * Returns the {@code VdlValue} corresponding to the provided Java value of a given |
| * reflection type. |
| * |
| * @param value Java object to be converted to {@code VdlValue} |
| * @param type type of the value |
| * @return {@code VdlValue} corresponding to the above value |
| * @throws IllegalArgumentException if the provided value cannot be converted |
| */ |
| public static VdlValue valueOf(Object value, Type type) { |
| return valueOf(value, Types.getVdlTypeFromReflect(type)); |
| } |
| |
| /** |
| * Returns the zero representation for each kind of VDL type. |
| * |
| * @throws IllegalArgumentException if the zero value couldn't be constructed |
| */ |
| public static VdlValue zeroValue(VdlType type) { |
| if (type == null) { |
| throw new IllegalArgumentException("Trying to construct a zero value using null type"); |
| } |
| switch (type.getKind()) { |
| case ANY: |
| return new VdlAny(); |
| case ARRAY: |
| VdlValue[] backingArray = new VdlValue[type.getLength()]; |
| VdlValue elemValue = zeroValue(type.getElem()); |
| for (int i = 0; i < type.getLength(); i++) { |
| backingArray[i] = elemValue; |
| } |
| return new VdlArray<VdlValue>(type, backingArray); |
| case BOOL: |
| return new VdlBool(); |
| case BYTE: |
| return new VdlByte(); |
| case COMPLEX128: |
| return new VdlComplex128(0); |
| case COMPLEX64: |
| return new VdlComplex64(0); |
| case ENUM: |
| return new VdlEnum(type, type.getLabels().get(0)); |
| case FLOAT32: |
| return new VdlFloat32(); |
| case FLOAT64: |
| return new VdlFloat64(); |
| case INT16: |
| return new VdlInt16(); |
| case INT32: |
| return new VdlInt32(); |
| case INT64: |
| return new VdlInt64(); |
| case LIST: |
| return new VdlList<VdlValue>(type, new ArrayList<VdlValue>()); |
| case MAP: |
| return new VdlMap<VdlValue, VdlValue>(type, new HashMap<VdlValue, VdlValue>()); |
| case UNION: |
| VdlField zeroField = type.getFields().get(0); |
| return new VdlUnion(type, 0, zeroField.getType(), zeroValue(zeroField.getType())); |
| case OPTIONAL: |
| return new VdlOptional<VdlValue>(type); |
| case SET: |
| return new VdlSet<VdlValue>(type, new HashSet<VdlValue>()); |
| case STRING: |
| return new VdlString(); |
| case STRUCT: |
| VdlStruct struct = new VdlStruct(type); |
| for (VdlField field : type.getFields()) { |
| struct.assignField(field.getName(), zeroValue(field.getType())); |
| } |
| return struct; |
| case TYPEOBJECT: |
| return new VdlTypeObject(Types.ANY); |
| case UINT16: |
| return new VdlUint16(); |
| case UINT32: |
| return new VdlUint32(); |
| case UINT64: |
| return new VdlUint64(); |
| default: |
| throw new IllegalArgumentException("Unhandled kind " + type.getKind()); |
| } |
| } |
| |
| /** |
| * Same as {@code zeroValue} except if type is {@code OPTIONAL} it returns a value representing |
| * the zero value of the element type. |
| * |
| * @throws IllegalArgumentException if the non-null zero value couldn't be constructed |
| */ |
| public static VdlValue nonNullZeroValue(VdlType type) { |
| if (type == null) { |
| throw new IllegalArgumentException( |
| "Trying to construct a non-null zero value using null type"); |
| } |
| switch (type.getKind()) { |
| case ANY: |
| throw new IllegalArgumentException("Type ANY doesn't have a non-null zero value"); |
| case OPTIONAL: |
| return VdlOptional.of(zeroValue(type.getElem())); |
| default: |
| return zeroValue(type); |
| } |
| } |
| } |