in src/Azure.IIoT.OpcUa/src/Encoders/JsonEncoderEx.cs [1331:1602]
private void WriteVariantContents(object value, int valueRank,
BuiltInType builtInType)
{
// Handle special value ranks
if (valueRank is <= (-2) or 0)
{
if (valueRank < -3)
{
throw new EncodingException(
$"Bad variant: Value rank '{valueRank}' is invalid.");
}
// Cannot deduce rank - write null
if (value == null)
{
WriteNull(null);
return;
}
// Handle one or more (0), Any (-2) or scalar or one dimension (-3)
if (value.GetType().IsArray)
{
var rank = value.GetType().GetArrayRank();
if (valueRank == -3 && rank != 1)
{
throw new EncodingException(
"Bad variant: Scalar or one dimension with matrix value.");
}
// Write as array or matrix
valueRank = rank;
}
else
{
if (valueRank == 0)
{
throw new EncodingException(
"Bad variant: One or more dimension rank with scalar value.");
}
// Force write as scalar
valueRank = -1;
}
}
// write scalar.
if (valueRank == -1)
{
switch (builtInType)
{
case BuiltInType.Null:
WriteNull(null);
return;
case BuiltInType.Boolean:
WriteBoolean(null, ToTypedScalar<bool>(value));
return;
case BuiltInType.SByte:
WriteSByte(null, ToTypedScalar<sbyte>(value));
return;
case BuiltInType.Byte:
WriteByte(null, ToTypedScalar<byte>(value));
return;
case BuiltInType.Int16:
WriteInt16(null, ToTypedScalar<short>(value));
return;
case BuiltInType.UInt16:
WriteUInt16(null, ToTypedScalar<ushort>(value));
return;
case BuiltInType.Int32:
WriteInt32(null, ToTypedScalar<int>(value));
return;
case BuiltInType.UInt32:
WriteUInt32(null, ToTypedScalar<uint>(value));
return;
case BuiltInType.Int64:
WriteInt64(null, ToTypedScalar<long>(value));
return;
case BuiltInType.UInt64:
WriteUInt64(null, ToTypedScalar<ulong>(value));
return;
case BuiltInType.Float:
WriteFloat(null, ToTypedScalar<float>(value));
return;
case BuiltInType.Double:
WriteDouble(null, ToTypedScalar<double>(value));
return;
case BuiltInType.String:
WriteString(null, ToTypedScalar<string>(value, null));
return;
case BuiltInType.DateTime:
WriteDateTime(null, ToTypedScalar<DateTime>(value));
return;
case BuiltInType.Guid:
WriteGuid(null, ToTypedScalar<Uuid>(value));
return;
case BuiltInType.ByteString:
WriteByteString(null, ToTypedScalar(value, Array.Empty<byte>()));
return;
case BuiltInType.XmlElement:
WriteXmlElement(null, ToTypedScalar<XmlElement>(value, null));
return;
case BuiltInType.NodeId:
WriteNodeId(null, ToTypedScalar<NodeId>(value, null));
return;
case BuiltInType.ExpandedNodeId:
WriteExpandedNodeId(null, ToTypedScalar<ExpandedNodeId>(value, null));
return;
case BuiltInType.StatusCode:
WriteStatusCode(null, ToTypedScalar<StatusCode>(value));
return;
case BuiltInType.QualifiedName:
WriteQualifiedName(null, ToTypedScalar<QualifiedName>(value, null));
return;
case BuiltInType.LocalizedText:
WriteLocalizedText(null, ToTypedScalar<LocalizedText>(value, null));
return;
case BuiltInType.ExtensionObject:
WriteExtensionObject(null, ToTypedScalar<ExtensionObject>(value, null));
return;
case BuiltInType.DataValue:
WriteDataValue(null, ToTypedScalar<DataValue>(value, null));
return;
case BuiltInType.Enumeration:
WriteInt32(null, ToTypedScalar<int>(value));
return;
case BuiltInType.Number:
case BuiltInType.Integer:
case BuiltInType.UInteger:
case BuiltInType.Variant:
throw new EncodingException(
"Bad variant: Unexpected type encountered while encoding " +
value.GetType());
}
}
// write array.
if (valueRank == 1)
{
switch (builtInType)
{
case BuiltInType.Null:
WriteNull(null);
return;
case BuiltInType.Boolean:
WriteBooleanArray(null, ToTypedArray<bool>(value));
return;
case BuiltInType.SByte:
WriteSByteArray(null, ToTypedArray<sbyte>(value));
return;
case BuiltInType.Byte:
WriteByteArray(null, ToTypedArray<byte>(value));
return;
case BuiltInType.Int16:
WriteInt16Array(null, ToTypedArray<short>(value));
return;
case BuiltInType.UInt16:
WriteUInt16Array(null, ToTypedArray<ushort>(value));
return;
case BuiltInType.Int32:
WriteInt32Array(null, ToTypedArray<int>(value));
return;
case BuiltInType.UInt32:
WriteUInt32Array(null, ToTypedArray<uint>(value));
return;
case BuiltInType.Int64:
WriteInt64Array(null, ToTypedArray<long>(value));
return;
case BuiltInType.UInt64:
WriteUInt64Array(null, ToTypedArray<ulong>(value));
return;
case BuiltInType.Float:
WriteFloatArray(null, ToTypedArray<float>(value));
return;
case BuiltInType.Double:
WriteDoubleArray(null, ToTypedArray<double>(value));
return;
case BuiltInType.String:
WriteStringArray(null, ToTypedArray<string>(value, null));
return;
case BuiltInType.DateTime:
WriteDateTimeArray(null, ToTypedArray<DateTime>(value));
return;
case BuiltInType.Guid:
WriteGuidArray(null, ToTypedArray<Uuid>(value));
return;
case BuiltInType.ByteString:
WriteByteStringArray(null, ToTypedArray<byte[]>(value, null));
return;
case BuiltInType.XmlElement:
WriteXmlElementArray(null, ToTypedArray<XmlElement>(value, null));
return;
case BuiltInType.NodeId:
WriteNodeIdArray(null, ToTypedArray<NodeId>(value, null));
return;
case BuiltInType.ExpandedNodeId:
WriteExpandedNodeIdArray(null, ToTypedArray<ExpandedNodeId>(value, null));
return;
case BuiltInType.StatusCode:
WriteStatusCodeArray(null, ToTypedArray<StatusCode>(value));
return;
case BuiltInType.QualifiedName:
WriteQualifiedNameArray(null, ToTypedArray<QualifiedName>(value, null));
return;
case BuiltInType.LocalizedText:
WriteLocalizedTextArray(null, ToTypedArray<LocalizedText>(value, null));
return;
case BuiltInType.ExtensionObject:
WriteExtensionObjectArray(null, ToTypedArray<ExtensionObject>(value, null));
return;
case BuiltInType.DataValue:
WriteDataValueArray(null, ToTypedArray<DataValue>(value, null));
return;
case BuiltInType.Enumeration:
if (value is not Enum[] enums)
{
throw new EncodingException(
"Bad enum: Unexpected type encountered while encoding " +
$"enumeration type: {value.GetType()}");
}
var values = new string[enums.Length];
for (var index = 0; index < enums.Length; index++)
{
var text = enums[index].ToString();
text += "_";
text += ((int)(object)enums[index])
.ToString(CultureInfo.InvariantCulture);
values[index] = text;
}
WriteStringArray(null, values);
return;
case BuiltInType.Number:
case BuiltInType.UInteger:
case BuiltInType.Integer:
case BuiltInType.Variant:
if (value is Variant[] variants)
{
WriteVariantArray(null, variants);
return;
}
if (value is object[] objects)
{
WriteObjectArray(null, objects);
return;
}
throw new EncodingException(
"Bad variant: Unexpected type encountered while encoding an array" +
$" of Variants: {value.GetType()}");
}
}
if (valueRank > 1)
{
// Write matrix
if (value == null)
{
WriteNull(null);
return;
}
// TODO: JSON array encoding only for
// non reversible encoding, otherwise
// flatten array and add Dimension.
// if (!UseReversibleEncoding) {
if (value is Matrix matrix)
{
var index = 0;
WriteMatrix(matrix, 0, ref index, builtInType);
return;
}
}
// Should never happen.
throw new EncodingException(
$"Bad variant: Type '{value.GetType().FullName}' is not allowed in Variant.");
}