Created
March 18, 2019 00:43
-
-
Save sseg/cf1bb67b7b62dcdafbded8184399644d to your computer and use it in GitHub Desktop.
Typed enum with case matching on types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
import abc | |
from types import new_class | |
from typeguard import check_type | |
from contextlib import contextmanager | |
def make_type_class(name, parent, type_declaration): | |
def init(self, value): | |
check_type(name, value, type_declaration, None) | |
self._value = value | |
def iterate(self): | |
return iter([self._value]) | |
return type( | |
name, | |
(), | |
dict( | |
parent.__dict__, | |
_type=type_declaration, | |
__init__=init, | |
__iter__=iterate | |
) | |
) | |
class TypeEnumMeta(abc.ABCMeta): | |
_types = {} | |
def __new__(metacls, cls, bases, classdict): | |
type_enum = super().__new__(metacls, cls, bases, classdict) | |
for type_name, type_declaration in classdict.get('__annotations__', {}).items(): | |
type_enum._types[type_name] = make_type_class(type_name, type_enum, type_declaration) | |
return type_enum | |
def __getattr__(cls, name): | |
try: | |
return cls._types[name] | |
except KeyError: | |
raise AttributeError(name) | |
class MatchNotFound(Exception): | |
pass | |
class CaseManager: | |
def __init__(self, variant): | |
self._bound_value = variant | |
self._match_found = False | |
self._callback = None | |
def __matmul__(self, variant_type): | |
if type(self._bound_value) is variant_type: | |
self._match_found = True | |
return self | |
def __rshift__(self, processor): | |
if self._match_found and self._callback is None: | |
self._callback = processor | |
def eval(self): | |
if self._callback is None: | |
raise MatchNotFound(self._bound_value) | |
(wrapped_value,) = self._bound_value | |
return self._callback(wrapped_value) | |
@property | |
def default(self): | |
if self._callback is None: | |
self._match_found = True | |
return self | |
class TypeEnum(metaclass=TypeEnumMeta): | |
@staticmethod | |
@contextmanager | |
def match(variant): | |
yield CaseManager(variant) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment