@PinfitSwitch¶
Writing one case per enum member by hand is tedious and goes stale the moment the enum grows.
Inside any user region you can tag a switch with a @PinfitSwitch comment and let Pinfit keep the
cases in sync instead.
Tag an empty switch¶
Write the comment directly above your own switch, naming the enum type:
/*@Pinfit usercode+ function.dispatch_opcode.body*/
/*@PinfitSwitch flash_opcodes_t*/
switch (opcode)
{
}
/*@Pinfit usercode-*/
Run pinfit generate. Pinfit resolves flash_opcodes_t (see Resolving the enum
below) and rewrites the switch with one case per member plus a default, each carrying its own
nested user region:
/*@PinfitSwitch flash_opcodes_t*/
switch (opcode)
{
case FLASH_OP_READ:
{
/*@Pinfit usercode+ switchcase.flash_opcodes_t.FLASH_OP_READ*/
/*@Pinfit usercode-*/
break;
}
case FLASH_OP_WRITE:
{
/*@Pinfit usercode+ switchcase.flash_opcodes_t.FLASH_OP_WRITE*/
/*@Pinfit usercode-*/
break;
}
default:
{
/*@Pinfit usercode+ switchcase.flash_opcodes_t.default*/
/*@Pinfit usercode-*/
break;
}
}
From then on, edit only inside the switchcase.<enum>.<case> regions. They survive regeneration
like any other user region, and a new enum member automatically gets its own empty case on the
next run. Removing a member works the other way round: if its case region still holds code,
generation fails and names that case, so you can move or delete the code first. An empty case is
removed without asking.
The skeleton is Pinfit's now
Anything you write inside the switch body but outside a case's own region — a stray statement, or a case you added by hand without regenerating — is not preserved. From the moment you tag it, the structure around the case regions belongs to Pinfit, exactly as everywhere else.
Tagging a switch you already wrote¶
You do not have to start from an empty switch. The first time you tag an existing hand-written one:
- code already inside a
casewhose label matches an enum member is migrated into that member's new region rather than discarded; - a
casewhose label does not match any member is left alone, and generation fails with a clear error instead of silently dropping it — fix or remove that case, then generate again.
Resolving the enum¶
Pinfit looks for the named type in two places, in order:
- Every
enums:block declared anywhere in the project's.module.yamland.interface.yamlfiles. If it is there, the case list is taken straight from the spec and nothing else happens. - The project's
.hand.cfiles, scanned for a matchingtypedef enum { ... } flash_opcodes_t;. Because this is a guess about your source, Pinfit shows what it found and asks you to confirm before using it:
@PinfitSwitch flash_opcodes_t is not declared in any YAML enums: block.
Found a matching 'typedef enum' in drivers/flash_regs.h:
FLASH_OP_READ, FLASH_OP_WRITE, FLASH_OP_ERASE
Use this enum? [y/N]:
The fallback scan is deliberately simple
It matches a single typedef enum { ... } name; and splits members on commas — it is not a C
preprocessor. Two files defining the same enum name with different members make generation
fail, naming both files; a body that builds its members from macros is not understood. Declare
the enum in a YAML enums: block if you hit either.
What gets remembered¶
Once you confirm an enum found by the file scan, Pinfit records where it is declared — never a
copy of it. It adds an entry to the externalEnums: block of the .module.yaml that owns the file
containing the @PinfitSwitch, with file relative to that YAML:
This is a link, not a declaration. Unlike enums:, Pinfit never emits its own typedef for an
externalEnums: entry — the type already exists in file, and redeclaring it would conflict with
or duplicate the real definition. Later runs read file directly to get the case list, with no
project scan and no repeated question.
The entry is written as a plain text insertion, the same way enums: entries are: the rest of the
file, comments included, is untouched, and the result is verified by re-parsing and rolled back if
that fails.
Only modules can remember
externalEnums: exists on .module.yaml only. A @PinfitSwitch inside a file owned by a
state machine, observer, command table or adapter spec will ask for confirmation every
time. Declare the enum in YAML enums: if that becomes tiresome.
When to use it¶
| Situation | Better tool |
|---|---|
| Reacting to opcodes from a wire protocol you own | Command table — it generates the whole dispatcher. |
| Reacting to events that change a mode or state | State machine. |
| Exhaustively handling a vendor enum, a register map, or an error code list inside one function | @PinfitSwitch. |