Coverage for src/monadc/option/nil.py: 97%
119 statements
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-19 20:24 -0700
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-19 20:24 -0700
1from typing import Optional, Callable, Union, Any, Iterator, cast
2from .option import Option, T, U, V, E
5class NilType(Option[T]):
7 __match_args__ = ()
9 _instance: Optional['NilType[Any]'] = None
11 def __new__(cls) -> 'NilType[Any]':
12 if cls._instance is None:
13 cls._instance = cast('NilType[Any]', super().__new__(cls))
14 return cls._instance
16 # ========================================
17 # Rust / Scala Common API
18 # ========================================
20 def is_defined(self) -> bool:
21 return False
23 def is_empty(self) -> bool:
24 return True
26 def map(self, func: Callable[[T], U]) -> Option[U]:
27 # Nil maps to Nil regardless of function
28 return Nil()
30 def flatten(self) -> Option[Any]:
31 """Flatten Nil to Nil."""
32 return cast(Option[Any], self)
34 def transpose(self) -> Any: # Returns Result[Option[T], E]
35 """Rust-style: Transpose Nil to Ok(Nil)."""
36 from ..result import Ok
37 return Ok(self)
39 def zip(self, other: Option[U]) -> Option[tuple[T, U]]:
40 """Rust-style: Return Nil since self is Nil."""
41 return cast(Option[tuple[T, U]], self)
43 def unzip(self) -> tuple[Option[Any], Option[Any]]:
44 """Unzip Nil to tuple of Nils."""
45 return cast(Option[Any], self), cast(Option[Any], self)
47 def filter(self, predicate: Callable[[T], bool]) -> Option[T]:
48 # Nil filters to Nil regardless of predicate
49 return self
51 # ========================================
52 # RUST API
53 # ========================================
55 def is_some(self) -> bool:
56 """Rust-style: Return False since this is Nil."""
57 return False
59 def is_none(self) -> bool:
60 """Rust-style: Return True since this is Nil."""
61 return True
63 def unwrap(self) -> T:
64 """Rust-style: Panic since this is Nil."""
65 raise ValueError("Called unwrap() on a Nil value")
67 def unwrap_or(self, default: T) -> T:
68 """Rust-style: Return default since this is Nil."""
69 return default
71 def unwrap_or_else(self, func: Callable[[], T]) -> T:
72 """Rust-style: Call func to compute default since this is Nil."""
73 return func()
75 def expect(self, message: str) -> T:
76 """Rust-style: Panic with custom message for Nil."""
77 raise ValueError(message)
79 def and_then(self, func: Callable[[T], Option[U]]) -> Option[U]:
80 """Rust-style: Return Nil since this is Nil."""
81 return cast(Option[U], self)
83 def or_else_with(self, func: Callable[[], Option[T]]) -> Option[T]:
84 """Rust-style: Call func to get alternative since self is Nil."""
85 return func()
87 def and_(self, other: Option[U]) -> Option[U]:
88 """Rust-style: Return Nil since self is Nil."""
89 return cast(Option[U], self)
91 def or_(self, other: Option[T]) -> Option[T]:
92 """Rust-style: Return other since self is Nil."""
93 return other
95 def xor(self, other: Option[T]) -> Option[T]:
96 """Rust-style: Return other since self is Nil."""
97 return other
100 def zip_with(self, other: Option[U], func: Callable[[T, U], V]) -> Option[V]:
101 """Rust-style: Return Nil since self is Nil."""
102 return cast(Option[V], self)
104 def inspect(self, func: Callable[[T], Any]) -> Option[T]:
105 """Rust-style: Do nothing since self is Nil, return self."""
106 return self
108 def get_or_insert(self, value: T) -> T:
109 """Rust-style: Return the inserted value since Nil is empty."""
110 return value
112 def get_or_insert_with(self, func: Callable[[], T]) -> T:
113 """Rust-style: Call func and return result since Nil is empty."""
114 return func()
116 def insert(self, value: T) -> T:
117 """Rust-style: Return the inserted value."""
118 return value
120 def map_or(self, default: U, func: Callable[[T], U]) -> U:
121 """Rust-style: Return default since Nil has no value."""
122 return default
124 def map_or_else(self, default_func: Callable[[], U], func: Callable[[T], U]) -> U:
125 """Rust-style: Call default_func since Nil has no value."""
126 return default_func()
128 def ok_or(self, error: E) -> Any: # Returns Result[T, E]
129 """Rust-style: Convert Nil to Err(error)."""
130 from ..result import Err
131 return Err(error)
133 def ok_or_else(self, func: Callable[[], E]) -> Any: # Returns Result[T, E]
134 """Rust-style: Convert Nil to Err(func())."""
135 from ..result import Err
136 return Err(func())
138 # ========================================
139 # SCALA API
140 # ========================================
142 def get(self) -> T:
143 raise ValueError("Cannot get value from empty Option")
145 def get_or_else(self, default: Union[T, Callable[[], T]]) -> T:
146 if callable(default):
147 try:
148 return default()
149 except Exception:
150 raise ValueError("Default function failed and Option is empty")
151 return default
153 def or_else(self, alternative: Union[Option[T], Callable[[], Option[T]]]) -> Option[T]:
154 if callable(alternative):
155 try:
156 return alternative()
157 except Exception:
158 return self
159 return alternative
161 def filter_not(self, predicate: Callable[[T], bool]) -> Option[T]:
162 # Nil filters to Nil regardless of predicate
163 return self
165 def flat_map(self, func: Callable[[T], Option[U]]) -> Option[U]:
166 # Nil flat_maps to Nil regardless of function
167 return Nil()
169 def fold(self, if_empty: U, func: Callable[[T], U]) -> U:
170 # Nil always returns the empty value
171 return if_empty
173 def foreach(self, func: Callable[[T], Any]) -> None:
174 """Scala-style: Nil does nothing."""
175 pass
177 def exists(self, predicate: Callable[[T], bool]) -> bool:
178 # Nil never satisfies any predicate
179 return False
181 def forall(self, predicate: Callable[[T], bool]) -> bool:
182 """Scala-style: Nil vacuously satisfies all predicates."""
183 return True
185 def contains(self, value: Any) -> bool:
186 """Scala-style: Nil never contains any value."""
187 return False
189 def non_empty(self) -> bool:
190 """Scala-style: False since Nil is empty."""
191 return False
193 def or_null(self) -> Optional[T]:
194 """Scala-style: Return None since Nil is empty."""
195 return None
197 def or_none(self) -> Optional[T]:
198 """Return None since Nil is empty. Alias for or_null."""
199 return None
201 def to_list(self) -> list[T]:
202 # Nil converts to empty list
203 return []
205 def to_optional(self) -> Optional[T]:
206 # Nil converts to None
207 return None
210 # ========================================
211 # PYTHON SPECIAL METHODS
212 # ========================================
214 def __bool__(self) -> bool:
215 return False
217 def __iter__(self) -> Iterator[T]:
218 # Nil yields nothing
219 return iter([])
221 def __eq__(self, other: object) -> bool:
222 # Nil is equal to other Nil instances
223 return isinstance(other, NilType)
225 def __repr__(self) -> str:
226 return "Nil()"
228 def __str__(self) -> str:
229 return self.__repr__()
232# Export singleton class
233Nil = NilType