Tested recipes
Start with the first C# program or the Node.js and browser quick start. These 40 recipes include complete programs, exact byte/value checks, exercises, and answers. Browser links identify related lessons; C# streams, spans, typed classes, and runtime-variable dictionaries have no direct browser equivalent.
Run one recipe from the repository root with the .NET 10 SDK:
dotnet run --project docs/examples/CStructSharp.Docs.Examples.csproj -c Release -- decode-header
Use --list instead of decode-header to list names. Omit arguments to run all scenarios. Success ends with
PASS all 56 scenarios. Complete programs can also be copied into a console project with a matching package.
Beginner
| Task | Result checked | Browser lesson |
|---|---|---|
| Read a fixed header | kind 2, length 6; typed read succeeds and truncated read fails | Open |
| Write and update a header | 03 00 06 00 00 00 after updating kind | Open |
| Diagnose the wrong byte order | little-endian kind 2; big-endian kind 512 and length 100663296 | Open |
| Read into a C# class | Point with X -2 and Y 5 | See browser API limits |
| Repair an invalid path | Header.kind fails; header.kind reads 2 | Open |
| Generate a layout class | Parse into a generated class with kind 2 and length 6, Serialize back to the same six bytes, and the size constant 6 | See browser API limits |
| Parse without exceptions | TryParse succeeding on six bytes and failing on three with a null value, the failure form handing over the short-read exception, a stream back at its origin, cancellation passing through, and the runtime's TryReadValue, TryGet, and GetOrDefault | See browser API limits |
Intermediate
| Task | Result checked | Browser lesson |
|---|---|---|
| Read an item in a nested array | packet.items[1].id is 2; exact four-byte round trip | Open |
| Explain padding in an aligned header | length 6 at offset 4; eight-byte round trip | Open |
| Read flags stored in one byte | 0B stores enabled 1, mode 5, reserved 0 | Open |
| Read and write fixed text | ABC followed by a zero character; XY writes 58 59 00 00 | Open |
| Read zero-terminated text | 41 42 00 reads AB and writes back unchanged | Open |
| Combine text, an enum, and a union | Text, AB with a zero character, and exact six-byte round trip | See browser API limits |
| Connect a field to its bytes | uint16 occupies offsets 1 and 2; ResolveAddress returns 1 | Open |
| Patch a nested field in a stream | EE EE 34 12 A5; invalid replacement preserves bytes and position | Open |
| Read three-byte integers | seven bytes, unsigned maximum 16777215, signed -2, and an atomic overflow rejection | Open |
| Decode byte-bounded text | Euro, accented and supplementary characters with exact byte counts and endian order | Open |
| Preserve exact fixed-point values | revision -1.5, volume 0.5, and rejected quantization of 0.1 | Open |
| Distinguish UUID and GUID storage | the same Guid value in two distinct 16-byte storage orders | Open |
| Paste a Windows header as it is | Magic 0x5A4D, promoted union members Major 10 and Build 12345, padding absent, and a 20-byte write with zeroed padding | Open |
| Read flags and data-terminated arrays | READ, EXEC and HIDDEN from 0x0105, two entries before the all-zero terminator, a read-to-end trailer, and a write that appends the terminator | Open |
| Inspect a compiled layout | a 7-byte root with length at offset 1, enum member DATA = 2, a definition rendered by ToDefinition that compiles to the same size, and a big-endian sibling layout | See browser API limits |
| Read through an allocation-free view | a view reading kind 2 and length 6 from the span, ToObject producing the class, and the runtime's short-read message for four bytes | See browser API limits |
| Map a generated layout to your classes | a [CStructMapped] record read by the runtime and by the generated bridge, an exact SerializeMapped round trip, and name matching through [CStructMember] | See browser API limits |
| Read a file asynchronously | a header read with ParseAsync from a file opened for asynchronous I/O, the payload that follows, a non-throwing read of three trailing bytes with the stream back at its origin, and a cancelled token leaving position 0 | See browser API limits |
| Read records one after another | three headers through the generated Records, their lengths summed through the allocation-free view enumerator, the same three through ParseMany and RecordsAsync, and two trailing bytes failing at record index 3 | See browser API limits |
Advanced
| Task | Result checked | Browser lesson |
|---|---|---|
| Preserve or select union storage | raw 34 12 round trip; selected small writes A5 00 | Open |
| Preserve an unknown enum number | 4294967295 with no known name, unsigned 32-bit backing | Open |
| Supply a runtime array count | three payload values; second is 32; length lookup preserves position | See browser API limits |
| Follow an absolute stored pointer | stored address 1 points to value 42 | Open |
| Follow a pointer relative to an origin | stored address 1 plus origin 1 reaches offset 2 and value 42 | See browser API limits |
| Bound the work of a read | three-byte budget fails; six-byte budget reads length 6 | Open |
| Read inside a larger stream | length address 4; inspection preserves Position 2; length reads 6 | See browser API limits |
| Reuse a layout with different output storage | 34 12 A5 from array, span, and buffer writer; unused capacity preserved | See browser API limits |
| Inspect and edit a complete binary file | 435301020100100200A5; truncated and excessive-count fixtures rejected | See browser API limits |
| Read and patch LEB128 values | 127 and 128 in different byte widths, signed -65, and a same-width update to 129 | Open |
| Keep a header's defines and size expressions | a text constant, a 64-bit mask constant, an #ifdef-selected typedef, and payload counts of 5 and 1 from a conditional sizeof/offsetof expression | Open |
| Register a custom codec | varint fields decoded as 2, 128, and 5 with an exact round trip and address 4 for the second id | See browser API limits |
| Parse tagged records with native branches | a UTF-8 label, a 24-bit number at offset 7, an inactive-path error, and rejected branch-changing update | Open |
| Frame records from a pipe | five fixed-size frames delivered in three chunks that cross frame boundaries, parsed with ParseMany over the whole frames and AdvanceTo for the rest, then three count-prefixed messages parsed only once every byte of each has arrived | See browser API limits |
Larger walkthroughs
- Inspect and edit a binary file validates a signature, version, and count before patching a record.
- Build a browser inspector adds local file input, a field map, and a verified download.