Skip to content

Instantly share code, notes, and snippets.

@sseg
Created March 18, 2019 00:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sseg/cf1bb67b7b62dcdafbded8184399644d to your computer and use it in GitHub Desktop.
Save sseg/cf1bb67b7b62dcdafbded8184399644d to your computer and use it in GitHub Desktop.
Typed enum with case matching on types.
# 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