from typing import Optional, List, Union, Any, TypeVar, Callable, Type, cast


T = TypeVar("T")


def from_int(x: Any) -> int:
    assert isinstance(x, int) and not isinstance(x, bool)
    return x


def from_none(x: Any) -> Any:
    assert x is None
    return x


def from_union(fs, x):
    for f in fs:
        try:
            return f(x)
        except:
            pass
    assert False


def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
    assert isinstance(x, list)
    return [f(y) for y in x]


def from_str(x: Any) -> str:
    assert isinstance(x, str)
    return x


def to_class(c: Type[T], x: Any) -> dict:
    assert isinstance(x, c)
    return cast(Any, x).to_dict()


class Asm4Structure:
    level: Optional[int]
    attached_to: Optional[Union[List[str], str]]
    label: Optional[str]
    axis: Optional[List[str]]

    def __init__(self, level: Optional[int], attached_to: Optional[Union[List[str], str]], label: Optional[str], axis: Optional[List[str]]) -> None:
        self.level = level
        self.attached_to = attached_to
        self.label = label
        self.axis = axis

    @staticmethod
    def from_dict(obj: Any) -> 'Asm4Structure':
        assert isinstance(obj, dict)
        level = from_union([from_int, from_none], obj.get("level"))
        attached_to = from_union([lambda x: from_list(from_str, x), from_str, from_none], obj.get("attachedTo"))
        label = from_union([from_str, from_none], obj.get("label"))
        axis = from_union([lambda x: from_list(from_str, x), from_none], obj.get("axis"))
        return Asm4Structure(level, attached_to, label, axis)

    def to_dict(self) -> dict:
        result: dict = {}
        if self.level is not None:
            result["level"] = from_union([from_int, from_none], self.level)
        if self.attached_to is not None:
            result["attachedTo"] = from_union([lambda x: from_list(from_str, x), from_str, from_none], self.attached_to)
        if self.label is not None:
            result["label"] = from_union([from_str, from_none], self.label)
        if self.axis is not None:
            result["axis"] = from_union([lambda x: from_list(from_str, x), from_none], self.axis)
        return result
    def parse(data) -> List['Asm4Structure']:
        structure:list = []

        for i in data:
            structure.append(Asm4Structure(
                label=i['label'],
                level=i['level'],
                attached_to=i['attachedTo'],
                axis=i['axis']
            ))
        return structure

def asm4_structures_from_dict(s: Any) -> List[Asm4Structure]:
    return from_list(Asm4Structure.from_dict, s)


def asm4_structures_to_dict(x: List[Asm4Structure]) -> Any:
    return from_list(lambda x: to_class(Asm4Structure, x), x)
