marshalField function
Marshals a single scalar field value and appends it to buffer.
Applies proto3 default-value elision: values equal to the type's default
(0, 0.0, false, empty string, empty bytes) are not written unless
repeated is true (packed encoding handles its own elision).
For TYPE_MESSAGE, value must be either a pre-encoded List<int> or
will be treated as such.
Returns buffer with the field bytes appended.
Implementation
List<int> marshalField(
List<int> buffer,
int fieldNumber,
String type,
Object? value, {
bool repeated = false,
bool explicitPresence = false,
bool delimited = false,
List<Map<String, Object?>>? messageDescriptor,
}) {
if (value == null) return buffer;
// Explicit / required presence: a present value is serialized even when it
// equals the type default. The low-level encoders below bake in proto3
// default elision, so route singular scalars through the forced writer.
// (Message fields track presence separately — handled by the normal path.)
if (explicitPresence && !repeated && type != 'TYPE_MESSAGE') {
return _writeScalarForced(buffer, fieldNumber, type, value);
}
switch (type) {
case 'TYPE_INT32':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeInt32Field(buffer, fieldNumber, v);
case 'TYPE_INT64':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeInt64Field(buffer, fieldNumber, v);
case 'TYPE_UINT32':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeUint32Field(buffer, fieldNumber, v);
case 'TYPE_UINT64':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeUint64Field(buffer, fieldNumber, v);
case 'TYPE_SINT32':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeSint32Field(buffer, fieldNumber, v);
case 'TYPE_SINT64':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeSint64Field(buffer, fieldNumber, v);
case 'TYPE_BOOL':
final v = value as bool;
if (!repeated && !v) return buffer;
encodeBoolField(buffer, fieldNumber, v);
case 'TYPE_ENUM':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeEnumField(buffer, fieldNumber, v);
case 'TYPE_FIXED32':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeFixed32Field(buffer, fieldNumber, v);
case 'TYPE_FIXED64':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeFixed64Field(buffer, fieldNumber, v);
case 'TYPE_SFIXED32':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeSfixed32Field(buffer, fieldNumber, v);
case 'TYPE_SFIXED64':
final v = _toInt(value);
if (!repeated && v == 0) return buffer;
encodeSfixed64Field(buffer, fieldNumber, v);
case 'TYPE_FLOAT':
final v = _toDouble(value);
if (!repeated && identical(v, 0.0)) return buffer;
encodeFloatField(buffer, fieldNumber, v);
case 'TYPE_DOUBLE':
final v = _toDouble(value);
if (!repeated && identical(v, 0.0)) return buffer;
encodeDoubleField(buffer, fieldNumber, v);
case 'TYPE_STRING':
final v = value as String;
if (!repeated && v.isEmpty) return buffer;
encodeStringField(buffer, fieldNumber, v);
case 'TYPE_BYTES':
final v = value as List<int>;
if (!repeated && v.isEmpty) return buffer;
encodeBytesField(buffer, fieldNumber, v);
case 'TYPE_MESSAGE':
// Value is either pre-encoded bytes (List<int>) or a map that needs
// marshaling via a messageDescriptor.
final List<int> v;
if (value is List<int>) {
v = value;
} else if (value is Map<String, Object?> && messageDescriptor != null) {
v = marshal(value, messageDescriptor);
} else if (value is Map<String, Object?>) {
throw ArgumentError(
'TYPE_MESSAGE field $fieldNumber received a Map but no '
'messageDescriptor was provided for auto-marshaling',
);
} else {
throw ArgumentError(
'TYPE_MESSAGE field $fieldNumber expected List<int> or '
'Map<String, Object?>, got ${value.runtimeType}',
);
}
if (delimited) {
// DELIMITED (group): a present submessage is always emitted, including
// an empty one (START_GROUP/END_GROUP carries presence on its own).
encodeGroupField(buffer, fieldNumber, v);
} else {
if (v.isEmpty) return buffer;
encodeMessageField(buffer, fieldNumber, v);
}
default:
throw ArgumentError('Unknown protobuf field type: $type');
}
return buffer;
}