aboutsummaryrefslogtreecommitdiff
path: root/tools/cru-py/cru/util/_func.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/cru-py/cru/util/_func.py')
-rw-r--r--tools/cru-py/cru/util/_func.py150
1 files changed, 150 insertions, 0 deletions
diff --git a/tools/cru-py/cru/util/_func.py b/tools/cru-py/cru/util/_func.py
new file mode 100644
index 0000000..5fb49a9
--- /dev/null
+++ b/tools/cru-py/cru/util/_func.py
@@ -0,0 +1,150 @@
+from collections.abc import Callable, Iterable
+from typing import TypeVar, Any, ParamSpec
+
+from ._list import ListOperations, CruList
+
+T = TypeVar("T")
+R = TypeVar("R")
+R1 = TypeVar("R1")
+P = ParamSpec("P")
+P1 = ParamSpec("P1")
+
+
+class _Placeholder:
+ pass
+
+
+PLACEHOLDER = _Placeholder()
+
+
+class RawFunctions:
+ @staticmethod
+ def ignore(*_v, **_kwargs) -> None:
+ return None
+
+ @staticmethod
+ def true_(*_v, **_kwargs) -> True:
+ return True
+
+ @staticmethod
+ def false_(*_v, **_kwargs) -> False:
+ return False
+
+ @staticmethod
+ def i_dont_care(r: T, *_v, **_kwargs) -> T:
+ return r
+
+ @staticmethod
+ def identity(v: T) -> T:
+ return v
+
+ @staticmethod
+ def equal(a: Any, b: Any) -> bool:
+ return a == b
+
+ @staticmethod
+ def not_equal(a: Any, b: Any) -> bool:
+ return a != b
+
+ @staticmethod
+ def not_(v):
+ return not v
+
+
+class MetaFunction:
+ @staticmethod
+ def bind(f: Callable[P, R], *bind_args, **bind_kwargs) -> Callable[P1, R1]:
+ def bound(*args, **kwargs):
+ popped = 0
+ real_args = []
+ for a in bind_args:
+ if isinstance(a, _Placeholder):
+ real_args.append(args[popped])
+ popped += 1
+ else:
+ real_args.append(a)
+ real_args.extend(args[popped:])
+ return f(*real_args, **(bind_kwargs | kwargs))
+
+ return bound
+
+ @staticmethod
+ def chain(*fs: Callable) -> Callable:
+ if len(fs) == 0:
+ raise ValueError("At least one function is required!")
+ rf = fs[0]
+ for f in fs[1:]:
+ def n(*args, **kwargs):
+ r = rf(*args, **kwargs)
+ r = r if isinstance(r, tuple) else (r,)
+ return f(*r)
+
+ rf = n
+ return rf
+
+ @staticmethod
+ def chain_single(f: Callable[P, R], f1: Callable[P1, R1], *bind_args, **bind_kwargs) -> \
+ Callable[
+ P, R1]:
+ return MetaFunction.chain(f, MetaFunction.bind(f1, *bind_args, **bind_kwargs))
+
+ convert_r = chain_single
+
+ @staticmethod
+ def neg(f: Callable[P, bool]) -> Callable[P, bool]:
+ return MetaFunction.convert_r(f, RawFunctions.not_)
+
+
+# Advanced Function Wrapper
+class CruFunction:
+ def __init__(self, f):
+ self._f = f
+
+ @property
+ def f(self) -> Callable:
+ return self._f
+
+ def bind(self, *bind_args, **bind_kwargs) -> "CruFunction":
+ self._f = MetaFunction.bind(self._f, *bind_args, **bind_kwargs)
+ return self
+
+ def chain(self, *fs: Callable) -> "CruFunction":
+ self._f = MetaFunction.chain(self._f, *fs)
+ return self
+
+ def chain_single(self, f: Callable[P, R], f1: Callable[P1, R1], *bind_args,
+ **bind_kwargs) -> "CruFunction":
+ self._f = MetaFunction.chain_single(self._f, f, f1, *bind_args, **bind_kwargs)
+ return self
+
+ def convert_r(self, f: Callable[P, R], f1: Callable[P1, R1], *bind_args,
+ **bind_kwargs) -> "CruFunction":
+ self._f = MetaFunction.convert_r(self._f, f, f1, *bind_args, **bind_kwargs)
+ return self
+
+ def neg(self) -> "CruFunction":
+ self._f = MetaFunction.neg(self._f)
+ return self
+
+ def __call__(self, *args, **kwargs):
+ return self._f(*args, **kwargs)
+
+ def list_transform(self, l: Iterable[T]) -> CruList[T]:
+ return CruList(l).transform(self)
+
+ def list_all(self, l: Iterable[T]) -> bool:
+ return ListOperations.all(l, self)
+
+ def list_any(self, l: Iterable[T]) -> bool:
+ return ListOperations.any(l, self)
+
+ def list_remove_all_if(self, l: Iterable[T]) -> CruList[T]:
+ return CruList(ListOperations.remove_all_if(l, self))
+
+
+class WrappedFunctions:
+ identity = CruFunction(RawFunctions.identity)
+ ignore = CruFunction(RawFunctions.ignore)
+ equal = CruFunction(RawFunctions.equal)
+ not_equal = CruFunction(RawFunctions.not_equal)
+ not_ = CruFunction(RawFunctions.not_)