commit 78a3df73bbf175805d950bd28a455c9e4085a82b
parent 320f56b3c1f89a0c3455b783d3f1dbb3c3a4a60d
Author: lash <dev@holbrook.no>
Date:   Mon, 31 Jan 2022 08:38:14 +0000
Complete base and alias inserts
Diffstat:
3 files changed, 108 insertions(+), 11 deletions(-)
diff --git a/schiz/error.py b/schiz/error.py
@@ -1,2 +1,6 @@
 class StateExists(Exception):
     pass
+
+
+class StateInvalid(Exception):
+    pass
diff --git a/schiz/state.py b/schiz/state.py
@@ -3,7 +3,10 @@ import enum
 import logging
 
 # local imports
-from .error import StateExists
+from schiz.error import (
+        StateExists,
+        StateInvalid,
+        )
 
 logg = logging.getLogger(__name__)
 
@@ -12,27 +15,84 @@ class State:
 
     def __init__(self, bits):
         self.__bits = bits
+        self.__limit = (1 << bits) - 1
         self.__c = 0
         self.__reverse = {}
 
-    def _persist(self):
+    def __store(self):
         pass
 
+    
+    def __is_pure(self, v):
+        c = 1
+        for i in range(self.__bits):
+            if c & v > 0:
+                break
+            c <<= 1
+        return c == v
 
-    def add(self, name):
-        if self.__c == self.__bits:
-            raise OverflowError(self.__c + 1)
-      
-        v = 1 << self.__c
-
-        k = name.upper()
 
+    def __check_name(self, k):
+        k = k.upper()
         try:
             getattr(self, k)
             raise StateExists(k)
         except AttributeError:
             pass
+        return k
 
-        setattr(self, k, v)
 
+    def __check_cover(self, v):
+        z = 0
+        c = 1
+        for i in range(self.__bits):
+            if c & v > 0:
+                if self.__reverse.get(c) == None:
+                    raise StateInvalid(v)
+            c <<= 1
+        return c == v
+
+
+    def __check_value(self, v):
+        v = int(v)
+        if self.__reverse.get(v):
+            raise StateValueExists(v)
+        if v > self.__limit:
+            raise OverflowError(v)
+        return v
+
+
+    def __check(self, k, v):
+        k = self.__check_name(k)
+        v = self.__check_value(v)
+        return (k, v,)
+
+
+    def __set(self, k, v):
+        setattr(self, k, v)
+        self.__reverse[v] = k
         self.__c += 1
+
+
+    def add(self, k):
+        v = 1 << self.__c
+        (k, v) = self.__check(k, v)
+        self.__set(k, v)
+        
+
+    def alias(self, k, v):
+        (k, v) = self.__check(k, v)
+        if self.__is_pure(v):
+            raise ValueError('use add to add pure values')
+        self.__check_cover(v) 
+        self.__set(k, v)
+
+
+#    def all(self):
+#        l = []
+#        for k in dir(self):
+#            if k[0] == '_':
+#                continue
+#            if k.upper() != k:
+#                continue
+#            l.append(k)
diff --git a/tests/test_state.py b/tests/test_state.py
@@ -3,7 +3,10 @@ import unittest
 
 # local imports
 from schiz import State
-from schiz.error import StateExists
+from schiz.error import (
+        StateExists,
+        StateInvalid,
+        )
 
 
 class TestState(unittest.TestCase):
@@ -31,5 +34,35 @@ class TestState(unittest.TestCase):
             states.add('foo')
 
 
+    def test_alias(self):
+        states = State(2)
+        states.add('foo')
+        states.add('bar')
+        states.alias('baz', states.FOO | states.BAR)
+        self.assertEqual(states.BAZ, 3)
+
+
+    def test_alias_limit(self):
+        states = State(2)
+        states.add('foo')
+        states.add('bar')
+        states.alias('baz', states.FOO | states.BAR)
+
+
+    def test_alias_nopure(self):
+        states = State(3)
+        with self.assertRaises(ValueError):
+            states.alias('foo', 4)
+
+
+    def test_alias_cover(self):
+        states = State(3)
+        states.add('foo')
+        states.add('bar')
+        with self.assertRaises(StateInvalid):
+            states.alias('baz', 5)
+
+
+
 if __name__ == '__main__':
     unittest.main()