Because a plain negative int wastes ten bytes, protobuf offers sint32 and sint64 that zigzag small negatives into small unsigned varints. Today you build the zigzag mapping and its inverse so signed values encode compactly.
Map signed integers to and from their zigzag varint encoding.
Zigzag encoding makes small-magnitude negatives cheap by interleaving signs:
0 maps to 0, -1 to 1, 1 to 2, -2 to 3, 2 to 4, so a value near zero stays near zero
whether it is positive or negative, and the resulting small unsigned number varint
encodes to one byte. The sint32 and sint64 types use this; plain int32 and
int64 from the last lesson do not.
The encode is (v << 1) ^ (v >> 63): shifting left by one makes room for the sign
in bit 0, and the arithmetic right shift by 63 produces all-ones for a negative and
all-zeros for a non-negative, which the XOR uses to flip the other bits for
negatives. Decoding reverses it: (u >> 1) ^ -(u & 1) moves the magnitude back
down and rebuilds the sign from bit 0. Confirm the two are inverses on the whole
sample - a codec that cannot round-trip its own signed values is worse than
useless.
// encode: fold the sign bit into bit 0 (arithmetic shift copies the sign)func zigzagEncode(v int64) uint64 { return uint64((v << 1) ^ (v >> 63)) }// decode: pull bit 0 back out as the signfunc zigzagDecode(u uint64) int64 { return int64(u>>1) ^ -int64(u&1) }