Skip to content

Commit baa56de

Browse files
committed
docs: change docs to use the new declarative types and Annotated fields
1 parent 88b489f commit baa56de

9 files changed

Lines changed: 176 additions & 44 deletions

File tree

SKILL.md

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Memory is accessed through an `inflater`, which wraps a `bytes` or `bytearray` b
2525
### Imports
2626

2727
```python
28+
from typing import Annotated
2829
from libdestruct import (
2930
inflater, # memory wrapper
3031
struct, # struct base class
@@ -33,10 +34,10 @@ from libdestruct import (
3334
c_float, c_double, # IEEE 754 floats (32/64-bit)
3435
c_str, # null-terminated C string
3536
ptr, # 8-byte pointer
36-
ptr_to, # typed pointer field descriptor
37-
ptr_to_self, # self-referential pointer field descriptor
38-
array_of, # fixed-size array field descriptor
39-
enum_of, # enum field descriptor
37+
ptr_to, # typed pointer field descriptor (legacy)
38+
ptr_to_self, # self-referential pointer field descriptor (legacy)
39+
array, array_of, # array type + field descriptor
40+
enum, enum_of, # enum type + field descriptor
4041
bitfield_of, # bitfield descriptor
4142
union, # union annotation type
4243
union_of, # plain union field descriptor
@@ -131,9 +132,21 @@ player = player_t.from_bytes(memory)
131132
```python
132133
class node_t(struct):
133134
value: c_int
134-
next: ptr = ptr_to_self() # pointer to own type
135+
next: ptr["node_t"] # pointer to own type (forward ref)
135136

136137
# Typed pointer to another type:
138+
class container_t(struct):
139+
data: c_int
140+
ref: ptr[c_long] # subscript syntax (preferred)
141+
```
142+
143+
Legacy syntax with `ptr_to()` and `ptr_to_self()` is still supported:
144+
145+
```python
146+
class node_t(struct):
147+
value: c_int
148+
next: ptr = ptr_to_self()
149+
137150
class container_t(struct):
138151
data: c_int
139152
ref: ptr = ptr_to(c_long)
@@ -176,7 +189,15 @@ class tree_t(struct):
176189
```python
177190
class packet_t(struct):
178191
length: c_int
179-
data: array_of(c_int, 8) # fixed array of 8 c_int
192+
data: array[c_int, 8] # subscript syntax (preferred)
193+
```
194+
195+
Legacy syntax with `array_of()` is still supported:
196+
197+
```python
198+
class packet_t(struct):
199+
length: c_int
200+
data: array_of(c_int, 8)
180201
```
181202

182203
Access array elements:
@@ -199,6 +220,19 @@ class Color(IntEnum):
199220
GREEN = 1
200221
BLUE = 2
201222

223+
class pixel_t(struct):
224+
color: enum[Color] # subscript syntax (preferred, defaults to c_int backing)
225+
alpha: c_int
226+
227+
# With a custom backing type:
228+
class pixel_t(struct):
229+
color: enum[Color, c_short] # 2-byte backing type
230+
alpha: c_int
231+
```
232+
233+
Legacy syntax with `enum_of()` is still supported:
234+
235+
```python
202236
class pixel_t(struct):
203237
color: c_int = enum_of(Color)
204238
alpha: c_int
@@ -274,10 +308,29 @@ class wide_t(struct):
274308

275309
### Explicit Field Offsets
276310

311+
```python
312+
from typing import Annotated
313+
314+
class sparse_t(struct):
315+
a: c_int
316+
b: Annotated[c_int, offset(0x10)] # Annotated syntax (preferred)
317+
```
318+
319+
This works with any type, including subscript types:
320+
321+
```python
322+
class example_t(struct):
323+
a: c_int
324+
data: Annotated[array[c_int, 4], offset(0x10)]
325+
ref: Annotated[ptr[c_int], offset(0x20)]
326+
```
327+
328+
Legacy syntax with default values is still supported:
329+
277330
```python
278331
class sparse_t(struct):
279332
a: c_int
280-
b: c_int = offset(0x10) # b starts at byte offset 0x10
333+
b: c_int = offset(0x10)
281334
```
282335

283336
### Nested Structs
@@ -374,7 +427,7 @@ class header_t(struct):
374427
magic: c_uint
375428
version: c_int
376429
num_entries: c_int
377-
entries_ptr: ptr = ptr_to(entry_t)
430+
entries_ptr: ptr[entry_t]
378431

379432
with open("file.bin", "rb") as f:
380433
data = bytearray(f.read())

docs/advanced/c_parser.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ node_t = definition_to_type("""
6464

6565
## Arrays
6666

67-
Fixed-size arrays are converted to `array_of()`:
67+
Fixed-size arrays are converted to `array[T, N]` types:
6868

6969
```python
7070
t = definition_to_type("""

docs/advanced/forward_refs.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class Node(struct):
1616

1717
At inflation time, the string `"Node"` is resolved to the actual `Node` class. This works because Python's `from __future__ import annotations` (used internally by libdestruct) defers annotation evaluation.
1818

19-
## The `ptr_to_self` Shortcut
19+
## The Legacy `ptr_to_self` Shortcut
2020

21-
For the common case of a pointer to the enclosing struct, use `ptr_to_self`:
21+
For the common case of a pointer to the enclosing struct, the legacy `ptr_to_self` syntax is also available:
2222

2323
```python
2424
from libdestruct import struct, c_int, ptr_to_self
@@ -28,7 +28,7 @@ class Node(struct):
2828
next: ptr_to_self
2929
```
3030

31-
This is equivalent to `ptr["Node"]` but doesn't require you to spell out the type name.
31+
This is equivalent to `ptr["Node"]` but doesn't require you to spell out the type name. The `ptr["TypeName"]` syntax is preferred as it is more explicit.
3232

3333
## Linked List Example
3434

docs/advanced/offset.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@ By default, struct fields are laid out sequentially — each field starts immedi
44

55
## Usage
66

7+
### Annotated syntax (preferred)
8+
9+
Use `Annotated[T, offset(N)]` to place a field at a specific offset:
10+
11+
```python
12+
from typing import Annotated
13+
from libdestruct import struct, c_int, offset
14+
15+
class sparse_t(struct):
16+
a: c_int
17+
b: Annotated[c_int, offset(16)]
18+
c: c_int
19+
```
20+
21+
This works with any type, including subscript types:
22+
23+
```python
24+
from libdestruct import struct, c_int, ptr, array, offset
25+
26+
class example_t(struct):
27+
a: c_int
28+
data: Annotated[array[c_int, 4], offset(0x10)]
29+
ref: Annotated[ptr[c_int], offset(0x20)]
30+
```
31+
32+
### Legacy syntax
33+
34+
The default-value syntax is also supported:
35+
736
```python
837
from libdestruct import struct, c_int, offset
938

@@ -49,8 +78,8 @@ C compilers often insert padding for alignment. Use `offset()` to match the actu
4978

5079
class data_t(struct):
5180
flag: c_char
52-
value: c_int = offset(4)
53-
timestamp: c_long = offset(8)
81+
value: Annotated[c_int, offset(4)]
82+
timestamp: Annotated[c_long, offset(8)]
5483
```
5584

5685
### Skipping Unknown Fields
@@ -59,13 +88,21 @@ When reverse engineering, you might know the offset of a field but not what come
5988

6089
```python
6190
class mystery_t(struct):
62-
known_field: c_int = offset(0x40)
63-
another_field: c_long = offset(0x100)
91+
known_field: Annotated[c_int, offset(0x40)]
92+
another_field: Annotated[c_long, offset(0x100)]
6493
```
6594

6695
## Combining with Other Attributes
6796

68-
`offset()` can be combined with `Field` attributes using a tuple:
97+
With the `Annotated` syntax, `offset()` can be combined with any type naturally:
98+
99+
```python
100+
class example_t(struct):
101+
data: Annotated[ptr[c_int], offset(8)]
102+
items: Annotated[array[c_int, 4], offset(0x10)]
103+
```
104+
105+
With the legacy syntax, `offset()` can be combined with `Field` attributes using a tuple:
69106

70107
```python
71108
from libdestruct.common.field import Field

docs/basics/arrays.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
# Arrays
22

3-
Fixed-size arrays are created with `array_of()`.
3+
Fixed-size arrays can be defined using the `array[T, N]` subscript syntax or the `array_of()` factory function.
44

55
## Defining Arrays
66

77
```python
8-
from libdestruct import c_int, array_of, inflater
8+
from libdestruct import c_int, array, array_of, inflater
99

10-
# An array of 5 c_int values
10+
# Subscript syntax (preferred)
11+
int_array_t = array[c_int, 5]
12+
13+
# Legacy factory function
1114
int_array_t = array_of(c_int, 5)
1215
```
1316

@@ -76,7 +79,16 @@ raw = bytes(arr)
7679

7780
## Arrays in Structs
7881

79-
Use `array_of()` as a type annotation:
82+
Use `array[T, N]` as a type annotation:
83+
84+
```python
85+
from libdestruct import struct, c_int, array
86+
87+
class matrix_row_t(struct):
88+
values: array[c_int, 4]
89+
```
90+
91+
The legacy `array_of()` syntax is also supported:
8092

8193
```python
8294
from libdestruct import struct, c_int, array_of

docs/basics/enums.md

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,45 @@
11
# Enums
22

3-
libdestruct maps integer values in memory to Python `Enum` types using `enum_of()`.
3+
libdestruct maps integer values in memory to Python `Enum` types using the `enum[T]` subscript syntax or the `enum_of()` factory function.
44

55
## Defining Enums
66

77
```python
88
from enum import IntEnum
9-
from libdestruct import struct, c_int, enum_of
9+
from libdestruct import struct, c_int, enum
1010

1111
class Color(IntEnum):
1212
RED = 0
1313
GREEN = 1
1414
BLUE = 2
1515

16+
# Subscript syntax (preferred)
17+
class pixel_t(struct):
18+
color: enum[Color] # defaults to c_int backing type
19+
x: c_int
20+
y: c_int
21+
22+
# With a custom backing type:
23+
class pixel2_t(struct):
24+
color: enum[Color, c_short] # 2-byte backing type
25+
x: c_int
26+
y: c_int
27+
```
28+
29+
The legacy `enum_of()` syntax is also supported:
30+
31+
```python
32+
from libdestruct import struct, c_int, enum_of
33+
1634
class pixel_t(struct):
1735
color: enum_of(Color, c_int)
1836
x: c_int
1937
y: c_int
2038
```
2139

22-
`enum_of(PythonEnum, backing_type)` creates a type that:
40+
The enum type:
2341

24-
- Reads the raw integer from memory using the backing type (`c_int`)
42+
- Reads the raw integer from memory using the backing type (`c_int` by default)
2543
- Converts it to the corresponding `Enum` member (`Color.RED`, etc.)
2644

2745
## Reading Enum Values
@@ -51,19 +69,20 @@ print(pixel.color.value) # 99 (raw integer, no error)
5169

5270
## Standalone Enums
5371

54-
You can also use `enum` directly (without `enum_of`):
72+
You can also inflate enums directly outside of structs:
5573

5674
```python
5775
from libdestruct import enum, inflater
5876

5977
memory = (2).to_bytes(4, "little")
6078
lib = inflater(memory)
6179

62-
# The enum() constructor takes a resolver, a Python Enum, and a backing type
80+
e = lib.inflate(enum[Color], 0)
81+
print(e.value) # Color.BLUE
6382
```
6483

6584
!!! tip
66-
For struct fields, `enum_of()` is the recommended API. It automatically handles type registration and inflation.
85+
For struct fields, the `enum[T]` subscript syntax is the recommended API. It automatically handles type registration and inflation.
6786

6887
## Serialization
6988

0 commit comments

Comments
 (0)