| 4245 | // --- Rust impl block extraction --- |
| 4246 | |
| 4247 | static void extract_rust_impl(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *spec) { |
| 4248 | CBMArena *a = ctx->arena; |
| 4249 | |
| 4250 | TSNode type_node = ts_node_child_by_field_name(node, TS_FIELD("type")); |
| 4251 | if (ts_node_is_null(type_node)) { |
| 4252 | return; |
| 4253 | } |
| 4254 | |
| 4255 | char *type_name = cbm_node_text(a, type_node, ctx->source); |
| 4256 | if (!type_name || !type_name[0]) { |
| 4257 | return; |
| 4258 | } |
| 4259 | /* Strip generic args from the implementing type: `Buffer<T>` → `Buffer`, |
| 4260 | * `Wrapper<T>` → `Wrapper`. The struct identity is the base name. */ |
| 4261 | { |
| 4262 | char *lt = strchr(type_name, '<'); |
| 4263 | if (lt) { |
| 4264 | *lt = '\0'; |
| 4265 | } |
| 4266 | } |
| 4267 | |
| 4268 | // Check for "impl Trait for Struct" pattern |
| 4269 | TSNode trait_node = ts_node_child_by_field_name(node, TS_FIELD("trait")); |
| 4270 | if (!ts_node_is_null(trait_node)) { |
| 4271 | char *trait_name = cbm_node_text(a, trait_node, ctx->source); |
| 4272 | /* Strip generic args from the trait: `From<Feet>` → `From`, |
| 4273 | * `Index<usize>` → `Index`, `AsRef<str>` → `AsRef`. Qualified paths |
| 4274 | * like `io::Write` / `fmt::Display` have no `<` and are preserved. */ |
| 4275 | if (trait_name) { |
| 4276 | char *lt = strchr(trait_name, '<'); |
| 4277 | if (lt) { |
| 4278 | *lt = '\0'; |
| 4279 | } |
| 4280 | } |
| 4281 | if (trait_name && trait_name[0]) { |
| 4282 | CBMImplTrait it; |
| 4283 | it.trait_name = trait_name; |
| 4284 | it.struct_name = type_name; |
| 4285 | cbm_impltrait_push(&ctx->result->impl_traits, a, it); |
| 4286 | } |
| 4287 | } |
| 4288 | |
| 4289 | const char *type_qn = cbm_fqn_compute(a, ctx->project, ctx->rel_path, type_name); |
| 4290 | |
| 4291 | // Extract methods inside impl body |
| 4292 | TSNode body = ts_node_child_by_field_name(node, TS_FIELD("body")); |
| 4293 | if (ts_node_is_null(body)) { |
| 4294 | return; |
| 4295 | } |
| 4296 | |
| 4297 | uint32_t count = ts_node_child_count(body); |
| 4298 | for (uint32_t i = 0; i < count; i++) { |
| 4299 | TSNode child = ts_node_child(body, i); |
| 4300 | if (ts_node_is_null(child)) { |
| 4301 | continue; |
| 4302 | } |
| 4303 | if (!cbm_kind_in_set(child, spec->function_node_types)) { |
| 4304 | continue; |
no test coverage detected