Skip to content

Commit ec4fd22

Browse files
committed
Add bitfield counter
1 parent 2a2e191 commit ec4fd22

2 files changed

Lines changed: 114 additions & 17 deletions

File tree

src/components/Docs/SchemaClass.tsx

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
useSearchMetadata,
1717
} from "./utils/filtering";
1818
import { formatHexOffset } from "./utils/format";
19+
import { computeBitfieldInfo, type BitfieldInfo } from "./utils/bitfields";
1920
import {
2021
CollapsedItemsLink,
2122
CommonGroupMembers,
@@ -186,6 +187,8 @@ export const SchemaClassView: React.FC<{
186187
return { matchingFields: matching, hiddenCount: declaration.fields.length - matching.length };
187188
}, [declaration.fields, searchWords, searchOffsets, searchMetadata, collapseNonMatching]);
188189

190+
const bitfieldInfo = useMemo(() => computeBitfieldInfo(declaration.fields), [declaration.fields]);
191+
189192
return (
190193
<CommonGroupWrapper>
191194
<DeclarationHeader>
@@ -210,6 +213,7 @@ export const SchemaClassView: React.FC<{
210213
<SchemaFieldView
211214
key={`${field.name}-${field.offset}`}
212215
field={field}
216+
bitfield={bitfieldInfo.get(field)}
213217
highlighted={
214218
collapseNonMatching ||
215219
(searchWords.length > 0 && matchesWords(field.name, searchWords)) ||
@@ -341,26 +345,74 @@ function InheritedFieldView({ field }: { field: api.SchemaField }) {
341345
);
342346
}
343347

344-
function SchemaFieldView({ field, highlighted }: { field: api.SchemaField; highlighted: boolean }) {
348+
const BitRange = styled.span`
349+
font-family:
350+
ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
351+
font-size: 13px;
352+
font-weight: 500;
353+
color: var(--text-dim);
354+
font-variant-numeric: tabular-nums;
355+
`;
356+
357+
const BitfieldPadding = styled.div`
358+
padding: 3px 10px;
359+
font-size: 13px;
360+
color: var(--text-dim);
361+
opacity: 0.5;
362+
font-style: italic;
363+
text-align: right;
364+
`;
365+
366+
function SchemaFieldView({
367+
field,
368+
bitfield,
369+
highlighted,
370+
}: {
371+
field: api.SchemaField;
372+
bitfield?: BitfieldInfo;
373+
highlighted: boolean;
374+
}) {
345375
const { root } = useContext(DeclarationsContext);
346376
const navigate = useNavigate();
347377
const offsetHex = formatHexOffset(field.offset);
348378
return (
349-
<FieldRow data-highlighted={highlighted || undefined}>
350-
<FieldIcon>
351-
<KindIcon kind="field" size="small" />
352-
</FieldIcon>
353-
<FieldContent>
354-
<FieldSignature>
355-
{field.name}: <SchemaTypeView type={field.type} />
356-
<FieldOffset
357-
onClick={() => navigate(`${root}?search=${encodeURIComponent(`offset:${offsetHex}`)}`)}
358-
>
359-
{field.offset} ({offsetHex})
360-
</FieldOffset>
361-
</FieldSignature>
362-
<MetadataTags metadata={field.metadata} />
363-
</FieldContent>
364-
</FieldRow>
379+
<>
380+
<FieldRow data-highlighted={highlighted || undefined}>
381+
<FieldIcon>
382+
<KindIcon kind="field" size="small" />
383+
</FieldIcon>
384+
<FieldContent>
385+
<FieldSignature>
386+
{field.name}: <SchemaTypeView type={field.type} />
387+
{bitfield && (
388+
<BitRange>
389+
bit{bitfield.bitCount !== 1 ? "s" : ""} {bitfield.bitOffset}
390+
{bitfield.bitCount !== 1 ? `..${bitfield.bitOffset + bitfield.bitCount - 1}` : ""}
391+
</BitRange>
392+
)}
393+
<FieldOffset
394+
onClick={() =>
395+
navigate(`${root}?search=${encodeURIComponent(`offset:${offsetHex}`)}`)
396+
}
397+
>
398+
{field.offset} ({offsetHex})
399+
</FieldOffset>
400+
</FieldSignature>
401+
<MetadataTags metadata={field.metadata} />
402+
</FieldContent>
403+
</FieldRow>
404+
{bitfield &&
405+
bitfield.totalBits > 0 &&
406+
(() => {
407+
const totalBytes = Math.ceil(bitfield.totalBits / 8);
408+
return (
409+
<BitfieldPadding>
410+
{totalBytes} byte{totalBytes !== 1 ? "s" : ""} ({bitfield.totalBits} bit
411+
{bitfield.totalBits !== 1 ? "s" : ""}
412+
{bitfield.padding > 0 ? ` + ${bitfield.padding} padding` : ""})
413+
</BitfieldPadding>
414+
);
415+
})()}
416+
</>
365417
);
366418
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { SchemaField } from "../api";
2+
3+
export interface BitfieldInfo {
4+
bitOffset: number;
5+
bitCount: number;
6+
padding: number; // padding bits after this field (only set on last bitfield in a group)
7+
totalBits: number; // total bits in the group (only set on last bitfield in a group)
8+
}
9+
10+
export function computeBitfieldInfo(fields: SchemaField[]): Map<SchemaField, BitfieldInfo> {
11+
const result = new Map<SchemaField, BitfieldInfo>();
12+
let i = 0;
13+
while (i < fields.length) {
14+
const field = fields[i];
15+
if (field.type.category !== "bitfield") {
16+
i++;
17+
continue;
18+
}
19+
20+
// Collect consecutive bitfields at the same offset
21+
const groupOffset = field.offset;
22+
let bitPos = 0;
23+
while (
24+
i < fields.length &&
25+
fields[i].type.category === "bitfield" &&
26+
fields[i].offset === groupOffset
27+
) {
28+
const f = fields[i];
29+
const count = (f.type as { category: "bitfield"; count: number }).count;
30+
result.set(f, { bitOffset: bitPos, bitCount: count, padding: 0, totalBits: 0 });
31+
bitPos += count;
32+
i++;
33+
}
34+
35+
// Compute padding to next byte boundary
36+
const lastField = fields[i - 1];
37+
const info = result.get(lastField)!;
38+
const remainder = bitPos % 8;
39+
info.totalBits = bitPos;
40+
if (remainder !== 0) {
41+
info.padding = 8 - remainder;
42+
}
43+
}
44+
return result;
45+
}

0 commit comments

Comments
 (0)