     public mutating func decodeFullObject(decodeField: (inout ProtobufFieldDecoder, Int) throws -> Bool) throws {
         while let tag = try scanner.getTag() {
             let protoFieldNumber = tag.fieldNumber
-            var fieldDecoder: ProtobufFieldDecoder
-            switch scanner.fieldWireFormat {
-            case .varint:
-                let value = try getVarint()
-                let raw = try scanner.getRawField()
-                fieldDecoder = ProtobufFieldWireType0(varint: value, unknown: raw, scanner: scanner)
-            case .fixed64:
-                let value = try getFixed8()
-                let raw = try scanner.getRawField()
-                fieldDecoder = ProtobufFieldWireType1(fixed8: value, unknown: raw, scanner: scanner)
-            case .lengthDelimited:
-                let value = try getBytesRef()
-                let raw = try scanner.getRawField()
-                fieldDecoder = ProtobufFieldWireType2(buffer: value, unknown: raw, scanner: scanner)
-            case .startGroup:
-                fieldDecoder = ProtobufFieldWireType3(scanner: scanner, protoFieldNumber: protoFieldNumber)
-            case .endGroup:
-                throw ProtobufDecodingError.malformedProtobuf
-            case .fixed32:
-                let value = try getFixed4()
-                let raw = try scanner.getRawField()
-                fieldDecoder = ProtobufFieldWireType5(fixed4: value, unknown: raw, scanner: scanner)
-            }
+            var fieldDecoder = try decoder(forFieldNumber: protoFieldNumber, scanner: scanner)
             if !(try decodeField(&fieldDecoder, protoFieldNumber)) {
                 let _ = try scanner.skip() // Skip and discard the field.
             }

    }
}

private struct ProtobufFieldWireType2: ProtobufBinaryFieldDecoder {
    let buffer: UnsafeBufferPointer<UInt8>
    let unknown: UnsafeBufferPointer<UInt8>
    let scanner: ProtobufScanner

                }
                break // Fail and exit
            }
            var fieldDecoder = try decoder(forFieldNumber: protoFieldNumber, scanner: scanner)
            // Proto2 groups always consume fields or throw errors, so we can ignore return here
            let _ = try group.decodeField(setter: &fieldDecoder, protoFieldNumber: tag.fieldNumber)
        }
        throw ProtobufDecodingError.truncatedInput
    }

    private mutating func decoder(forFieldNumber fieldNumber: Int, scanner: ProtobufScanner) throws -> ProtobufFieldDecoder {
        switch scanner.fieldWireFormat {
        case .varint:
            let value = try getVarint()
            let raw = try scanner.getRawField()
            return ProtobufFieldWireTypeVarint(varint: value, unknown: raw, scanner: scanner)
        case .fixed64:
            let value = try getFixed8()
            let raw = try scanner.getRawField()
            return ProtobufFieldWireTypeFixed64(fixed8: value, unknown: raw, scanner: scanner)
        case .lengthDelimited:
            let value = try getBytesRef()
            let raw = try scanner.getRawField()
            return ProtobufFieldWireTypeLengthDelimited(buffer: value, unknown: raw, scanner: scanner)
        case .startGroup:
            return ProtobufFieldWireTypeStartGroup(scanner: scanner, protoFieldNumber: fieldNumber)
        case .endGroup:
            throw ProtobufDecodingError.malformedProtobuf
        case .fixed32:
            let value = try getFixed4()
            let raw = try scanner.getRawField()
            return ProtobufFieldWireTypeFixed32(fixed4: value, unknown: raw, scanner: scanner)
        }
    }

    // Marks failure if no or broken varint but returns zero
