@@ -880,30 +880,67 @@ function foo()
880880
881881### Compiler-assisted field mapping
882882
883- For dedicated state classes, the compiler provides two save/load intrinsics that expand into direct field
884- accesses:
883+ The compiler provides three prefixed operations for libraries that need type-safe structural mapping without
884+ runtime reflection: ` wurstForFields ` , ` wurstMapFields ` , and ` wurstNewInstance<T>() ` . They are declared in
885+ ` MagicFunctions ` with ` @compilerintrinsic ` , so editors can show their documentation and signatures while the
886+ compiler still replaces calls with direct accesses and constructor calls.
885887
886888``` wurst
887889class PlayerState
888890 int level = 1
889891 string name = ""
890892
891893 function save(FieldWriter writer)
892- __wurst_forFields ((fieldName, value) -> writer.write(fieldName, value))
894+ wurstForFields ((fieldName, value) -> writer.write(fieldName, value))
893895
894896 function load(FieldReader reader)
895- __wurst_mapFields((fieldName, value) -> reader.read(fieldName, value))
897+ wurstMapFields((fieldName, value) -> reader.read(fieldName, value))
898+
899+ function loadPlayerState(FieldReader reader) returns PlayerState
900+ let result = wurstNewInstance<PlayerState>()
901+ result.load(reader)
902+ return result
903+ ```
904+
905+ ` wurstForFields ` invokes the callback once for every accessible, non-static instance field, including inherited
906+ and module-injected fields. Readonly and constant fields are included. ` wurstMapFields ` assigns each callback
907+ result back to its field, so every included field must be mutable. The callback's value parameter has the concrete
908+ type of the current field; leave it inferred and overload the reader or writer for every supported field type.
909+ This allows a library to compose codecs for primitives, enums, nullable values, nested state classes, tuples, and
910+ generic collections without a runtime type registry.
911+
912+ Both operations also accept an explicit target as their first argument. Class targets are evaluated exactly once.
913+ Tuple targets use direct component accesses; a tuple passed to ` wurstMapFields ` must be a variable so the updated
914+ tuple can be written back safely.
915+
916+ ``` wurst
917+ tuple Position(int x, int y)
918+
919+ function savePosition(Position position, FieldWriter writer)
920+ wurstForFields(position, (fieldName, value) -> writer.write(fieldName, value))
921+
922+ function loadPosition(Position position, FieldReader reader) returns Position
923+ var result = position
924+ wurstMapFields(result, (fieldName, value) -> reader.read(fieldName, value))
925+ return result
896926```
897927
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.
928+ ` wurstNewInstance<T>() ` calls the normal accessible zero-argument constructor of a concrete class. Constructor
929+ initializers therefore provide defaults for fields absent from older records; the operation never allocates an
930+ uninitialized object or performs class-name lookup.
931+
932+ These operations generate ordinary constructor calls and direct field or tuple accesses in both Jass and Lua.
933+ They do not define a save format or make field names stable persisted identities. A serialization library must
934+ own numeric field IDs, object versions, migrations, parsing, and integrity checks. Cyclic object graphs and field
935+ types for which the library has no codec still require an explicit user-provided codec.
936+
937+ The original unprefixed ` forFields ` , ` mapFields ` , and ` newInstance<T>() ` spellings remain available as compatibility
938+ fallbacks. New code should use the ` wurst ` -prefixed names to avoid accidental collisions. If an applicable ordinary
939+ function with the same name is visible, normal overload resolution selects that function instead of the compiler
940+ operation.
902941
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.
942+ Keep serializable state in a small class and keep persistence policy separate from the rest of the game logic.
943+ See the [ Save and Load tutorial] ( /tutorials/saveload.html ) for integration with Warcraft III's file API.
907944
908945### Array Members
909946
0 commit comments