Marko Durkovic abd0c1fa73 Add serde
2021-05-16 17:40:53 +02:00

104 lines
2.3 KiB
Python

# Copyright 2020-2021 Ternaris.
# SPDX-License-Identifier: Apache-2.0
"""Helpers used by code generators."""
from __future__ import annotations
from enum import IntEnum
from importlib.util import module_from_spec, spec_from_loader
from typing import TYPE_CHECKING, NamedTuple
if TYPE_CHECKING:
from types import ModuleType
from typing import Any, Dict, List
class Valtype(IntEnum):
"""Msg field value types."""
BASE = 1
MESSAGE = 2
ARRAY = 3
SEQUENCE = 4
class Descriptor(NamedTuple):
"""Value type descriptor."""
valtype: Valtype
args: Any # Union[Descriptor, Msgdef, Tuple[int, Descriptor], str]
SIZEMAP: Dict[str, int] = {
'bool': 1,
'int8': 1,
'int16': 2,
'int32': 4,
'int64': 8,
'uint8': 1,
'uint16': 2,
'uint32': 4,
'uint64': 8,
'float32': 4,
'float64': 8,
}
def align(entry: Descriptor) -> int:
"""Get alignment requirement for entry.
Args:
entry: Field.
Returns:
Required alignment in bytes.
"""
if entry.valtype == Valtype.BASE:
if entry.args == 'string':
return 4
return SIZEMAP[entry.args]
if entry.valtype == Valtype.MESSAGE:
return align(entry.args.fields[0].descriptor)
if entry.valtype == Valtype.ARRAY:
return align(entry.args[1])
assert entry.valtype == Valtype.SEQUENCE
return 4
def align_after(entry: Descriptor) -> int:
"""Get alignment after entry.
Args:
entry: Field.
Returns:
Memory alignment after entry.
"""
if entry.valtype == Valtype.BASE:
if entry.args == 'string':
return 1
return SIZEMAP[entry.args]
if entry.valtype == Valtype.MESSAGE:
return align_after(entry.args.fields[-1].descriptor)
if entry.valtype == Valtype.ARRAY:
return align_after(entry.args[1])
assert entry.valtype == Valtype.SEQUENCE
return min([4, align_after(entry.args)])
def compile_lines(lines: List[str]) -> ModuleType:
"""Compile lines of code to module.
Args:
lines: Lines of python code.
Returns:
Compiled and loaded module.
"""
module = module_from_spec(spec_from_loader('tmpmod', loader=None))
exec('\n'.join(lines), module.__dict__) # pylint: disable=exec-used
return module