Turn a BaseStruct subclass into a volatile structure. Field values are never cached: when retrieving a field's value, its value is read from memory and when setting a field's value, its value is flushed to memory. This is useful to make sure a struct
| 82 | _fields = dict((fname, ftype) for fname, ftype, *_ in cls._fields_) |
| 83 | |
| 84 | class VolatileStructRef(cls): |
| 85 | """Turn a BaseStruct subclass into a volatile structure. |
| 86 | |
| 87 | Field values are never cached: when retrieving a field's value, its value |
| 88 | is read from memory and when setting a field's value, its value is flushed |
| 89 | to memory. |
| 90 | |
| 91 | This is useful to make sure a structure's fields are alway synced with memory. |
| 92 | """ |
| 93 | |
| 94 | def __getattribute__(self, name: str) -> Any: |
| 95 | # accessing a structure field? |
| 96 | if name in _fields: |
| 97 | field = cls.__dict__[name] |
| 98 | ftype = _fields[name] |
| 99 | |
| 100 | if issubclass(ftype, BaseStruct): |
| 101 | fvalue = ftype.volatile_ref(mem, address + field.offset) |
| 102 | |
| 103 | else: |
| 104 | # load field's bytes from memory and tranform them into a value |
| 105 | data = mem.read(address + field.offset, field.size) |
| 106 | fvalue = ftype.from_buffer(data) |
| 107 | |
| 108 | if hasattr(fvalue, 'value'): |
| 109 | fvalue = fvalue.value |
| 110 | |
| 111 | # set the value to the structure in order to maintain consistency with ctypes.Structure |
| 112 | super().__setattr__(name, fvalue) |
| 113 | return fvalue |
| 114 | |
| 115 | # return attribute value |
| 116 | return super().__getattribute__(name) |
| 117 | |
| 118 | def __setattr__(self, name: str, value: Any) -> None: |
| 119 | # accessing a structure field? |
| 120 | if name in _fields: |
| 121 | field = cls.__dict__[name] |
| 122 | ftype = _fields[name] |
| 123 | |
| 124 | # transform value into field bytes and write them to memory |
| 125 | fvalue = ftype(*value) if hasattr(ftype, '_length_') else ftype(value) |
| 126 | data = bytes(fvalue) |
| 127 | |
| 128 | mem.write(address + field.offset, data) |
| 129 | |
| 130 | # proceed to set the value to the structure in order to maintain consistency with ctypes.Structure |
| 131 | |
| 132 | # set attribute value |
| 133 | super().__setattr__(name, value) |
| 134 | |
| 135 | return VolatileStructRef() |
| 136 |