validateArrowValue function
Implementation
void validateArrowValue(
ArrowDataType type,
ArrowValue value, {
String path = 'value',
}) {
Never mismatch() =>
throw ArgumentError('$path is ${value.runtimeType}, not valid for $type');
switch (type) {
case ArrowNullType():
mismatch();
case ArrowBooleanType():
if (value is! ArrowBooleanValue) mismatch();
case final ArrowIntegerType integer:
if (value is! ArrowIntegerValue) mismatch();
if (value.value < integer.minimum || value.value > integer.maximum) {
throw RangeError(
'$path integer ${value.value} is outside ${integer.minimum}..${integer.maximum}',
);
}
case final ArrowFloatingType floating:
if (value is! ArrowFloatingValue || value.bitWidth != floating.bitWidth) {
mismatch();
}
case final ArrowDecimalType decimal:
if (value is! ArrowDecimalValue) mismatch();
final digits = value.unscaled.abs().toString().length;
if (digits > decimal.precision) {
throw RangeError(
'$path unscaled decimal has $digits digits; precision is ${decimal.precision}',
);
}
_checkSignedWidth(value.unscaled, decimal.bitWidth, path);
case ArrowUtf8Type():
if (value is! ArrowStringValue) mismatch();
case ArrowBinaryType():
if (value is! ArrowBinaryValue) mismatch();
case final ArrowDateType date:
if (value is! ArrowTemporalValue) mismatch();
final width = date.unit == ArrowDateUnit.day ? 32 : 64;
final minimum = -(BigInt.one << (width - 1));
final maximum = (BigInt.one << (width - 1)) - BigInt.one;
if (value.value < minimum || value.value > maximum) {
throw RangeError('$path date counter does not fit int$width');
}
case ArrowTimestampType() || ArrowDurationType():
if (value is! ArrowTemporalValue) mismatch();
if (!_fitsSigned64(value.value)) {
throw RangeError('$path temporal counter does not fit int64');
}
case final ArrowTimeType time:
if (value is! ArrowTemporalValue) mismatch();
final unitsPerSecond = switch (time.unit) {
ArrowTimeUnit.second => BigInt.one,
ArrowTimeUnit.millisecond => BigInt.from(1000),
ArrowTimeUnit.microsecond => BigInt.from(1000000),
ArrowTimeUnit.nanosecond => BigInt.from(1000000000),
};
final endOfDay = BigInt.from(86400) * unitsPerSecond;
if (value.value.isNegative || value.value >= endOfDay) {
throw RangeError('$path time counter must fall within one day');
}
if ((time.unit == ArrowTimeUnit.second ||
time.unit == ArrowTimeUnit.millisecond) &&
value.value > BigInt.from(0x7fffffff)) {
throw RangeError('$path time counter does not fit int32');
}
case final ArrowListType list:
if (value is! ArrowListValue) mismatch();
_validateChildren(list.field, value.values, path);
case final ArrowFixedSizeListType list:
if (value is! ArrowListValue) mismatch();
if (value.values.length != list.size) {
throw ArgumentError(
'$path has ${value.values.length} children; expected ${list.size}',
);
}
_validateChildren(list.field, value.values, path);
case final ArrowStructType struct:
if (value is! ArrowStructValue) mismatch();
if (value.fields.length != struct.fields.length) {
throw ArgumentError(
'$path has ${value.fields.length} fields; expected ${struct.fields.length}',
);
}
for (var i = 0; i < struct.fields.length; i++) {
final expected = struct.fields[i];
final actual = value.fields[i];
if (actual.name != expected.name) {
throw ArgumentError(
'$path field $i is ${actual.name}; expected ${expected.name}',
);
}
if (actual.value == null) {
if (!expected.nullable) {
throw ArgumentError('$path.${expected.name} is not nullable');
}
} else {
validateArrowValue(
expected.type,
actual.value!,
path: '$path.${expected.name}',
);
}
}
case final ArrowDictionaryType dictionary:
if (value is! ArrowDictionaryIndexValue) mismatch();
validateArrowValue(
dictionary.indexType,
ArrowIntegerValue(value.index),
path: path,
);
case ArrowFixedSizeBinaryType() ||
ArrowMapType() ||
ArrowUnionType() ||
ArrowIntervalType() ||
ArrowRunEndEncodedType():
_validateExtendedValue(type, value, path, mismatch);
case final ArrowExtensionType extension:
if (value is! ArrowExtensionValue) mismatch();
validateArrowValue(
extension.storageType,
value.storage,
path: '$path.storage',
);
}
}