Skip to content

Commit 1da0802

Browse files
committed
Document compiler-assisted field mapping
1 parent f0708ae commit 1da0802

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

_doc/manual.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,33 @@ function foo()
878878
let s = Terrain.someArr[0]
879879
```
880880

881+
### Compiler-assisted field mapping
882+
883+
For dedicated state classes, the compiler provides two save/load intrinsics that expand into direct field
884+
accesses:
885+
886+
```wurst
887+
class PlayerState
888+
int level = 1
889+
string name = ""
890+
891+
function save(FieldWriter writer)
892+
__wurst_forFields((fieldName, value) -> writer.write(fieldName, value))
893+
894+
function load(FieldReader reader)
895+
__wurst_mapFields((fieldName, value) -> reader.read(fieldName, value))
896+
```
897+
898+
`__wurst_forFields` invokes the callback once for every non-static instance field. The callback receives the
899+
field name and current value and must produce a statement. `__wurst_mapFields` invokes a reader callback and
900+
assigns its result back to each field. Leave the two callback parameter types inferred; overload the reader or
901+
writer for the field types used by the state class.
902+
903+
These are compile-time transformations, not runtime reflection, and generate equivalent direct accesses in both
904+
Jass and Lua. Keep serializable state in a small class with mutable instance fields and keep the persistence
905+
codec separate from the rest of the game logic. See the [Save and Load tutorial](/tutorials/saveload.html) for
906+
integration with Warcraft III's file API.
907+
881908
### Array Members
882909

883910
Wurstscript supports sized arrays as classmembers by translating it to SIZE times arrays and then resolve the array in a get/set function via binary search.

_tutorials/saveload.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,35 @@ Of course usually we don't want to save just strings, but data that is stored in
6262
For this purpose there is the `Serializable` class for simple saving and loading of primitive attribute values.
6363
The `serialize()` function returns a `ChunkedString`, which then can be passed to the data save function from above.
6464

65+
## Compiler-assisted field mapping
66+
67+
For small, dedicated state classes, Wurst can generate the repetitive field mapping for you. Use the
68+
compiler intrinsics `__wurst_forFields` when writing fields and `__wurst_mapFields` when reading them:
69+
70+
```wurst
71+
class PlayerState
72+
int level = 1
73+
string name = ""
74+
75+
function save(FieldWriter writer)
76+
__wurst_forFields((fieldName, value) -> writer.write(fieldName, value))
77+
78+
function load(FieldReader reader)
79+
__wurst_mapFields((fieldName, value) -> reader.read(fieldName, value))
80+
```
81+
82+
The callback receives the field name as a `string` and the current field value. The compiler expands these
83+
calls into ordinary direct field accesses, so there is no runtime reflection or metadata lookup. The same
84+
source works for both Jass and Lua.
85+
86+
`__wurst_forFields` is for statement callbacks. `__wurst_mapFields` uses the callback result to assign each
87+
field, so the reader should return the value to store. Leave both callback parameter types inferred and use
88+
the reader/writer overload matching each field type. Static fields are not included.
89+
90+
The `__wurst_` names are compiler intrinsics; ordinary user functions named `forFields` or `mapFields` are
91+
unaffected. Keep these state classes focused on their serializable data (normally direct mutable instance
92+
fields) and keep the persistence codec separate from the game logic.
93+
6594

6695
## Usage
6796

0 commit comments

Comments
 (0)