| 4231 | /// Used when compatible mode is enabled but the remote schema matches locally. |
| 4232 | template <typename T, size_t... Indices> |
| 4233 | FORY_ALWAYS_INLINE void |
| 4234 | read_struct_fields_impl_fast(T &obj, ReadContext &ctx, |
| 4235 | std::index_sequence<Indices...>) { |
| 4236 | using Helpers = CompileTimeFieldHelpers<T>; |
| 4237 | constexpr size_t fixed_count = Helpers::leading_fixed_count; |
| 4238 | constexpr size_t fixed_bytes = Helpers::leading_fixed_size_bytes; |
| 4239 | constexpr size_t varint_count = Helpers::varint_count; |
| 4240 | constexpr size_t total_count = sizeof...(Indices); |
| 4241 | |
| 4242 | Buffer &buffer = ctx.buffer(); |
| 4243 | |
| 4244 | // Phase 1: Read leading fixed-size primitives if any |
| 4245 | if constexpr (fixed_count > 0 && fixed_bytes > 0) { |
| 4246 | if (FORY_PREDICT_FALSE(!buffer.ensure_readable( |
| 4247 | static_cast<uint32_t>(fixed_bytes), ctx.error()))) { |
| 4248 | return; |
| 4249 | } |
| 4250 | // Fast read fixed-size primitives |
| 4251 | read_fixed_primitive_fields<T>(obj, buffer, |
| 4252 | std::make_index_sequence<fixed_count>{}); |
| 4253 | } |
| 4254 | |
| 4255 | // Phase 2: Read consecutive varint primitives (int32, int64) if any |
| 4256 | if constexpr (varint_count > 0) { |
| 4257 | if (FORY_PREDICT_FALSE(buffer.has_input_stream())) { |
| 4258 | // Stream-backed buffers may not have all varint bytes materialized yet. |
| 4259 | // Fall back to per-field readers that propagate stream read errors. |
| 4260 | read_remaining_fields<T, fixed_count, total_count>(obj, ctx); |
| 4261 | return; |
| 4262 | } |
| 4263 | // Track offset locally for batch varint reading |
| 4264 | uint32_t offset = buffer.reader_index(); |
| 4265 | // Fast read varint primitives (bounds checking happens in |
| 4266 | // get_var_uint32/64) |
| 4267 | read_varint_primitive_fields<T, fixed_count>( |
| 4268 | obj, buffer, offset, std::make_index_sequence<varint_count>{}); |
| 4269 | // Update reader_index once after all varints |
| 4270 | buffer.reader_index(offset); |
| 4271 | } |
| 4272 | |
| 4273 | // Phase 3: Read remaining fields (if any) with normal path |
| 4274 | constexpr size_t fast_count = fixed_count + varint_count; |
| 4275 | if constexpr (fast_count < total_count) { |
| 4276 | read_remaining_fields<T, fast_count, total_count>(obj, ctx); |
| 4277 | } |
| 4278 | } |
| 4279 | |
| 4280 | /// Read struct fields with schema evolution (compatible mode) |
| 4281 | /// Reads fields in remote schema order, dispatching by field_id to local fields |
no test coverage detected