sain

sain is a set of minimal abstraction that brings Rust's ecosystem to Python. It offers a few of the core Rust types like Vec<T> and Result<T, E> and more.

  1# BSD 3-Clause License
  2#
  3# Copyright (c) 2022-Present, nxtlo
  4# All rights reserved.
  5#
  6# Redistribution and use in source and binary forms, with or without
  7# modification, are permitted provided that the following conditions are met:
  8#
  9# * Redistributions of source code must retain the above copyright notice, this
 10#   list of conditions and the following disclaimer.
 11#
 12# * Redistributions in binary form must reproduce the above copyright notice,
 13#   this list of conditions and the following disclaimer in the documentation
 14#   and/or other materials provided with the distribution.
 15#
 16# * Neither the name of the copyright holder nor the names of its
 17#   contributors may be used to endorse or promote products derived from
 18#   this software without specific prior written permission.
 19#
 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30
 31"""sain is a set of minimal abstraction that brings Rust's ecosystem to Python. It offers a few of the core Rust types like `Vec<T>` and `Result<T, E>` and more."""
 32
 33from __future__ import annotations
 34
 35__all__ = (
 36    # cfg.py
 37    "cfg",
 38    "cfg_attr",
 39    # default.py
 40    "default",
 41    "Default",
 42    # option.py
 43    "option",
 44    "Some",
 45    "Option",
 46    "NOTHING",
 47    # iter.py
 48    "Iter",
 49    "Iterator",
 50    "iter",
 51    # macros.py
 52    "macros",
 53    "todo",
 54    "deprecated",
 55    "unimplemented",
 56    "doc",
 57    "include_str",
 58    "include_bytes",
 59    "assert_eq",
 60    "assert_ne",
 61    # futures.py
 62    "futures",
 63    # result.py
 64    "result",
 65    "Ok",
 66    "Err",
 67    "Result",
 68    # collections
 69    "collections",
 70    "Vec",
 71    # error.py
 72    "error",
 73    "Error",
 74    # boxed.py
 75    "boxed",
 76    "Box",
 77    # sync
 78    "sync",
 79    # maybe_uninit.py
 80    "maybe_uninit",
 81    # convert
 82    "convert",
 83    "From",
 84    "TryFrom",
 85    "Into",
 86    "TryInto",
 87    "ToString",
 88)
 89
 90from . import boxed
 91from . import collections
 92from . import convert
 93from . import default
 94from . import error
 95from . import futures
 96from . import iter
 97from . import macros
 98from . import maybe_uninit
 99from . import option
100from . import result
101from . import sync
102from .boxed import Box
103from .cfg import cfg
104from .cfg import cfg_attr
105from .collections import Vec
106from .convert import From
107from .convert import Into
108from .convert import ToString
109from .convert import TryFrom
110from .convert import TryInto
111from .default import Default
112from .error import Error
113from .iter import Iter
114from .iter import Iterator
115from .macros import assert_eq
116from .macros import assert_ne
117from .macros import deprecated
118from .macros import doc
119from .macros import include_bytes
120from .macros import include_str
121from .macros import todo
122from .macros import unimplemented
123from .option import NOTHING
124from .option import Option
125from .option import Some
126from .result import Err
127from .result import Ok
128from .result import Result
129
130__version__: str = "1.3.0"
131__url__: str = "https://github.com/nxtlo/sain"
132__author__: str = "nxtlo"
133__about__: str = (
134    "Sain is a dependency-free library that implements some of the Rust core"
135    "types which abstracts over common patterns in Rust for Python."
136)
137__license__: str = "BSD 3-Clause License"
@rustc_diagnostic_item('cfg')
def cfg( target_os: Optional[Literal['linux', 'win32', 'darwin', 'macos', 'unix', 'windows', 'ios']] = None, python_version: tuple[int, int, int] | None = None, target_arch: Optional[Literal['x86', 'x86_64', 'arm', 'arm64']] = None, impl: Optional[Literal['CPython', 'PyPy', 'IronPython', 'Jython']] = None) -> bool:
173@rustc_diagnostic_item("cfg")
174def cfg(
175    target_os: System | None = None,
176    python_version: tuple[int, int, int] | None = None,
177    target_arch: Arch | None = None,
178    impl: Python | None = None,
179) -> bool:
180    """A function that will run the code only if all predicate attributes returns `True`.
181
182    The difference between this function and `cfg_attr` is that this function will not raise an exception.
183    Instead it will return `False` if any of the attributes fails.
184
185    Example
186    -------
187    ```py
188    import sain
189
190    if cfg(target_os="windows"):
191        print("Windows")
192    elif cfg(target_os="linux", target_arch="arm64"):
193        print("Linux")
194    else:
195        print("Something else")
196    ```
197
198    Parameters
199    ----------
200    target_os : `str | None`
201        The targeted operating system thats required for the object to be ran.
202    python_version : `tuple[int, int, int] | None`
203        The targeted Python version thats required for the object to be ran. Format must be `(3, 9, 5)``
204    target_arch : `str | None`
205        The CPU targeted architecture thats required for the object to be ran.
206    impl : `str | None`
207        The Python implementation thats required for the object to be ran.
208
209    Returns
210    -------
211    `bool`
212        The condition that was checked.
213    """
214    checker = _AttrCheck(
215        lambda: None,
216        no_raise=True,
217        target_os=target_os,
218        python_version=python_version,
219        target_arch=target_arch,
220        impl=impl,
221    )
222    return checker.internal_check()

A function that will run the code only if all predicate attributes returns True.

The difference between this function and cfg_attr is that this function will not raise an exception. Instead it will return False if any of the attributes fails.

Example
import sain

if cfg(target_os="windows"):
    print("Windows")
elif cfg(target_os="linux", target_arch="arm64"):
    print("Linux")
else:
    print("Something else")
Parameters
  • target_os (str | None): The targeted operating system thats required for the object to be ran.
  • python_version (tuple[int, int, int] | None): The targeted Python version thats required for the object to be ran. Format must be `(3, 9, 5)``
  • target_arch (str | None): The CPU targeted architecture thats required for the object to be ran.
  • impl (str | None): The Python implementation thats required for the object to be ran.
Returns
  • bool: The condition that was checked.
  • # Implementations
  • **This function implements cfg:
@rustc_diagnostic_item('cfg_attr')
def cfg_attr( *, target_os: Optional[Literal['linux', 'win32', 'darwin', 'macos', 'unix', 'windows', 'ios']] = None, python_version: tuple[int, int, int] | None = None, target_arch: Optional[Literal['x86', 'x86_64', 'arm', 'arm64']] = None, impl: Optional[Literal['CPython', 'PyPy', 'IronPython', 'Jython']] = None) -> Callable[[~F], ~F]:
101@rustc_diagnostic_item("cfg_attr")
102def cfg_attr(
103    *,
104    target_os: System | None = None,
105    python_version: tuple[int, int, int] | None = None,
106    target_arch: Arch | None = None,
107    impl: Python | None = None,
108) -> collections.Callable[[F], F]:
109    """Conditional runtime object configuration based on passed arguments.
110
111    If the decorated object gets called and one of the attributes returns `False`,
112    `RuntimeError` will be raised and the object will not run.
113
114    Example
115    -------
116    ```py
117    import sain
118
119    @cfg_attr(target_os="windows")
120    def windows_only():
121        # Do stuff with Windows's API.
122        ...
123
124    # Mut be PyPy Python implementation or `RuntimeError` will be raised
125    # when creating the instance.
126    @cfg_attr(impl="PyPy")
127    class Zoo:
128        @sain.cfg_attr(target_os="linux")
129        def bark(self) -> None:
130            ...
131
132    # An instance will not be created if raised.
133    zoo = Zoo()
134    # RuntimeError("class Zoo requires PyPy implementation")
135    ```
136
137    Parameters
138    ----------
139    target_os : `str | None`
140        The targeted operating system thats required for the object.
141    python_version : `tuple[int, int, int] | None`
142        The targeted Python version thats required for the object. Format must be `(3, 9, 5)`.
143    target_arch : `str | None`
144        The CPU targeted architecture thats required for the object.
145    impl : `str | None`
146        The Python implementation thats required for the object.
147
148    Raises
149    ------
150    `RuntimeError`
151        This fails if any of the attributes returns `False`.
152    `ValueError`
153        If the passed Python implementation is unknown.
154    """
155
156    def decorator(callback: F) -> F:
157        @functools.wraps(callback)
158        def wrapper(*args: typing.Any, **kwargs: typing.Any) -> F:
159            checker = _AttrCheck(
160                callback,
161                target_os=target_os,
162                python_version=python_version,
163                target_arch=target_arch,
164                impl=impl,
165            )
166            return checker(*args, **kwargs)
167
168        return typing.cast(F, wrapper)
169
170    return decorator

Conditional runtime object configuration based on passed arguments.

If the decorated object gets called and one of the attributes returns False, RuntimeError will be raised and the object will not run.

Example
import sain

@cfg_attr(target_os="windows")
def windows_only():
    # Do stuff with Windows's API.
    ...

# Mut be PyPy Python implementation or `RuntimeError` will be raised
# when creating the instance.
@cfg_attr(impl="PyPy")
class Zoo:
    @sain.cfg_attr(target_os="linux")
    def bark(self) -> None:
        ...

# An instance will not be created if raised.
zoo = Zoo()
# RuntimeError("class Zoo requires PyPy implementation")
Parameters
  • target_os (str | None): The targeted operating system thats required for the object.
  • python_version (tuple[int, int, int] | None): The targeted Python version thats required for the object. Format must be (3, 9, 5).
  • target_arch (str | None): The CPU targeted architecture thats required for the object.
  • impl (str | None): The Python implementation thats required for the object.
Raises
  • RuntimeError: This fails if any of the attributes returns False.
  • ValueError: If the passed Python implementation is unknown.
  • # Implementations
  • **This function implements cfg_attr:
@rustc_diagnostic_item('Default')
@typing.runtime_checkable
class Default(typing.Protocol[+_T_co]):
58@rustc_diagnostic_item("Default")
59@typing.runtime_checkable
60class Default(typing.Protocol[_T_co]):
61    """An interface for an object that has a default value.
62
63    Example
64    -------
65    ```py
66    from sain import Default
67
68    class Cache(Default[dict[str, Any]]):
69
70        @staticmethod
71        def default() -> dict[str, Any]:
72            return {}
73
74    cache = Cache.default()
75    print(cache)
76    assert isinstance(cache, Default)
77    # {}
78    ```
79    """
80
81    __slots__ = ()
82
83    @rustc_diagnostic_item("default_fn")
84    @staticmethod
85    def default() -> _T_co:
86        """Return the default value of the object."""
87        raise NotImplementedError

An interface for an object that has a default value.

Example
from sain import Default

class Cache(Default[dict[str, Any]]):

    @staticmethod
    def default() -> dict[str, Any]:
        return {}

cache = Cache.default()
print(cache)
assert isinstance(cache, Default)
# {}

Implementations

This class implements Default in Rust.

Default(*args, **kwargs)
1941def _no_init_or_replace_init(self, *args, **kwargs):
1942    cls = type(self)
1943
1944    if cls._is_protocol:
1945        raise TypeError('Protocols cannot be instantiated')
1946
1947    # Already using a custom `__init__`. No need to calculate correct
1948    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1949    if cls.__init__ is not _no_init_or_replace_init:
1950        return
1951
1952    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1953    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1954    # searches for a proper new `__init__` in the MRO. The new `__init__`
1955    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1956    # instantiation of the protocol subclass will thus use the new
1957    # `__init__` and no longer call `_no_init_or_replace_init`.
1958    for base in cls.__mro__:
1959        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1960        if init is not _no_init_or_replace_init:
1961            cls.__init__ = init
1962            break
1963    else:
1964        # should not happen
1965        cls.__init__ = object.__init__
1966
1967    cls.__init__(self, *args, **kwargs)
@rustc_diagnostic_item('default_fn')
@staticmethod
def default() -> +_T_co:
83    @rustc_diagnostic_item("default_fn")
84    @staticmethod
85    def default() -> _T_co:
86        """Return the default value of the object."""
87        raise NotImplementedError

Return the default value of the object.

@rustc_diagnostic_item('Option')
@typing.final
class Some(typing.Generic[~T], sain.Default[ForwardRef('Option[None]')]):
 56@rustc_diagnostic_item("Option")
 57@typing.final
 58class Some(typing.Generic[T], _default.Default["Option[None]"]):
 59    """The `Option` type. An object that might be `T` or `None`.
 60
 61    It is a replacement for `typing.Optional[T]`, with more convenient methods to handle the contained value.
 62
 63    Example
 64    -------
 65    ```py
 66    value = Some("Hello")
 67    print(value)
 68    # Some("Hello")
 69
 70    # This will unwrap the contained value as long as
 71    # it is not `None` otherwise this will raise an error.
 72    print(value.unwrap())
 73    # "Hello"
 74
 75    none_value = Some(None)
 76    while none_value.unwrap():
 77        # Never unreachable!
 78
 79    # Solving it with `unwrap_or` method to unwrap the value or return a default value.
 80    print(none_value.unwrap_or(10))
 81    # 10
 82    ```
 83    """
 84
 85    __slots__ = ("_value",)
 86    __match_args__ = ("_value",)
 87
 88    def __init__(self, value: T | None, /) -> None:
 89        self._value = value
 90
 91    @staticmethod
 92    def default() -> Option[None]:
 93        """Default value for `Some`. Returns `None` wrapped in `Some`.
 94
 95        Example
 96        -------
 97        ```py
 98        assert Some.default() == NOTHING
 99        ```
100        """
101        return NOTHING
102
103    # *- Reading the value -*
104
105    def transpose(self) -> T | None:
106        """Convert `Option[T]` into `T | None`.
107
108        Examples
109        --------
110        ```py
111        opt = Some('char')
112        x = opt.transpose()
113        assert x == 'char'
114
115        opt = Some(None)
116        assert opt.transpose() is None
117        ```
118        """
119        return self._value
120
121    def unwrap(self) -> T:
122        """Unwrap the inner value either returning if its not `None` or raising a `RuntimeError`.
123
124        It's usually not recommended to use this method in production code, since it raises.
125
126        Example
127        -------
128        ```py
129        value = Some(5)
130        print(value.unwrap())
131        # 5
132
133        value = Some(None)
134        print(value.unwrap())
135        # RuntimeError
136        ```
137
138        Raises
139        ------
140        `RuntimeError`
141            If the inner value is `None`.
142        """
143        if self._value is None:
144            raise RuntimeError("Called `Option.unwrap()` on `None`.") from None
145
146        return self._value
147
148    def unwrap_or(self, default: T, /) -> T:
149        """Unwrap the inner value either returning if its not `None` or returning `default`.
150
151        Example
152        -------
153        ```py
154        value = Some(5)
155        print(value.unwrap_or(10))
156        # 5
157
158        # Type hint is required here.
159        value: Option[int] = Some(None)
160        print(value.unwrap_or(10))
161        # 10
162        ```
163        """
164        if self._value is None:
165            return default
166
167        return self._value
168
169    def unwrap_or_else(self, f: FnOnce[T], /) -> T:
170        """Unwrap the inner value either returning if its not `None` or calling `f` to get a default value.
171
172        Example
173        -------
174        ```py
175        value = Some(5)
176        print(value.unwrap_or_else(lambda: 10))
177        # 5
178
179        value: Option[bool] = Some(None)
180        print(value.unwrap_or_else(lambda: True))
181        # True
182        ```
183        """
184        if self._value is None:
185            return f()
186
187        return self._value
188
189    @macros.unsafe
190    def unwrap_unchecked(self) -> T:
191        """Returns the contained Some value without checking that the value is not None.
192
193        Example
194        -------
195        ```py
196        v: Option[float] = Some(1.2)
197        v.unwrap_unchecked() # 1.2
198
199        v: Option[float] = Some(None)
200        print(v.unwrap_unchecked()) # Undefined Behavior
201        ```
202        """
203        #! SAFETY: The caller guarantees that the value is not None.
204        return self._value  # pyright: ignore
205
206    def expect(self, message: str, /) -> T:
207        """Returns the contained value if it is not `None` otherwise raises a `RuntimeError`.
208
209        Example
210        -------
211        ```py
212        value = Some("Hello")
213
214        print(value.expect("Value is None"))
215        # "Hello"
216
217        value: Option[str] = Some(None)
218        print(value.expect("Value is None"))
219        # RuntimeError("Value is None")
220        ```
221        """
222        if self._value is None:
223            raise RuntimeError(message)
224
225        return self._value
226
227    # *- object transformation -*
228
229    def map(self, f: Fn[T, U], /) -> Option[U]:
230        """Map the inner value to another type. Returning `Some(None)` if `T` is `None`.
231
232        Example
233        -------
234        ```py
235        value = Some(5.0)
236
237        print(value.map(lambda x: x * 2.0))
238        # Some(10.0)
239
240        value: Option[bool] = Some(None)
241        print(value)
242        # Some(None)
243        ```
244        """
245        if self._value is None:
246            return NOTHING  # pyright: ignore
247
248        return Some(f(self._value))
249
250    def map_or(self, default: U, f: Fn[T, U], /) -> U:
251        """Map the inner value to another type or return `default` if its `None`.
252
253        Example
254        -------
255        ```py
256        value: Option[float] = Some(5.0)
257
258        # map to int.
259        print(value.map_or(0, int))
260        # 6
261
262        value: Option[float] = Some(None)
263        print(value.map_or(0, int)
264        # 0
265        ```
266        """
267        if self._value is None:
268            return default
269
270        return f(self._value)
271
272    def map_or_else(self, default: FnOnce[U], f: Fn[T, U], /) -> U:
273        """Map the inner value to another type, or return `default()` if its `None`.
274
275        Example
276        -------
277        ```py
278        def default() -> int:
279            return sys.getsizeof(object())
280
281        value: Option[float] = Some(5.0)
282
283        # map to int.
284        print(value.map_or_else(default, int))
285        # 6
286
287        value: Option[float] = Some(None)
288        print(value.map_or_else(default, int)
289        # 28 <- size of object()
290        ```
291        """
292        if self._value is None:
293            return default()
294
295        return f(self._value)
296
297    def filter(self, predicate: Fn[T, bool]) -> Option[T]:
298        """Returns `Some(None)` if the contained value is `None`,
299
300        otherwise calls the predicate and returns `Some(T)` if the predicate returns `True`.
301
302        Example
303        -------
304        ```py
305        value = Some([1, 2, 3])
306
307        print(value.filter(lambda x: 1 in x))
308        # Some([1, 2, 3])
309
310        value: Option[int] = Some([1, 2, 3]) # or Some(None)
311        print(value.filter(lambda x: 1 not in x))
312        # None
313        ```
314        """
315        if (value := self._value) is not None:
316            if predicate(value):
317                return Some(value)
318
319        return NOTHING  # pyright: ignore
320
321    def ok_or(self, err: U) -> _result.Result[T, U]:
322        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
323
324        Example
325        -------
326        ```py
327        xyz: Option[str] = Some("foo")
328        assert xyz.ok_or(None) == Ok("foo")
329
330        xyz: Option[str] = Some(None)
331        assert xyz.ok_or(None) == Err(None)
332        ```
333        """
334        if self._value is None:
335            return _result.Err(err)
336
337        return _result.Ok(self._value)
338
339    def ok_or_else(self, err: FnOnce[U]) -> _result.Result[T, U]:
340        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`.
341
342        Example
343        -------
344        ```py
345        xyz: Option[str] = Some("foo")
346        assert xyz.ok_or(None) == Ok("foo")
347
348        xyz: Option[str] = Some(None)
349        assert xyz.ok_or(None) == Err(None)
350        ```
351        """
352        if self._value is None:
353            return _result.Err(err())
354
355        return _result.Ok(self._value)
356
357    def zip(self, other: Option[U]) -> Option[tuple[T, U]]:
358        """Zips `self` with `other`.
359
360        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some((s, o))` otherwise `None`.
361
362        Example
363        -------
364        ```py
365        x = Some(1)
366        y = Some("hi")
367        z: Option[str] = Some(None)
368
369        assert x.zip(y) == Some((1, "hi"))
370        assert x.zip(z) == Some(None)
371        ```
372        """
373        if self._value is not None and other._value is not None:
374            return Some((self._value, other._value))
375
376        return NOTHING  # type: ignore
377
378    def zip_with(
379        self, other: Option[U], f: collections.Callable[[T, U], T_co]
380    ) -> Option[T_co]:
381        """Zips `self` with `other` using function `f`.
382
383        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some(f(s, o))` otherwise `None`.
384
385        Example
386        -------
387        ```py
388        @dataclass
389        class Point:
390            x: float
391            y: float
392
393        x, y = Some(32.1), Some(42.4)
394        assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))
395        ```
396        """
397        if self._value is not None and other._value is not None:
398            return Some(f(self._value, other._value))
399
400        return NOTHING  # type: ignore
401
402    # *- Inner operations *-
403
404    def take(self) -> Option[T]:
405        """Take the value from `Self`, Setting it to `None`.
406
407        Example
408        -------
409        ```py
410        original = Some("Hi")
411        new = original.take()
412
413        print(original, new)
414        # None, Some("Hi")
415        ```
416        """
417        if self._value is None:
418            return NOTHING  # pyright: ignore
419
420        val = self._value
421        self._value = None
422        return Some(val)
423
424    def take_if(self, predicate: collections.Callable[[T], bool]) -> Option[T]:
425        """Take the value from `Self`, Setting it to `None` only if predicate returns `True`.
426
427        Example
428        -------
429        ```py
430        def validate(email: str) -> bool:
431            # you can obviously validate this better.
432            return email.find('@') == 1
433
434        original = Some("flex@gg.com")
435        valid = original.take_if(validate)
436        assert is_allowed.is_some() and original.is_none()
437
438        original = Some("mail.example.com")
439        invalid = original.take_if(validate)
440        assert invalid.is_none() and original.is_some()
441        ```
442        """
443        if self.map_or(False, predicate):
444            return self.take()
445
446        return NOTHING  # pyright: ignore
447
448    def replace(self, value: T) -> Option[T]:
449        """Replace the contained value with another value.
450
451        Use `Option.insert` if you want to return the original value
452        that got inserted instead of `self`
453
454        Example
455        -------
456        ```py
457        value: Option[str] = Some(None)
458        value.replace("Hello")
459        # Some("Hello")
460        ```
461        """
462        self._value = value
463        return self
464
465    def insert(self, value: T) -> T:
466        """Insert a value into the option, and then return a reference to it.
467
468        This will overwrite the old value if it was already contained.
469
470        Example
471        -------
472        ```py
473        flag: Option[bool] = Some(None)
474        flag_ref = flag.insert(True)
475        assert flag_ref == True
476        assert flag.unwrap() == True
477        ```
478        """
479        self._value = value
480        return value
481
482    def get_or_insert(self, value: T) -> T:
483        """Insert a value into the option if it was `None`,
484        and then return a reference to it.
485
486        Example
487        -------
488        ```py
489        state: Option[bool] = Some(None)
490        assert state.get_or_insert(True) is True
491        assert state.get_or_insert(False) is True
492        ```
493        """
494        if self._value is not None:
495            return self._value
496
497        self._value = value
498        return value
499
500    def get_or_insert_with(self, f: FnOnce[T]) -> T:
501        """Insert a value into the option computed from `f()` if it was `None`,
502        and then return a reference to it.
503
504        Example
505        -------
506        ```py
507        flag: Option[bool] = Some(None)
508        flag_ref = flag.insert(True)
509        assert flag_ref == True
510        assert flag.unwrap() == True
511        ```
512        """
513        if self._value is not None:
514            return self._value
515
516        v = self._value = f()
517        return v
518
519    def and_ok(self, optb: Option[T]) -> Option[T]:
520        """Returns `None` if `self` or `optb` is `None`, otherwise return `optb`.
521
522        aliases: `Option::and`
523
524        Example
525        -------
526        ```py
527        x = Some(1)
528        y: Option[str] = Some(None)
529        assert x.and_ok(y) == Some(None)
530
531        x: Option[str] = Some(None)
532        y = Some(1)
533        assert x.and_ok(y) == Some(None)
534
535        y: Option[str] = Some("hi")
536        y = Some(100)
537        assert x.and_ok(y) == Some(100)
538        ```
539        """
540        if self._value is None or optb._value is None:
541            return optb
542
543        return NOTHING  # pyright: ignore
544
545    def and_then(self, f: Fn[T, Option[T]]) -> Option[T]:
546        """Returns `Some(None)` if the contained value is `None`, otherwise call `f()`
547        on `T` and return `Option[T]`.
548
549        Example
550        -------
551        ```py
552        value = Some(5)
553        print(value.and_then(lambda x: Some(x * 2)))
554        # Some(10)
555
556        value: Option[int] = Some(None)
557        print(value.and_then(lambda x: Some(x * 2)))
558        # Some(None)
559        ```
560        """
561        if self._value is None:
562            return NOTHING  # pyright: ignore
563
564        return f(self._value)
565
566    def inspect(self, f: Fn[T, typing.Any]) -> Option[T]:
567        """Calls `f()` on the contained value if it was `Some(v)`, otherwise does nothing.
568
569        Example
570        -------
571        ```py
572        def debug(x: str) -> None:
573            print("Debugging:", x)
574
575        value = Some("foo")
576        inner = value.inspect(debug).expect("no value to debug")
577        # prints: Debugging: "foo"
578
579        value: Option[str] = Some(None)
580        value.inspect(debug) # prints nothing
581        """
582        if self._value is not None:
583            f(self._value)
584
585        return self
586
587    # *- Builder methods *-
588
589    def iter(self) -> _iter.Iterator[T]:
590        """Returns an iterator over the contained value.
591
592        Example
593        -------
594        ```py
595        from sain import Some
596        value = Some("gg").iter()
597        assert value.next() == Some("gg")
598
599        value: Option[int] = Some(None)
600        assert value.iter().next().is_none()
601        ```
602        """
603        if self._value is None:
604            return _iter.empty()
605
606        return _iter.once(self._value)
607
608    # *- Boolean checks *-
609
610    def is_some(self) -> bool:
611        """Returns `True` if the contained value is not `None`, otherwise returns `False`.
612
613        Example
614        -------
615        ```py
616        value = Some(5)
617        print(value.is_some())
618        # True
619
620        value: Option[int] = Some(None)
621        print(value.is_some())
622        # False
623        ```
624        """
625        return self._value is not None
626
627    def is_some_and(self, predicate: Fn[T, bool]) -> bool:
628        """Returns `True` if the contained value is not `None` and
629        the predicate returns `True`, otherwise returns `False`.
630
631        Example
632        -------
633        ```py
634        value = Some(5)
635        print(value.is_some_and(lambda x: x > 3))
636        # True
637
638        value: Option[int] = Some(None)
639        print(value.is_some_and(lambda x: x > 3))
640        # False
641        ```
642        """
643        return self._value is not None and predicate(self._value)
644
645    def is_none(self) -> bool:
646        """Returns `True` if the contained value is `None`, otherwise returns `False`.
647
648        Example
649        -------
650        ```py
651        value = Some(5)
652        print(value.is_none())
653        # False
654
655        value: Option[int] = Some(None)
656        print(value.is_none())
657        # True
658        ```
659        """
660        return self._value is None
661
662    def is_none_or(self, f: Fn[T, bool]) -> bool:
663        """Returns `True` if the contained value is `None` or the predicate returns `True`,
664        otherwise returns `False`.
665
666        Example
667        -------
668        ```py
669        value = Some(5)
670        print(value.is_none_or(lambda x: x > 3))
671        # False
672
673        value: Option[int] = Some(None)
674        print(value.is_none_or(lambda x: x > 3))
675        # True
676        ```
677        """
678        match self._value:
679            case None:
680                return True
681            case x:
682                return f(x)
683
684    def __repr__(self) -> str:
685        if self._value is None:
686            return "None"
687        return f"Some({self._value!r})"
688
689    __str__ = __repr__
690
691    def __invert__(self) -> T:
692        return self.unwrap()
693
694    def __or__(self, other: T) -> T:
695        return self.unwrap_or(other)
696
697    def __bool__(self) -> bool:
698        return self.is_some()
699
700    def __eq__(self, other: object) -> bool:
701        if not isinstance(other, Some):
702            return NotImplemented
703
704        return self._value == other._value  # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType]
705
706    def __ne__(self, other: object) -> bool:
707        return not self.__eq__(other)
708
709    def __hash__(self) -> int:
710        return hash(self._value)

The Option type. An object that might be T or None.

It is a replacement for typing.Optional[T], with more convenient methods to handle the contained value.

Example
value = Some("Hello")
print(value)
# Some("Hello")

# This will unwrap the contained value as long as
# it is not `None` otherwise this will raise an error.
print(value.unwrap())
# "Hello"

none_value = Some(None)
while none_value.unwrap():
    # Never unreachable!

# Solving it with `unwrap_or` method to unwrap the value or return a default value.
print(none_value.unwrap_or(10))
# 10

Implementations

This class implements Option in Rust.

Some(value: Optional[~T], /)
88    def __init__(self, value: T | None, /) -> None:
89        self._value = value
@staticmethod
def default() -> 'Option[None]':
 91    @staticmethod
 92    def default() -> Option[None]:
 93        """Default value for `Some`. Returns `None` wrapped in `Some`.
 94
 95        Example
 96        -------
 97        ```py
 98        assert Some.default() == NOTHING
 99        ```
100        """
101        return NOTHING

Default value for Some. Returns None wrapped in Some.

Example
assert Some.default() == NOTHING
def transpose(self) -> Optional[~T]:
105    def transpose(self) -> T | None:
106        """Convert `Option[T]` into `T | None`.
107
108        Examples
109        --------
110        ```py
111        opt = Some('char')
112        x = opt.transpose()
113        assert x == 'char'
114
115        opt = Some(None)
116        assert opt.transpose() is None
117        ```
118        """
119        return self._value

Convert Option[T] into T | None.

Examples
opt = Some('char')
x = opt.transpose()
assert x == 'char'

opt = Some(None)
assert opt.transpose() is None
def unwrap(self) -> ~T:
121    def unwrap(self) -> T:
122        """Unwrap the inner value either returning if its not `None` or raising a `RuntimeError`.
123
124        It's usually not recommended to use this method in production code, since it raises.
125
126        Example
127        -------
128        ```py
129        value = Some(5)
130        print(value.unwrap())
131        # 5
132
133        value = Some(None)
134        print(value.unwrap())
135        # RuntimeError
136        ```
137
138        Raises
139        ------
140        `RuntimeError`
141            If the inner value is `None`.
142        """
143        if self._value is None:
144            raise RuntimeError("Called `Option.unwrap()` on `None`.") from None
145
146        return self._value

Unwrap the inner value either returning if its not None or raising a RuntimeError.

It's usually not recommended to use this method in production code, since it raises.

Example
value = Some(5)
print(value.unwrap())
# 5

value = Some(None)
print(value.unwrap())
# RuntimeError
Raises
  • RuntimeError: If the inner value is None.
def unwrap_or(self, default: ~T, /) -> ~T:
148    def unwrap_or(self, default: T, /) -> T:
149        """Unwrap the inner value either returning if its not `None` or returning `default`.
150
151        Example
152        -------
153        ```py
154        value = Some(5)
155        print(value.unwrap_or(10))
156        # 5
157
158        # Type hint is required here.
159        value: Option[int] = Some(None)
160        print(value.unwrap_or(10))
161        # 10
162        ```
163        """
164        if self._value is None:
165            return default
166
167        return self._value

Unwrap the inner value either returning if its not None or returning default.

Example
value = Some(5)
print(value.unwrap_or(10))
# 5

# Type hint is required here.
value: Option[int] = Some(None)
print(value.unwrap_or(10))
# 10
def unwrap_or_else(self, f: Callable[[], ~T], /) -> ~T:
169    def unwrap_or_else(self, f: FnOnce[T], /) -> T:
170        """Unwrap the inner value either returning if its not `None` or calling `f` to get a default value.
171
172        Example
173        -------
174        ```py
175        value = Some(5)
176        print(value.unwrap_or_else(lambda: 10))
177        # 5
178
179        value: Option[bool] = Some(None)
180        print(value.unwrap_or_else(lambda: True))
181        # True
182        ```
183        """
184        if self._value is None:
185            return f()
186
187        return self._value

Unwrap the inner value either returning if its not None or calling f to get a default value.

Example
value = Some(5)
print(value.unwrap_or_else(lambda: 10))
# 5

value: Option[bool] = Some(None)
print(value.unwrap_or_else(lambda: True))
# True
@macros.unsafe
def unwrap_unchecked(self) -> ~T:
189    @macros.unsafe
190    def unwrap_unchecked(self) -> T:
191        """Returns the contained Some value without checking that the value is not None.
192
193        Example
194        -------
195        ```py
196        v: Option[float] = Some(1.2)
197        v.unwrap_unchecked() # 1.2
198
199        v: Option[float] = Some(None)
200        print(v.unwrap_unchecked()) # Undefined Behavior
201        ```
202        """
203        #! SAFETY: The caller guarantees that the value is not None.
204        return self._value  # pyright: ignore

Returns the contained Some value without checking that the value is not None.

Example
v: Option[float] = Some(1.2)
v.unwrap_unchecked() # 1.2

v: Option[float] = Some(None)
print(v.unwrap_unchecked()) # Undefined Behavior

Safety ⚠️

Calling this method on None is considered undefined behavior.

def expect(self, message: str, /) -> ~T:
206    def expect(self, message: str, /) -> T:
207        """Returns the contained value if it is not `None` otherwise raises a `RuntimeError`.
208
209        Example
210        -------
211        ```py
212        value = Some("Hello")
213
214        print(value.expect("Value is None"))
215        # "Hello"
216
217        value: Option[str] = Some(None)
218        print(value.expect("Value is None"))
219        # RuntimeError("Value is None")
220        ```
221        """
222        if self._value is None:
223            raise RuntimeError(message)
224
225        return self._value

Returns the contained value if it is not None otherwise raises a RuntimeError.

Example
value = Some("Hello")

print(value.expect("Value is None"))
# "Hello"

value: Option[str] = Some(None)
print(value.expect("Value is None"))
# RuntimeError("Value is None")
def map(self, f: Callable[[~T], ~U], /) -> 'Option[U]':
229    def map(self, f: Fn[T, U], /) -> Option[U]:
230        """Map the inner value to another type. Returning `Some(None)` if `T` is `None`.
231
232        Example
233        -------
234        ```py
235        value = Some(5.0)
236
237        print(value.map(lambda x: x * 2.0))
238        # Some(10.0)
239
240        value: Option[bool] = Some(None)
241        print(value)
242        # Some(None)
243        ```
244        """
245        if self._value is None:
246            return NOTHING  # pyright: ignore
247
248        return Some(f(self._value))

Map the inner value to another type. Returning Some(None) if T is None.

Example
value = Some(5.0)

print(value.map(lambda x: x * 2.0))
# Some(10.0)

value: Option[bool] = Some(None)
print(value)
# Some(None)
def map_or(self, default: ~U, f: Callable[[~T], ~U], /) -> ~U:
250    def map_or(self, default: U, f: Fn[T, U], /) -> U:
251        """Map the inner value to another type or return `default` if its `None`.
252
253        Example
254        -------
255        ```py
256        value: Option[float] = Some(5.0)
257
258        # map to int.
259        print(value.map_or(0, int))
260        # 6
261
262        value: Option[float] = Some(None)
263        print(value.map_or(0, int)
264        # 0
265        ```
266        """
267        if self._value is None:
268            return default
269
270        return f(self._value)

Map the inner value to another type or return default if its None.

Example
value: Option[float] = Some(5.0)

# map to int.
print(value.map_or(0, int))
# 6

value: Option[float] = Some(None)
print(value.map_or(0, int)
# 0
def map_or_else(self, default: Callable[[], ~U], f: Callable[[~T], ~U], /) -> ~U:
272    def map_or_else(self, default: FnOnce[U], f: Fn[T, U], /) -> U:
273        """Map the inner value to another type, or return `default()` if its `None`.
274
275        Example
276        -------
277        ```py
278        def default() -> int:
279            return sys.getsizeof(object())
280
281        value: Option[float] = Some(5.0)
282
283        # map to int.
284        print(value.map_or_else(default, int))
285        # 6
286
287        value: Option[float] = Some(None)
288        print(value.map_or_else(default, int)
289        # 28 <- size of object()
290        ```
291        """
292        if self._value is None:
293            return default()
294
295        return f(self._value)

Map the inner value to another type, or return default() if its None.

Example
def default() -> int:
    return sys.getsizeof(object())

value: Option[float] = Some(5.0)

# map to int.
print(value.map_or_else(default, int))
# 6

value: Option[float] = Some(None)
print(value.map_or_else(default, int)
# 28 <- size of object()
def filter(self, predicate: Callable[[~T], bool]) -> 'Option[T]':
297    def filter(self, predicate: Fn[T, bool]) -> Option[T]:
298        """Returns `Some(None)` if the contained value is `None`,
299
300        otherwise calls the predicate and returns `Some(T)` if the predicate returns `True`.
301
302        Example
303        -------
304        ```py
305        value = Some([1, 2, 3])
306
307        print(value.filter(lambda x: 1 in x))
308        # Some([1, 2, 3])
309
310        value: Option[int] = Some([1, 2, 3]) # or Some(None)
311        print(value.filter(lambda x: 1 not in x))
312        # None
313        ```
314        """
315        if (value := self._value) is not None:
316            if predicate(value):
317                return Some(value)
318
319        return NOTHING  # pyright: ignore

Returns Some(None) if the contained value is None,

otherwise calls the predicate and returns Some(T) if the predicate returns True.

Example
value = Some([1, 2, 3])

print(value.filter(lambda x: 1 in x))
# Some([1, 2, 3])

value: Option[int] = Some([1, 2, 3]) # or Some(None)
print(value.filter(lambda x: 1 not in x))
# None
def ok_or(self, err: ~U) -> '_result.Result[T, U]':
321    def ok_or(self, err: U) -> _result.Result[T, U]:
322        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
323
324        Example
325        -------
326        ```py
327        xyz: Option[str] = Some("foo")
328        assert xyz.ok_or(None) == Ok("foo")
329
330        xyz: Option[str] = Some(None)
331        assert xyz.ok_or(None) == Err(None)
332        ```
333        """
334        if self._value is None:
335            return _result.Err(err)
336
337        return _result.Ok(self._value)

Transforms the Option<T> into a Result<T, E>, mapping Some(v) to Ok(v) and None to Err(err).

Example
xyz: Option[str] = Some("foo")
assert xyz.ok_or(None) == Ok("foo")

xyz: Option[str] = Some(None)
assert xyz.ok_or(None) == Err(None)
def ok_or_else(self, err: Callable[[], ~U]) -> '_result.Result[T, U]':
339    def ok_or_else(self, err: FnOnce[U]) -> _result.Result[T, U]:
340        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`.
341
342        Example
343        -------
344        ```py
345        xyz: Option[str] = Some("foo")
346        assert xyz.ok_or(None) == Ok("foo")
347
348        xyz: Option[str] = Some(None)
349        assert xyz.ok_or(None) == Err(None)
350        ```
351        """
352        if self._value is None:
353            return _result.Err(err())
354
355        return _result.Ok(self._value)

Transforms the Option<T> into a Result<T, E>, mapping Some(v) to Ok(v) and None to Err(err()).

Example
xyz: Option[str] = Some("foo")
assert xyz.ok_or(None) == Ok("foo")

xyz: Option[str] = Some(None)
assert xyz.ok_or(None) == Err(None)
def zip(self, other: 'Option[U]') -> 'Option[tuple[T, U]]':
357    def zip(self, other: Option[U]) -> Option[tuple[T, U]]:
358        """Zips `self` with `other`.
359
360        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some((s, o))` otherwise `None`.
361
362        Example
363        -------
364        ```py
365        x = Some(1)
366        y = Some("hi")
367        z: Option[str] = Some(None)
368
369        assert x.zip(y) == Some((1, "hi"))
370        assert x.zip(z) == Some(None)
371        ```
372        """
373        if self._value is not None and other._value is not None:
374            return Some((self._value, other._value))
375
376        return NOTHING  # type: ignore

Zips self with other.

if self is Some(s) and other is Some(o), this returns Some((s, o)) otherwise None.

Example
x = Some(1)
y = Some("hi")
z: Option[str] = Some(None)

assert x.zip(y) == Some((1, "hi"))
assert x.zip(z) == Some(None)
def zip_with(self, other: 'Option[U]', f: Callable[[~T, ~U], +T_co]) -> 'Option[T_co]':
378    def zip_with(
379        self, other: Option[U], f: collections.Callable[[T, U], T_co]
380    ) -> Option[T_co]:
381        """Zips `self` with `other` using function `f`.
382
383        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some(f(s, o))` otherwise `None`.
384
385        Example
386        -------
387        ```py
388        @dataclass
389        class Point:
390            x: float
391            y: float
392
393        x, y = Some(32.1), Some(42.4)
394        assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))
395        ```
396        """
397        if self._value is not None and other._value is not None:
398            return Some(f(self._value, other._value))
399
400        return NOTHING  # type: ignore

Zips self with other using function f.

if self is Some(s) and other is Some(o), this returns Some(f(s, o)) otherwise None.

Example
@dataclass
class Point:
    x: float
    y: float

x, y = Some(32.1), Some(42.4)
assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))
def take(self) -> 'Option[T]':
404    def take(self) -> Option[T]:
405        """Take the value from `Self`, Setting it to `None`.
406
407        Example
408        -------
409        ```py
410        original = Some("Hi")
411        new = original.take()
412
413        print(original, new)
414        # None, Some("Hi")
415        ```
416        """
417        if self._value is None:
418            return NOTHING  # pyright: ignore
419
420        val = self._value
421        self._value = None
422        return Some(val)

Take the value from Self, Setting it to None.

Example
original = Some("Hi")
new = original.take()

print(original, new)
# None, Some("Hi")
def take_if(self, predicate: Callable[[~T], bool]) -> 'Option[T]':
424    def take_if(self, predicate: collections.Callable[[T], bool]) -> Option[T]:
425        """Take the value from `Self`, Setting it to `None` only if predicate returns `True`.
426
427        Example
428        -------
429        ```py
430        def validate(email: str) -> bool:
431            # you can obviously validate this better.
432            return email.find('@') == 1
433
434        original = Some("flex@gg.com")
435        valid = original.take_if(validate)
436        assert is_allowed.is_some() and original.is_none()
437
438        original = Some("mail.example.com")
439        invalid = original.take_if(validate)
440        assert invalid.is_none() and original.is_some()
441        ```
442        """
443        if self.map_or(False, predicate):
444            return self.take()
445
446        return NOTHING  # pyright: ignore

Take the value from Self, Setting it to None only if predicate returns True.

Example
def validate(email: str) -> bool:
    # you can obviously validate this better.
    return email.find('@') == 1

original = Some("flex@gg.com")
valid = original.take_if(validate)
assert is_allowed.is_some() and original.is_none()

original = Some("mail.example.com")
invalid = original.take_if(validate)
assert invalid.is_none() and original.is_some()
def replace(self, value: ~T) -> 'Option[T]':
448    def replace(self, value: T) -> Option[T]:
449        """Replace the contained value with another value.
450
451        Use `Option.insert` if you want to return the original value
452        that got inserted instead of `self`
453
454        Example
455        -------
456        ```py
457        value: Option[str] = Some(None)
458        value.replace("Hello")
459        # Some("Hello")
460        ```
461        """
462        self._value = value
463        return self

Replace the contained value with another value.

Use Option.insert if you want to return the original value that got inserted instead of self

Example
value: Option[str] = Some(None)
value.replace("Hello")
# Some("Hello")
def insert(self, value: ~T) -> ~T:
465    def insert(self, value: T) -> T:
466        """Insert a value into the option, and then return a reference to it.
467
468        This will overwrite the old value if it was already contained.
469
470        Example
471        -------
472        ```py
473        flag: Option[bool] = Some(None)
474        flag_ref = flag.insert(True)
475        assert flag_ref == True
476        assert flag.unwrap() == True
477        ```
478        """
479        self._value = value
480        return value

Insert a value into the option, and then return a reference to it.

This will overwrite the old value if it was already contained.

Example
flag: Option[bool] = Some(None)
flag_ref = flag.insert(True)
assert flag_ref == True
assert flag.unwrap() == True
def get_or_insert(self, value: ~T) -> ~T:
482    def get_or_insert(self, value: T) -> T:
483        """Insert a value into the option if it was `None`,
484        and then return a reference to it.
485
486        Example
487        -------
488        ```py
489        state: Option[bool] = Some(None)
490        assert state.get_or_insert(True) is True
491        assert state.get_or_insert(False) is True
492        ```
493        """
494        if self._value is not None:
495            return self._value
496
497        self._value = value
498        return value

Insert a value into the option if it was None, and then return a reference to it.

Example
state: Option[bool] = Some(None)
assert state.get_or_insert(True) is True
assert state.get_or_insert(False) is True
def get_or_insert_with(self, f: Callable[[], ~T]) -> ~T:
500    def get_or_insert_with(self, f: FnOnce[T]) -> T:
501        """Insert a value into the option computed from `f()` if it was `None`,
502        and then return a reference to it.
503
504        Example
505        -------
506        ```py
507        flag: Option[bool] = Some(None)
508        flag_ref = flag.insert(True)
509        assert flag_ref == True
510        assert flag.unwrap() == True
511        ```
512        """
513        if self._value is not None:
514            return self._value
515
516        v = self._value = f()
517        return v

Insert a value into the option computed from f() if it was None, and then return a reference to it.

Example
flag: Option[bool] = Some(None)
flag_ref = flag.insert(True)
assert flag_ref == True
assert flag.unwrap() == True
def and_ok(self, optb: 'Option[T]') -> 'Option[T]':
519    def and_ok(self, optb: Option[T]) -> Option[T]:
520        """Returns `None` if `self` or `optb` is `None`, otherwise return `optb`.
521
522        aliases: `Option::and`
523
524        Example
525        -------
526        ```py
527        x = Some(1)
528        y: Option[str] = Some(None)
529        assert x.and_ok(y) == Some(None)
530
531        x: Option[str] = Some(None)
532        y = Some(1)
533        assert x.and_ok(y) == Some(None)
534
535        y: Option[str] = Some("hi")
536        y = Some(100)
537        assert x.and_ok(y) == Some(100)
538        ```
539        """
540        if self._value is None or optb._value is None:
541            return optb
542
543        return NOTHING  # pyright: ignore

Returns None if self or optb is None, otherwise return optb.

aliases: Option::and

Example
x = Some(1)
y: Option[str] = Some(None)
assert x.and_ok(y) == Some(None)

x: Option[str] = Some(None)
y = Some(1)
assert x.and_ok(y) == Some(None)

y: Option[str] = Some("hi")
y = Some(100)
assert x.and_ok(y) == Some(100)
def and_then(self, f: 'Fn[T, Option[T]]') -> 'Option[T]':
545    def and_then(self, f: Fn[T, Option[T]]) -> Option[T]:
546        """Returns `Some(None)` if the contained value is `None`, otherwise call `f()`
547        on `T` and return `Option[T]`.
548
549        Example
550        -------
551        ```py
552        value = Some(5)
553        print(value.and_then(lambda x: Some(x * 2)))
554        # Some(10)
555
556        value: Option[int] = Some(None)
557        print(value.and_then(lambda x: Some(x * 2)))
558        # Some(None)
559        ```
560        """
561        if self._value is None:
562            return NOTHING  # pyright: ignore
563
564        return f(self._value)

Returns Some(None) if the contained value is None, otherwise call f() on T and return Option[T].

Example
value = Some(5)
print(value.and_then(lambda x: Some(x * 2)))
# Some(10)

value: Option[int] = Some(None)
print(value.and_then(lambda x: Some(x * 2)))
# Some(None)
def inspect(self, f: Callable[[~T], typing.Any]) -> 'Option[T]':
566    def inspect(self, f: Fn[T, typing.Any]) -> Option[T]:
567        """Calls `f()` on the contained value if it was `Some(v)`, otherwise does nothing.
568
569        Example
570        -------
571        ```py
572        def debug(x: str) -> None:
573            print("Debugging:", x)
574
575        value = Some("foo")
576        inner = value.inspect(debug).expect("no value to debug")
577        # prints: Debugging: "foo"
578
579        value: Option[str] = Some(None)
580        value.inspect(debug) # prints nothing
581        """
582        if self._value is not None:
583            f(self._value)
584
585        return self

Calls f() on the contained value if it was Some(v), otherwise does nothing.

Example

```py def debug(x: str) -> None: print("Debugging:", x)

value = Some("foo") inner = value.inspect(debug).expect("no value to debug")

prints: Debugging: "foo"

value: Option[str] = Some(None) value.inspect(debug) # prints nothing

def iter(self) -> Iterator[~T]:
589    def iter(self) -> _iter.Iterator[T]:
590        """Returns an iterator over the contained value.
591
592        Example
593        -------
594        ```py
595        from sain import Some
596        value = Some("gg").iter()
597        assert value.next() == Some("gg")
598
599        value: Option[int] = Some(None)
600        assert value.iter().next().is_none()
601        ```
602        """
603        if self._value is None:
604            return _iter.empty()
605
606        return _iter.once(self._value)

Returns an iterator over the contained value.

Example
from sain import Some
value = Some("gg")sain.iter()
assert value.next() == Some("gg")

value: Option[int] = Some(None)
assert value.iter().next().is_none()
def is_some(self) -> bool:
610    def is_some(self) -> bool:
611        """Returns `True` if the contained value is not `None`, otherwise returns `False`.
612
613        Example
614        -------
615        ```py
616        value = Some(5)
617        print(value.is_some())
618        # True
619
620        value: Option[int] = Some(None)
621        print(value.is_some())
622        # False
623        ```
624        """
625        return self._value is not None

Returns True if the contained value is not None, otherwise returns False.

Example
value = Some(5)
print(value.is_some())
# True

value: Option[int] = Some(None)
print(value.is_some())
# False
def is_some_and(self, predicate: Callable[[~T], bool]) -> bool:
627    def is_some_and(self, predicate: Fn[T, bool]) -> bool:
628        """Returns `True` if the contained value is not `None` and
629        the predicate returns `True`, otherwise returns `False`.
630
631        Example
632        -------
633        ```py
634        value = Some(5)
635        print(value.is_some_and(lambda x: x > 3))
636        # True
637
638        value: Option[int] = Some(None)
639        print(value.is_some_and(lambda x: x > 3))
640        # False
641        ```
642        """
643        return self._value is not None and predicate(self._value)

Returns True if the contained value is not None and the predicate returns True, otherwise returns False.

Example
value = Some(5)
print(value.is_some_and(lambda x: x > 3))
# True

value: Option[int] = Some(None)
print(value.is_some_and(lambda x: x > 3))
# False
def is_none(self) -> bool:
645    def is_none(self) -> bool:
646        """Returns `True` if the contained value is `None`, otherwise returns `False`.
647
648        Example
649        -------
650        ```py
651        value = Some(5)
652        print(value.is_none())
653        # False
654
655        value: Option[int] = Some(None)
656        print(value.is_none())
657        # True
658        ```
659        """
660        return self._value is None

Returns True if the contained value is None, otherwise returns False.

Example
value = Some(5)
print(value.is_none())
# False

value: Option[int] = Some(None)
print(value.is_none())
# True
def is_none_or(self, f: Callable[[~T], bool]) -> bool:
662    def is_none_or(self, f: Fn[T, bool]) -> bool:
663        """Returns `True` if the contained value is `None` or the predicate returns `True`,
664        otherwise returns `False`.
665
666        Example
667        -------
668        ```py
669        value = Some(5)
670        print(value.is_none_or(lambda x: x > 3))
671        # False
672
673        value: Option[int] = Some(None)
674        print(value.is_none_or(lambda x: x > 3))
675        # True
676        ```
677        """
678        match self._value:
679            case None:
680                return True
681            case x:
682                return f(x)

Returns True if the contained value is None or the predicate returns True, otherwise returns False.

Example
value = Some(5)
print(value.is_none_or(lambda x: x > 3))
# False

value: Option[int] = Some(None)
print(value.is_none_or(lambda x: x > 3))
# True
Option = 'Some[T]'
NOTHING = None
@rustc_diagnostic_item('Iter')
@typing.final
@diagnostic
class Iter(typing.Generic[~Item], sain.Iterator[~Item]):
 937@rustc_diagnostic_item("Iter")
 938@typing.final
 939@diagnostic
 940class Iter(typing.Generic[Item], Iterator[Item]):
 941    """a lazy iterator that has its items ready in-memory.
 942
 943    This is similar to Rust `std::slice::Iter<T>` item which iterables can build
 944    from this via `.iter()` method.
 945
 946    Example
 947    -------
 948    ```py
 949    iterator = Iter([1, 2, 3])
 950
 951    # Limit the results to 2.
 952    for item in iterator.take(2):
 953        print(item)
 954    # 1
 955    # 2
 956
 957    # Filter the results.
 958    for item in iterator.filter(lambda item: item > 1):
 959        print(item)
 960    # 2
 961    # 3
 962    # 3
 963
 964    # Indexing is supported.
 965    print(iterator[0])
 966    # 1
 967    ```
 968
 969    Parameters
 970    ----------
 971    items: `Iterable[Item]`
 972        The items to iterate over. This can be anything that implements `__iter__` and `__next__`.
 973    """
 974
 975    __slots__ = ("_it",)
 976
 977    def __init__(self, iterable: collections.Iterable[Item]) -> None:
 978        self._it = iter(iterable)
 979
 980    def clone(self) -> Iter[Item]:
 981        """Return a copy of this iterator.
 982
 983        ```py
 984        it = Iterator([1, 2, 3])
 985
 986        for i in it.clone():
 987            ...
 988
 989        # The actual iterator hasn't been exhausted.
 990        assert it.count() == 3
 991        ```
 992        """
 993        return Iter(copy.copy(self._it))
 994
 995    def __next__(self) -> Item:
 996        return next(self._it)
 997
 998    def __getitem__(self, index: int) -> Option[Item]:
 999        try:
1000            return self.skip(index).first()
1001        except IndexError:
1002            unreachable()
1003
1004    def __contains__(self, item: Item) -> bool:
1005        return item in self._it

a lazy iterator that has its items ready in-memory.

This is similar to Rust std::slice::Iter<T> item which iterables can build from this via sain.iter method.

Example
iterator = Iter([1, 2, 3])

# Limit the results to 2.
for item in iterator.take(2):
    print(item)
# 1
# 2

# Filter the results.
for item in iterator.filter(lambda item: item > 1):
    print(item)
# 2
# 3
# 3

# Indexing is supported.
print(iterator[0])
# 1
Parameters
  • items (Iterable[Item]): The items to iterate over. This can be anything that implements __iter__ and __next__.
  • # Implementations
  • **This class implements Iter:
Iter(iterable: Iterable[~Item])
977    def __init__(self, iterable: collections.Iterable[Item]) -> None:
978        self._it = iter(iterable)
def clone(self) -> Iter[~Item]:
980    def clone(self) -> Iter[Item]:
981        """Return a copy of this iterator.
982
983        ```py
984        it = Iterator([1, 2, 3])
985
986        for i in it.clone():
987            ...
988
989        # The actual iterator hasn't been exhausted.
990        assert it.count() == 3
991        ```
992        """
993        return Iter(copy.copy(self._it))

Return a copy of this iterator.

it = Iterator([1, 2, 3])

for i in it.clone():
    ...

# The actual iterator hasn't been exhausted.
assert it.count() == 3
class Iterator(typing.Generic[~Item], abc.ABC, sain.Default[ForwardRef('Empty[Item]')]):
120class Iterator(
121    typing.Generic[Item],
122    abc.ABC,
123    _default.Default["Empty[Item]"],
124):
125    """An abstract interface for dealing with iterators.
126
127    This is exactly the same trait as `core::iter::Iterator` trait from Rust.
128
129    This is the main interface that any type can implement by basically inheriting from it.
130    The method `__next__` is the only method that needs to be implemented, You get all the other methods for free.
131
132    If you want to use a ready iterator for general purposes, Use `Iter`. This interface is only for implementors
133    and type hints.
134
135    Example
136    -------
137    ```py
138    @dataclass
139    class Counter(Iterator[int]):
140        start: int = 0
141        stop: int | None = None
142
143        # implement the required method.
144        def __next__(self) -> int:
145            result = self.start
146            self.start += 1
147
148            if self.stop is not None and result >= self.stop:
149                raise StopIteration
150
151            return result
152
153    counter = Counter(start=0, stop=10)
154    for i in counter.map(lambda x: x * 2): # multiply each number
155        ...
156    ```
157    """
158
159    @abc.abstractmethod
160    def __next__(self) -> Item:
161        raise NotImplementedError
162
163    ###################
164    # const functions #
165    ###################
166
167    @staticmethod
168    @typing.final
169    def default() -> Empty[Item]:
170        """Return the default iterator for this type. It returns an empty iterator.
171
172        Example
173        -------
174        ```py
175        it: Iterator[int] = Iter.default()
176        assert t.next().is_none()
177        ```
178        """
179        return Empty()
180
181    @typing.overload
182    def collect(self) -> collections.Sequence[Item]: ...
183
184    @typing.overload
185    def collect(
186        self, *, cast: collections.Callable[[Item], OtherItem]
187    ) -> collections.Sequence[OtherItem]: ...
188
189    @typing.final
190    def collect(
191        self, *, cast: collections.Callable[[Item], OtherItem] | None = None
192    ) -> collections.Sequence[Item] | collections.Sequence[OtherItem]:
193        """Collects all items in the iterator into an immutable sequence.
194
195        Example
196        -------
197        ```py
198        iterator = Iter(range(3))
199        iterator.collect()
200        # (0, 1, 2, 3)
201        iterator.collect(cast=str) # Map each element and collect it.
202        # ('0', '1', '2', '3')
203        ```
204
205        Parameters
206        ----------
207        cast: `T | None`
208            An optional type to cast the items into.
209            If not provided the items will be returned as it's original type.
210        """
211        if cast is not None:
212            return tuple(cast(i) for i in self)
213
214        return tuple(_ for _ in self)
215
216    @typing.final
217    def collect_into(self, collection: Collector[Item]) -> None:
218        """Consume this iterator, extending all items in the iterator into a mutable `collection`.
219
220        Example
221        -------
222        ```py
223        iterator = Iter([1, 1, 2, 3, 4, 2, 6])
224        uniques = set()
225        iterator.collect_into(uniques)
226        # assert uniques == {1, 2, 3, 4, 6}
227        ```
228
229        Parameters
230        ----------
231        collection: `MutableSequence[T]` | `set[T]`
232            The collection to extend the items in this iterator with.
233        """
234        if isinstance(collection, collections.MutableSequence):
235            collection.extend(_ for _ in self)
236        elif isinstance(collection, collections.MutableSet):
237            collection.update(_ for _ in self)
238        else:
239            for idx, item in enumerate(self):
240                collection[idx] = item
241
242    @typing.final
243    def to_vec(self) -> _vec.Vec[Item]:
244        """Convert this iterator into `Vec[T]`.
245
246        Example
247        -------
248        ```py
249        it = sain.iter.once(0)
250        vc = it.to_vec()
251
252        assert to_vec == [0]
253        ```
254        """
255        return _vec.Vec(_ for _ in self)
256
257    @typing.final
258    def sink(self) -> None:
259        """Consume all elements from this iterator, flushing it into the sink.
260
261        Example
262        -------
263        ```py
264        it = Iter((1, 2, 3))
265        it.sink()
266        assert it.next().is_none()
267        ```
268        """
269        for _ in self:
270            pass
271
272    @typing.final
273    def raw_parts(self) -> collections.Generator[Item, None, None]:
274        """Decompose all elements from this iterator, yielding it one by one
275        as a normal generator.
276
277        This mainly used for objects that needs to satisfy its exact type.
278
279        ```py
280        it = Iter("cba")
281        sort = sorted(it.raw_parts())
282
283        assert it.count() == 0
284        assert sort == ["a", "b", "c"]
285        ```
286        """
287        for item in self:
288            yield item
289
290    ##################
291    # default impl's #
292    ##################
293
294    def next(self) -> Option[Item]:
295        """Advance the iterator, Returning the next item, `Some(None)` if all items yielded.
296
297        Example
298        -------
299        ```py
300        iterator = Iter(["1", "2"])
301        assert iterator.next() == Some("1")
302        assert iterator.next() == Some("2")
303        assert iterator.next().is_none()
304        ```
305        """
306        try:
307            return _option.Some(self.__next__())
308        except StopIteration:
309            # ! SAFETY: No more items in the iterator.
310            return _option.NOTHING  # pyright: ignore
311
312    def cloned(self) -> Cloned[Item]:
313        """Creates an iterator which shallow copies its elements by reference.
314
315        If you need a copy of the actual iterator and not the elements.
316        use `Iter.clone()`
317
318        .. note::
319            This method calls [`copy.copy()`](https://docs.python.org/3/library/copy.html)
320            on each item that is being yielded.
321
322        Example
323        -------
324        ```py
325        @dataclass
326        class User:
327            users_ids: list[int] = []
328
329        # An iterator which elements points to the same user.
330        user = User()
331        it = Iter((user, user))
332
333        for u in it.cloned():
334            u.user_ids.append(1)
335
336        # We iterated over the same user pointer twice and appended "1"
337        # since `copy` returns a shallow copy of nested structures.
338        assert len(user.user_ids) == 2
339        ```
340        """
341        return Cloned(self)
342
343    def copied(self) -> Copied[Item]:
344        """Creates an iterator which copies all of its elements by value.
345
346        If you only need a copy of the item reference, Use `.cloned()` instead.
347
348        .. note::
349            This method simply calls [`copy.deepcopy()`](https://docs.python.org/3/library/copy.html)
350            on each item that is being yielded.
351
352        Example
353        -------
354        ```py
355        @dataclass
356        class User:
357            users_ids: list[int] = []
358
359        # An iterator which elements points to the same user.
360        user = User()
361        it = Iter((user, user))
362
363        for u in it.copied():
364            # A new list is created for each item.
365            u.user_ids.append(1)
366
367        # The actual list is untouched since we consumed a deep copy of it.
368        assert len(user.user_ids) == 0
369        ```
370        """
371        return Copied(self)
372
373    def map(self, fn: collections.Callable[[Item], OtherItem]) -> Map[Item, OtherItem]:
374        """Maps each item in the iterator to another type.
375
376        Example
377        -------
378        ```py
379        iterator = Iter(["1", "2", "3"]).map(int)
380
381        for item in iterator:
382            assert isinstance(item, int)
383        ```
384
385        Parameters
386        ----------
387        predicate: `Callable[[Item], OtherItem]`
388            The function to map each item in the iterator to the other type.
389        """
390        return Map(self, fn)
391
392    def filter(self, predicate: collections.Callable[[Item], bool]) -> Filter[Item]:
393        """Filters the iterator to only yield items that match the predicate.
394
395        Example
396        -------
397        ```py
398        places = Iter(['London', 'Paris', 'Los Angeles'])
399        for place in places.filter(lambda place: place.startswith('L')):
400            print(place)
401
402        # London
403        # Los Angeles
404        ```
405        """
406        return Filter(self, predicate)
407
408    def take(self, count: int) -> Take[Item]:
409        """Take the first number of items until the number of items
410        are yielded or the end of the iterator is exhausted.
411
412        Example
413        -------
414        ```py
415        iterator = Iter(['c', 'x', 'y'])
416
417        for x in iterator.take(2):
418            assert x in ('c', 'x')
419
420        # <Iter(['c', 'x'])>
421        ```
422        """
423        return Take(self, count)
424
425    def skip(self, count: int) -> Skip[Item]:
426        """Skips the first number of items in the iterator.
427
428        Example
429        -------
430        ```py
431        iterator = Iter((1, 2, 3, 4))
432        for i in iterator.skip(2):
433            print(i)
434
435        # 3
436        # 4
437        ```
438        """
439        return Skip(self, count)
440
441    def enumerate(self, *, start: int = 0) -> Enumerate[Item]:
442        """Create a new iterator that yields a tuple of the index and item.
443
444        Example
445        -------
446        ```py
447        iterator = Iter([1, 2, 3])
448        for index, item in iterator.enumerate():
449            print(index, item)
450
451        # 0 1
452        # 1 2
453        # 2 3
454        ```
455        """
456        return Enumerate(self, start)
457
458    def take_while(self, f: collections.Callable[[Item], bool]) -> TakeWhile[Item]:
459        """yields items from the iterator while predicate returns `True`.
460
461        The rest of the items are discarded as soon as the predicate returns `False`
462
463        Example
464        -------
465        ```py
466        iterator = Iter(['a', 'ab', 'xd', 'ba'])
467        for x in iterator.take_while(lambda x: 'a' in x):
468            print(x)
469
470        # a
471        # ab
472        ```
473
474        Parameters
475        ----------
476        predicate: `collections.Callable[[Item], bool]`
477            The function to predicate each item in the iterator.
478        """
479        return TakeWhile(self, f)
480
481    def drop_while(self, f: collections.Callable[[Item], bool]) -> DropWhile[Item]:
482        """Yields items from the iterator while predicate returns `False`.
483
484        Example
485        -------
486        ```py
487        iterator = Iter(['a', 'ab', 'xd', 'ba'])
488        for x in iterator.drop_while(lambda x: 'a' in x):
489            print(x)
490
491        # xd
492        # ba
493        ```
494
495        Parameters
496        ----------
497        predicate: `collections.Callable[[Item], bool]`
498            The function to predicate each item in the iterator.
499        """
500        return DropWhile(self, f)
501
502    def chunks(self, chunk_size: int, /) -> Chunks[Item]:
503        """Returns an iterator over `chunk_size` elements of the iterator at a time,
504        starting at the beginning of the iterator.
505
506        Example
507        -------
508        ```py
509        iter = Iter(['a', 'b', 'c', 'd', 'e'])
510        chunks = iter.chunks()
511        assert chunks.next().unwrap() == ['a', 'b']
512        assert chunks.next().unwrap() == ['c', 'd']
513        assert chunks.next().unwrap() == ['e']
514        assert chunks.next().is_none()
515        ```
516        """
517        return Chunks(self, chunk_size)
518
519    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
520        """Return `True` if all items in the iterator match the predicate.
521
522        Example
523        -------
524        ```py
525        iterator = Iter([1, 2, 3])
526        while iterator.all(lambda item: isinstance(item, int)):
527            print("Still all integers")
528            continue
529            # Still all integers
530        ```
531
532        Parameters
533        ----------
534        predicate: `collections.Callable[[Item], bool]`
535            The function to test each item in the iterator.
536        """
537        return all(predicate(item) for item in self)
538
539    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
540        """`True` if any items in the iterator match the predicate.
541
542        Example
543        -------
544        ```py
545        iterator = Iter([1, 2, 3])
546        if iterator.any(lambda item: isinstance(item, int)):
547            print("At least one item is an int.")
548        # At least one item is an int.
549        ```
550
551        Parameters
552        ----------
553        predicate: `collections.Callable[[Item], bool]`
554            The function to test each item in the iterator.
555        """
556        return any(predicate(item) for item in self)
557
558    def zip(
559        self, other: collections.Iterable[OtherItem]
560    ) -> Iter[tuple[Item, OtherItem]]:
561        """Zips the iterator with another iterable.
562
563        Example
564        -------
565        ```py
566        iterator = Iter([1, 2, 3])
567        for item, other_item in iterator.zip([4, 5, 6]):
568            assert item == other_item
569        <Iter([(1, 4), (2, 5), (3, 6)])>
570        ```
571
572        Parameters
573        ----------
574        other: `Iter[OtherItem]`
575            The iterable to zip with.
576
577        Returns
578        -------
579        `Iter[tuple[Item, OtherItem]]`
580            The zipped iterator.
581
582        """
583        return Iter(zip(self.raw_parts(), other))
584
585    def sort(
586        self,
587        *,
588        key: collections.Callable[[Item], _typeshed.SupportsRichComparison],
589        reverse: bool = False,
590    ) -> Iter[Item]:
591        """Sorts the iterator.
592
593        Example
594        -------
595        ```py
596        iterator = Iter([3, 1, 6, 7])
597        for item in iterator.sort(key=lambda item: item < 3):
598            print(item)
599        # 1
600        # 3
601        # 6
602        # 7
603        ```
604
605        Parameters
606        ----------
607        key: `collections.Callable[[Item], Any]`
608            The function to sort by.
609        reverse: `bool`
610            Whether to reverse the sort.
611
612        """
613        return Iter(sorted(self.raw_parts(), key=key, reverse=reverse))
614
615    def reversed(self) -> Iter[Item]:
616        """Returns a new iterator that yields the items in the iterator in reverse order.
617
618        Example
619        -------
620        ```py
621        iterator = Iter([3, 1, 6, 7])
622        for item in iterator.reversed():
623            print(item)
624        # 7
625        # 6
626        # 1
627        # 3
628        ```
629        """
630        # NOTE: In order to reverse the iterator we need to
631        # first collect it into some collection.
632        return Iter(reversed(self.collect()))
633
634    def union(self, other: collections.Iterable[Item]) -> Iter[Item]:
635        """Returns a new iterator that yields all items from both iterators.
636
637        Example
638        -------
639        ```py
640        iterator = Iter([1, 2, 3])
641        other = [4, 5, 6]
642
643        for item in iterator.union(other):
644            print(item)
645        # 1
646        # 2
647        # 3
648        # 4
649        # 5
650        # 6
651        ```
652
653        Parameters
654        ----------
655        other: `Iter[Item]`
656            The iterable to union with.
657        """
658        return Iter(itertools.chain(self.raw_parts(), other))
659
660    def first(self) -> Option[Item]:
661        """Returns the first item in the iterator.
662
663        Example
664        -------
665        ```py
666        iterator = Iter([3, 1, 6, 7])
667        iterator.first().is_some_and(lambda x: x == 3)
668        ```
669        """
670        return self.take(1).next()
671
672    def last(self) -> Option[Item]:
673        """Returns the last item in the iterator.
674
675        Example
676        -------
677        ```py
678        iterator = Iter([3, 1, 6, 7])
679        iterator.last().is_some_and(lambda x: x == 7)
680        ```
681        """
682        return self.reversed().first()
683
684    def count(self) -> int:
685        """Return the count of elements in memory this iterator has.
686
687        Example
688        -------
689        ```py
690        it = Iter(range(3))
691        assert it.count() == 3
692        ```
693        """
694        count = 0
695        for _ in self:
696            count += 1
697
698        return count
699
700    def find(self, predicate: collections.Callable[[Item], bool]) -> Option[Item]:
701        """Searches for an element of an iterator that satisfies a predicate.
702
703        If you want the position of the element, use `Iterator.position` instead.
704
705        `find()` takes a lambda that returns true or false. It applies this closure to each element of the iterator,
706        and if any of them return true, then find() returns `Some(element)`. If they all return false, it returns None.
707
708        Example
709        -------
710        ```py
711        it = Iter(range(10))
712        item = it.find(lambda num: num > 5)
713        print(item) # 6
714        ```
715        """
716        for item in self:
717            if predicate(item):
718                return _option.Some(item)
719
720        # no more items
721        return _option.NOTHING  # pyright: ignore
722
723    def position(self, predicate: collections.Callable[[Item], bool]) -> Option[int]:
724        """Searches for the position of an element in the iterator that satisfies a predicate.
725
726        If you want the object itself, use `Iterator.find` instead.
727
728        `position()` takes a lambda that returns true or false. It applies this closure to each element of the iterator,
729        and if any of them return true, then position() returns `Some(position_of_element)`. If they all return false, it returns None.
730
731        Example
732        -------
733        ```py
734        it = Iter(range(10))
735        position = it.find(lambda num: num > 5)
736        assert position.unwrap() == 6
737        ```
738        """
739        for position, value in self.enumerate():
740            if predicate(value):
741                return _option.Some(position)
742
743        # no more items
744        return _option.NOTHING  # pyright: ignore
745
746    def fold(
747        self, init: OtherItem, f: collections.Callable[[OtherItem, Item], OtherItem]
748    ) -> OtherItem:
749        """Folds every element into an accumulator by applying an operation, returning the final result.
750
751        fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element.
752        The closure returns the value that the accumulator should have for the next iteration.
753
754        The initial value is the value the accumulator will have on the first call.
755
756        After applying this closure to every element of the iterator, fold() returns the accumulator.
757
758        This operation is sometimes called ‘reduce’ or ‘inject’.
759
760        Example
761        -------
762        ```py
763        a = Iter([1, 2, 3, 4])
764        sum = a.fold(0, lambda acc, elem: acc + elem)
765        assert sum == 10
766        ```
767        """
768        accum = init
769        while True:
770            try:
771                x = self.__next__()
772                accum = f(accum, x)
773            except StopIteration:
774                break
775
776        return accum
777
778    def sum(self: Sum) -> int:
779        """Sums an iterator of a possible type that can be converted to an integer.
780
781        Example
782        -------
783        ```py
784        numbers: Iterator[str] = Iter(["1", "2", "3"])
785        total = numbers.sum()
786        assert total == 6
787        ```
788        """
789        return sum(int(_) for _ in self)
790
791    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
792        """Calls `func` on each item in the iterator.
793
794        Example
795        -------
796        ```py
797        iterator = Iter([1, 2, 3])
798        iterator.for_each(lambda item: print(item))
799        # 1
800        # 2
801        # 3
802        ```
803
804        Parameters
805        ----------
806        func: `collections.Callable[[Item], typing.Any]`
807            The function to call on each item in the iterator.
808        """
809        for item in self:
810            func(item)
811
812    async def async_for_each(
813        self,
814        func: collections.Callable[
815            [Item], collections.Coroutine[None, typing.Any, OtherItem]
816        ],
817    ) -> _result.Result[collections.Sequence[OtherItem], futures.JoinError]:
818        """Calls the async function on each item in the iterator concurrently.
819
820        Example
821        -------
822        ```py
823        async def create_user(username: str) -> None:
824            async with aiohttp.request("POST", f'.../{username}') as r:
825                return await r.json()
826
827        async def main():
828            users = sain.into_iter(["danny", "legalia"])
829            results = await users.async_for_each(lambda username: create_user(username))
830            for k, v in results.unwrap().items():
831                ...
832        ```
833
834        Parameters
835        ----------
836        func: `collections.Callable[[Item], Coroutine[None, Any, Any]]`
837            The async function to call on each item in the iterator.
838        """
839        return await futures.join(*(func(item) for item in self))
840
841    def __reversed__(self) -> Iter[Item]:
842        return self.reversed()
843
844    def __setitem__(self, _: None, __: None) -> typing.NoReturn:
845        raise NotImplementedError(
846            f"{type(self).__name__} doesn't support item assignment."
847        ) from None
848
849    def __repr__(self) -> str:
850        return "<Iterator>"
851
852    def __copy__(self) -> Cloned[Item]:
853        return self.cloned()
854
855    def __deepcopy__(
856        self, memo: collections.MutableMapping[int, typing.Any], /
857    ) -> Copied[Item]:
858        return self.copied()
859
860    def __len__(self) -> int:
861        return self.count()
862
863    def __iter__(self) -> Iterator[Item]:
864        return self

An abstract interface for dealing with iterators.

This is exactly the same trait as core::iter::Iterator trait from Rust.

This is the main interface that any type can implement by basically inheriting from it. The method __next__ is the only method that needs to be implemented, You get all the other methods for free.

If you want to use a ready iterator for general purposes, Use Iter. This interface is only for implementors and type hints.

Example
@dataclass
class Counter(Iterator[int]):
    start: int = 0
    stop: int | None = None

    # implement the required method.
    def __next__(self) -> int:
        result = self.start
        self.start += 1

        if self.stop is not None and result >= self.stop:
            raise StopIteration

        return result

counter = Counter(start=0, stop=10)
for i in counter.map(lambda x: x * 2): # multiply each number
    ...
@staticmethod
@typing.final
def default() -> sain.iter.Empty[~Item]:
167    @staticmethod
168    @typing.final
169    def default() -> Empty[Item]:
170        """Return the default iterator for this type. It returns an empty iterator.
171
172        Example
173        -------
174        ```py
175        it: Iterator[int] = Iter.default()
176        assert t.next().is_none()
177        ```
178        """
179        return Empty()

Return the default iterator for this type. It returns an empty iterator.

Example
it: Iterator[int] = Iter.default()
assert t.next().is_none()
@typing.final
def collect( self, *, cast: Callable[[~Item], ~OtherItem] | None = None) -> Sequence[~Item] | Sequence[~OtherItem]:
189    @typing.final
190    def collect(
191        self, *, cast: collections.Callable[[Item], OtherItem] | None = None
192    ) -> collections.Sequence[Item] | collections.Sequence[OtherItem]:
193        """Collects all items in the iterator into an immutable sequence.
194
195        Example
196        -------
197        ```py
198        iterator = Iter(range(3))
199        iterator.collect()
200        # (0, 1, 2, 3)
201        iterator.collect(cast=str) # Map each element and collect it.
202        # ('0', '1', '2', '3')
203        ```
204
205        Parameters
206        ----------
207        cast: `T | None`
208            An optional type to cast the items into.
209            If not provided the items will be returned as it's original type.
210        """
211        if cast is not None:
212            return tuple(cast(i) for i in self)
213
214        return tuple(_ for _ in self)

Collects all items in the iterator into an immutable sequence.

Example
iterator = Iter(range(3))
iterator.collect()
# (0, 1, 2, 3)
iterator.collect(cast=str) # Map each element and collect it.
# ('0', '1', '2', '3')
Parameters
  • cast (T | None): An optional type to cast the items into. If not provided the items will be returned as it's original type.
@typing.final
def collect_into(self, collection: 'Collector[Item]') -> None:
216    @typing.final
217    def collect_into(self, collection: Collector[Item]) -> None:
218        """Consume this iterator, extending all items in the iterator into a mutable `collection`.
219
220        Example
221        -------
222        ```py
223        iterator = Iter([1, 1, 2, 3, 4, 2, 6])
224        uniques = set()
225        iterator.collect_into(uniques)
226        # assert uniques == {1, 2, 3, 4, 6}
227        ```
228
229        Parameters
230        ----------
231        collection: `MutableSequence[T]` | `set[T]`
232            The collection to extend the items in this iterator with.
233        """
234        if isinstance(collection, collections.MutableSequence):
235            collection.extend(_ for _ in self)
236        elif isinstance(collection, collections.MutableSet):
237            collection.update(_ for _ in self)
238        else:
239            for idx, item in enumerate(self):
240                collection[idx] = item

Consume this iterator, extending all items in the iterator into a mutable collection.

Example
iterator = Iter([1, 1, 2, 3, 4, 2, 6])
uniques = set()
iterator.collect_into(uniques)
# assert uniques == {1, 2, 3, 4, 6}
Parameters
  • collection (MutableSequence[T] | set[T]): The collection to extend the items in this iterator with.
@typing.final
def to_vec(self) -> Vec[~Item]:
242    @typing.final
243    def to_vec(self) -> _vec.Vec[Item]:
244        """Convert this iterator into `Vec[T]`.
245
246        Example
247        -------
248        ```py
249        it = sain.iter.once(0)
250        vc = it.to_vec()
251
252        assert to_vec == [0]
253        ```
254        """
255        return _vec.Vec(_ for _ in self)

Convert this iterator into Vec[T].

Example
it = sain.iter.once(0)
vc = it.to_vec()

assert to_vec == [0]
@typing.final
def sink(self) -> None:
257    @typing.final
258    def sink(self) -> None:
259        """Consume all elements from this iterator, flushing it into the sink.
260
261        Example
262        -------
263        ```py
264        it = Iter((1, 2, 3))
265        it.sink()
266        assert it.next().is_none()
267        ```
268        """
269        for _ in self:
270            pass

Consume all elements from this iterator, flushing it into the sink.

Example
it = Iter((1, 2, 3))
it.sink()
assert it.next().is_none()
@typing.final
def raw_parts(self) -> Generator[~Item, None, None]:
272    @typing.final
273    def raw_parts(self) -> collections.Generator[Item, None, None]:
274        """Decompose all elements from this iterator, yielding it one by one
275        as a normal generator.
276
277        This mainly used for objects that needs to satisfy its exact type.
278
279        ```py
280        it = Iter("cba")
281        sort = sorted(it.raw_parts())
282
283        assert it.count() == 0
284        assert sort == ["a", "b", "c"]
285        ```
286        """
287        for item in self:
288            yield item

Decompose all elements from this iterator, yielding it one by one as a normal generator.

This mainly used for objects that needs to satisfy its exact type.

it = Iter("cba")
sort = sorted(it.raw_parts())

assert it.count() == 0
assert sort == ["a", "b", "c"]
def next(self) -> 'Option[Item]':
294    def next(self) -> Option[Item]:
295        """Advance the iterator, Returning the next item, `Some(None)` if all items yielded.
296
297        Example
298        -------
299        ```py
300        iterator = Iter(["1", "2"])
301        assert iterator.next() == Some("1")
302        assert iterator.next() == Some("2")
303        assert iterator.next().is_none()
304        ```
305        """
306        try:
307            return _option.Some(self.__next__())
308        except StopIteration:
309            # ! SAFETY: No more items in the iterator.
310            return _option.NOTHING  # pyright: ignore

Advance the iterator, Returning the next item, Some(None) if all items yielded.

Example
iterator = Iter(["1", "2"])
assert iterator.next() == Some("1")
assert iterator.next() == Some("2")
assert iterator.next().is_none()
def cloned(self) -> sain.iter.Cloned[~Item]:
312    def cloned(self) -> Cloned[Item]:
313        """Creates an iterator which shallow copies its elements by reference.
314
315        If you need a copy of the actual iterator and not the elements.
316        use `Iter.clone()`
317
318        .. note::
319            This method calls [`copy.copy()`](https://docs.python.org/3/library/copy.html)
320            on each item that is being yielded.
321
322        Example
323        -------
324        ```py
325        @dataclass
326        class User:
327            users_ids: list[int] = []
328
329        # An iterator which elements points to the same user.
330        user = User()
331        it = Iter((user, user))
332
333        for u in it.cloned():
334            u.user_ids.append(1)
335
336        # We iterated over the same user pointer twice and appended "1"
337        # since `copy` returns a shallow copy of nested structures.
338        assert len(user.user_ids) == 2
339        ```
340        """
341        return Cloned(self)

Creates an iterator which shallow copies its elements by reference.

If you need a copy of the actual iterator and not the elements. use Iter.clone()

This method calls copy.copy() on each item that is being yielded.

Example
@dataclass
class User:
    users_ids: list[int] = []

# An iterator which elements points to the same user.
user = User()
it = Iter((user, user))

for u in it.cloned():
    u.user_ids.append(1)

# We iterated over the same user pointer twice and appended "1"
# since `copy` returns a shallow copy of nested structures.
assert len(user.user_ids) == 2
def copied(self) -> sain.iter.Copied[~Item]:
343    def copied(self) -> Copied[Item]:
344        """Creates an iterator which copies all of its elements by value.
345
346        If you only need a copy of the item reference, Use `.cloned()` instead.
347
348        .. note::
349            This method simply calls [`copy.deepcopy()`](https://docs.python.org/3/library/copy.html)
350            on each item that is being yielded.
351
352        Example
353        -------
354        ```py
355        @dataclass
356        class User:
357            users_ids: list[int] = []
358
359        # An iterator which elements points to the same user.
360        user = User()
361        it = Iter((user, user))
362
363        for u in it.copied():
364            # A new list is created for each item.
365            u.user_ids.append(1)
366
367        # The actual list is untouched since we consumed a deep copy of it.
368        assert len(user.user_ids) == 0
369        ```
370        """
371        return Copied(self)

Creates an iterator which copies all of its elements by value.

If you only need a copy of the item reference, Use .cloned() instead.

This method simply calls copy.deepcopy() on each item that is being yielded.

Example
@dataclass
class User:
    users_ids: list[int] = []

# An iterator which elements points to the same user.
user = User()
it = Iter((user, user))

for u in it.copied():
    # A new list is created for each item.
    u.user_ids.append(1)

# The actual list is untouched since we consumed a deep copy of it.
assert len(user.user_ids) == 0
def map( self, fn: Callable[[~Item], ~OtherItem]) -> sain.iter.Map[~Item, ~OtherItem]:
373    def map(self, fn: collections.Callable[[Item], OtherItem]) -> Map[Item, OtherItem]:
374        """Maps each item in the iterator to another type.
375
376        Example
377        -------
378        ```py
379        iterator = Iter(["1", "2", "3"]).map(int)
380
381        for item in iterator:
382            assert isinstance(item, int)
383        ```
384
385        Parameters
386        ----------
387        predicate: `Callable[[Item], OtherItem]`
388            The function to map each item in the iterator to the other type.
389        """
390        return Map(self, fn)

Maps each item in the iterator to another type.

Example
iterator = Iter(["1", "2", "3"]).map(int)

for item in iterator:
    assert isinstance(item, int)
Parameters
  • predicate (Callable[[Item], OtherItem]): The function to map each item in the iterator to the other type.
def filter(self, predicate: Callable[[~Item], bool]) -> sain.iter.Filter[~Item]:
392    def filter(self, predicate: collections.Callable[[Item], bool]) -> Filter[Item]:
393        """Filters the iterator to only yield items that match the predicate.
394
395        Example
396        -------
397        ```py
398        places = Iter(['London', 'Paris', 'Los Angeles'])
399        for place in places.filter(lambda place: place.startswith('L')):
400            print(place)
401
402        # London
403        # Los Angeles
404        ```
405        """
406        return Filter(self, predicate)

Filters the iterator to only yield items that match the predicate.

Example
places = Iter(['London', 'Paris', 'Los Angeles'])
for place in places.filter(lambda place: place.startswith('L')):
    print(place)

# London
# Los Angeles
def take(self, count: int) -> sain.iter.Take[~Item]:
408    def take(self, count: int) -> Take[Item]:
409        """Take the first number of items until the number of items
410        are yielded or the end of the iterator is exhausted.
411
412        Example
413        -------
414        ```py
415        iterator = Iter(['c', 'x', 'y'])
416
417        for x in iterator.take(2):
418            assert x in ('c', 'x')
419
420        # <Iter(['c', 'x'])>
421        ```
422        """
423        return Take(self, count)

Take the first number of items until the number of items are yielded or the end of the iterator is exhausted.

Example
iterator = Iter(['c', 'x', 'y'])

for x in iterator.take(2):
    assert x in ('c', 'x')

# <Iter(['c', 'x'])>
def skip(self, count: int) -> sain.iter.Skip[~Item]:
425    def skip(self, count: int) -> Skip[Item]:
426        """Skips the first number of items in the iterator.
427
428        Example
429        -------
430        ```py
431        iterator = Iter((1, 2, 3, 4))
432        for i in iterator.skip(2):
433            print(i)
434
435        # 3
436        # 4
437        ```
438        """
439        return Skip(self, count)

Skips the first number of items in the iterator.

Example
iterator = Iter((1, 2, 3, 4))
for i in iterator.skip(2):
    print(i)

# 3
# 4
def enumerate(self, *, start: int = 0) -> sain.iter.Enumerate[~Item]:
441    def enumerate(self, *, start: int = 0) -> Enumerate[Item]:
442        """Create a new iterator that yields a tuple of the index and item.
443
444        Example
445        -------
446        ```py
447        iterator = Iter([1, 2, 3])
448        for index, item in iterator.enumerate():
449            print(index, item)
450
451        # 0 1
452        # 1 2
453        # 2 3
454        ```
455        """
456        return Enumerate(self, start)

Create a new iterator that yields a tuple of the index and item.

Example
iterator = Iter([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)

# 0 1
# 1 2
# 2 3
def take_while(self, f: Callable[[~Item], bool]) -> sain.iter.TakeWhile[~Item]:
458    def take_while(self, f: collections.Callable[[Item], bool]) -> TakeWhile[Item]:
459        """yields items from the iterator while predicate returns `True`.
460
461        The rest of the items are discarded as soon as the predicate returns `False`
462
463        Example
464        -------
465        ```py
466        iterator = Iter(['a', 'ab', 'xd', 'ba'])
467        for x in iterator.take_while(lambda x: 'a' in x):
468            print(x)
469
470        # a
471        # ab
472        ```
473
474        Parameters
475        ----------
476        predicate: `collections.Callable[[Item], bool]`
477            The function to predicate each item in the iterator.
478        """
479        return TakeWhile(self, f)

yields items from the iterator while predicate returns True.

The rest of the items are discarded as soon as the predicate returns False

Example
iterator = Iter(['a', 'ab', 'xd', 'ba'])
for x in iterator.take_while(lambda x: 'a' in x):
    print(x)

# a
# ab
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
def drop_while(self, f: Callable[[~Item], bool]) -> sain.iter.DropWhile[~Item]:
481    def drop_while(self, f: collections.Callable[[Item], bool]) -> DropWhile[Item]:
482        """Yields items from the iterator while predicate returns `False`.
483
484        Example
485        -------
486        ```py
487        iterator = Iter(['a', 'ab', 'xd', 'ba'])
488        for x in iterator.drop_while(lambda x: 'a' in x):
489            print(x)
490
491        # xd
492        # ba
493        ```
494
495        Parameters
496        ----------
497        predicate: `collections.Callable[[Item], bool]`
498            The function to predicate each item in the iterator.
499        """
500        return DropWhile(self, f)

Yields items from the iterator while predicate returns False.

Example
iterator = Iter(['a', 'ab', 'xd', 'ba'])
for x in iterator.drop_while(lambda x: 'a' in x):
    print(x)

# xd
# ba
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
def chunks(self, chunk_size: int, /) -> sain.iter.Chunks[~Item]:
502    def chunks(self, chunk_size: int, /) -> Chunks[Item]:
503        """Returns an iterator over `chunk_size` elements of the iterator at a time,
504        starting at the beginning of the iterator.
505
506        Example
507        -------
508        ```py
509        iter = Iter(['a', 'b', 'c', 'd', 'e'])
510        chunks = iter.chunks()
511        assert chunks.next().unwrap() == ['a', 'b']
512        assert chunks.next().unwrap() == ['c', 'd']
513        assert chunks.next().unwrap() == ['e']
514        assert chunks.next().is_none()
515        ```
516        """
517        return Chunks(self, chunk_size)

Returns an iterator over chunk_size elements of the iterator at a time, starting at the beginning of the iterator.

Example
iter = Iter(['a', 'b', 'c', 'd', 'e'])
chunks = iter.chunks()
assert chunks.next().unwrap() == ['a', 'b']
assert chunks.next().unwrap() == ['c', 'd']
assert chunks.next().unwrap() == ['e']
assert chunks.next().is_none()
def all(self, predicate: Callable[[~Item], bool]) -> bool:
519    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
520        """Return `True` if all items in the iterator match the predicate.
521
522        Example
523        -------
524        ```py
525        iterator = Iter([1, 2, 3])
526        while iterator.all(lambda item: isinstance(item, int)):
527            print("Still all integers")
528            continue
529            # Still all integers
530        ```
531
532        Parameters
533        ----------
534        predicate: `collections.Callable[[Item], bool]`
535            The function to test each item in the iterator.
536        """
537        return all(predicate(item) for item in self)

Return True if all items in the iterator match the predicate.

Example
iterator = Iter([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
    # Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
def any(self, predicate: Callable[[~Item], bool]) -> bool:
539    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
540        """`True` if any items in the iterator match the predicate.
541
542        Example
543        -------
544        ```py
545        iterator = Iter([1, 2, 3])
546        if iterator.any(lambda item: isinstance(item, int)):
547            print("At least one item is an int.")
548        # At least one item is an int.
549        ```
550
551        Parameters
552        ----------
553        predicate: `collections.Callable[[Item], bool]`
554            The function to test each item in the iterator.
555        """
556        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = Iter([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
def zip( self, other: Iterable[~OtherItem]) -> Iter[tuple[~Item, ~OtherItem]]:
558    def zip(
559        self, other: collections.Iterable[OtherItem]
560    ) -> Iter[tuple[Item, OtherItem]]:
561        """Zips the iterator with another iterable.
562
563        Example
564        -------
565        ```py
566        iterator = Iter([1, 2, 3])
567        for item, other_item in iterator.zip([4, 5, 6]):
568            assert item == other_item
569        <Iter([(1, 4), (2, 5), (3, 6)])>
570        ```
571
572        Parameters
573        ----------
574        other: `Iter[OtherItem]`
575            The iterable to zip with.
576
577        Returns
578        -------
579        `Iter[tuple[Item, OtherItem]]`
580            The zipped iterator.
581
582        """
583        return Iter(zip(self.raw_parts(), other))

Zips the iterator with another iterable.

Example
iterator = Iter([1, 2, 3])
for item, other_item in iterator.zip([4, 5, 6]):
    assert item == other_item
<Iter([(1, 4), (2, 5), (3, 6)])>
Parameters
  • other (Iter[OtherItem]): The iterable to zip with.
Returns
  • Iter[tuple[Item, OtherItem]]: The zipped iterator.
def sort( self, *, key: 'collections.Callable[[Item], _typeshed.SupportsRichComparison]', reverse: bool = False) -> Iter[~Item]:
585    def sort(
586        self,
587        *,
588        key: collections.Callable[[Item], _typeshed.SupportsRichComparison],
589        reverse: bool = False,
590    ) -> Iter[Item]:
591        """Sorts the iterator.
592
593        Example
594        -------
595        ```py
596        iterator = Iter([3, 1, 6, 7])
597        for item in iterator.sort(key=lambda item: item < 3):
598            print(item)
599        # 1
600        # 3
601        # 6
602        # 7
603        ```
604
605        Parameters
606        ----------
607        key: `collections.Callable[[Item], Any]`
608            The function to sort by.
609        reverse: `bool`
610            Whether to reverse the sort.
611
612        """
613        return Iter(sorted(self.raw_parts(), key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = Iter([3, 1, 6, 7])
for item in iterator.sort(key=lambda item: item < 3):
    print(item)
# 1
# 3
# 6
# 7
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
def reversed(self) -> Iter[~Item]:
615    def reversed(self) -> Iter[Item]:
616        """Returns a new iterator that yields the items in the iterator in reverse order.
617
618        Example
619        -------
620        ```py
621        iterator = Iter([3, 1, 6, 7])
622        for item in iterator.reversed():
623            print(item)
624        # 7
625        # 6
626        # 1
627        # 3
628        ```
629        """
630        # NOTE: In order to reverse the iterator we need to
631        # first collect it into some collection.
632        return Iter(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = Iter([3, 1, 6, 7])
for item in iterator.reversed():
    print(item)
# 7
# 6
# 1
# 3
def union(self, other: Iterable[~Item]) -> Iter[~Item]:
634    def union(self, other: collections.Iterable[Item]) -> Iter[Item]:
635        """Returns a new iterator that yields all items from both iterators.
636
637        Example
638        -------
639        ```py
640        iterator = Iter([1, 2, 3])
641        other = [4, 5, 6]
642
643        for item in iterator.union(other):
644            print(item)
645        # 1
646        # 2
647        # 3
648        # 4
649        # 5
650        # 6
651        ```
652
653        Parameters
654        ----------
655        other: `Iter[Item]`
656            The iterable to union with.
657        """
658        return Iter(itertools.chain(self.raw_parts(), other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = Iter([1, 2, 3])
other = [4, 5, 6]

for item in iterator.union(other):
    print(item)
# 1
# 2
# 3
# 4
# 5
# 6
Parameters
  • other (Iter[Item]): The iterable to union with.
def first(self) -> 'Option[Item]':
660    def first(self) -> Option[Item]:
661        """Returns the first item in the iterator.
662
663        Example
664        -------
665        ```py
666        iterator = Iter([3, 1, 6, 7])
667        iterator.first().is_some_and(lambda x: x == 3)
668        ```
669        """
670        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = Iter([3, 1, 6, 7])
iterator.first().is_some_and(lambda x: x == 3)
def last(self) -> 'Option[Item]':
672    def last(self) -> Option[Item]:
673        """Returns the last item in the iterator.
674
675        Example
676        -------
677        ```py
678        iterator = Iter([3, 1, 6, 7])
679        iterator.last().is_some_and(lambda x: x == 7)
680        ```
681        """
682        return self.reversed().first()

Returns the last item in the iterator.

Example
iterator = Iter([3, 1, 6, 7])
iterator.last().is_some_and(lambda x: x == 7)
def count(self) -> int:
684    def count(self) -> int:
685        """Return the count of elements in memory this iterator has.
686
687        Example
688        -------
689        ```py
690        it = Iter(range(3))
691        assert it.count() == 3
692        ```
693        """
694        count = 0
695        for _ in self:
696            count += 1
697
698        return count

Return the count of elements in memory this iterator has.

Example
it = Iter(range(3))
assert it.count() == 3
def find(self, predicate: Callable[[~Item], bool]) -> 'Option[Item]':
700    def find(self, predicate: collections.Callable[[Item], bool]) -> Option[Item]:
701        """Searches for an element of an iterator that satisfies a predicate.
702
703        If you want the position of the element, use `Iterator.position` instead.
704
705        `find()` takes a lambda that returns true or false. It applies this closure to each element of the iterator,
706        and if any of them return true, then find() returns `Some(element)`. If they all return false, it returns None.
707
708        Example
709        -------
710        ```py
711        it = Iter(range(10))
712        item = it.find(lambda num: num > 5)
713        print(item) # 6
714        ```
715        """
716        for item in self:
717            if predicate(item):
718                return _option.Some(item)
719
720        # no more items
721        return _option.NOTHING  # pyright: ignore

Searches for an element of an iterator that satisfies a predicate.

If you want the position of the element, use Iterator.position instead.

find() takes a lambda that returns true or false. It applies this closure to each element of the iterator, and if any of them return true, then find() returns Some(element). If they all return false, it returns None.

Example
it = Iter(range(10))
item = it.find(lambda num: num > 5)
print(item) # 6
def position(self, predicate: Callable[[~Item], bool]) -> 'Option[int]':
723    def position(self, predicate: collections.Callable[[Item], bool]) -> Option[int]:
724        """Searches for the position of an element in the iterator that satisfies a predicate.
725
726        If you want the object itself, use `Iterator.find` instead.
727
728        `position()` takes a lambda that returns true or false. It applies this closure to each element of the iterator,
729        and if any of them return true, then position() returns `Some(position_of_element)`. If they all return false, it returns None.
730
731        Example
732        -------
733        ```py
734        it = Iter(range(10))
735        position = it.find(lambda num: num > 5)
736        assert position.unwrap() == 6
737        ```
738        """
739        for position, value in self.enumerate():
740            if predicate(value):
741                return _option.Some(position)
742
743        # no more items
744        return _option.NOTHING  # pyright: ignore

Searches for the position of an element in the iterator that satisfies a predicate.

If you want the object itself, use Iterator.find instead.

position() takes a lambda that returns true or false. It applies this closure to each element of the iterator, and if any of them return true, then position() returns Some(position_of_element). If they all return false, it returns None.

Example
it = Iter(range(10))
position = it.find(lambda num: num > 5)
assert position.unwrap() == 6
def fold( self, init: ~OtherItem, f: Callable[[~OtherItem, ~Item], ~OtherItem]) -> ~OtherItem:
746    def fold(
747        self, init: OtherItem, f: collections.Callable[[OtherItem, Item], OtherItem]
748    ) -> OtherItem:
749        """Folds every element into an accumulator by applying an operation, returning the final result.
750
751        fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element.
752        The closure returns the value that the accumulator should have for the next iteration.
753
754        The initial value is the value the accumulator will have on the first call.
755
756        After applying this closure to every element of the iterator, fold() returns the accumulator.
757
758        This operation is sometimes called ‘reduce’ or ‘inject’.
759
760        Example
761        -------
762        ```py
763        a = Iter([1, 2, 3, 4])
764        sum = a.fold(0, lambda acc, elem: acc + elem)
765        assert sum == 10
766        ```
767        """
768        accum = init
769        while True:
770            try:
771                x = self.__next__()
772                accum = f(accum, x)
773            except StopIteration:
774                break
775
776        return accum

Folds every element into an accumulator by applying an operation, returning the final result.

fold() takes two arguments: an initial value, and a closure with two arguments: an ‘accumulator’, and an element. The closure returns the value that the accumulator should have for the next iteration.

The initial value is the value the accumulator will have on the first call.

After applying this closure to every element of the iterator, fold() returns the accumulator.

This operation is sometimes called ‘reduce’ or ‘inject’.

Example
a = Iter([1, 2, 3, 4])
sum = a.fold(0, lambda acc, elem: acc + elem)
assert sum == 10
def sum(self: 'Sum') -> int:
778    def sum(self: Sum) -> int:
779        """Sums an iterator of a possible type that can be converted to an integer.
780
781        Example
782        -------
783        ```py
784        numbers: Iterator[str] = Iter(["1", "2", "3"])
785        total = numbers.sum()
786        assert total == 6
787        ```
788        """
789        return sum(int(_) for _ in self)

Sums an iterator of a possible type that can be converted to an integer.

Example
numbers: Iterator[str] = Iter(["1", "2", "3"])
total = numbers.sum()
assert total == 6
def for_each(self, func: Callable[[~Item], typing.Any]) -> None:
791    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
792        """Calls `func` on each item in the iterator.
793
794        Example
795        -------
796        ```py
797        iterator = Iter([1, 2, 3])
798        iterator.for_each(lambda item: print(item))
799        # 1
800        # 2
801        # 3
802        ```
803
804        Parameters
805        ----------
806        func: `collections.Callable[[Item], typing.Any]`
807            The function to call on each item in the iterator.
808        """
809        for item in self:
810            func(item)

Calls func on each item in the iterator.

Example
iterator = Iter([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (collections.Callable[[Item], typing.Any]): The function to call on each item in the iterator.
async def async_for_each( self, func: Callable[[~Item], Coroutine[None, typing.Any, ~OtherItem]]) -> '_result.Result[collections.Sequence[OtherItem], futures.JoinError]':
812    async def async_for_each(
813        self,
814        func: collections.Callable[
815            [Item], collections.Coroutine[None, typing.Any, OtherItem]
816        ],
817    ) -> _result.Result[collections.Sequence[OtherItem], futures.JoinError]:
818        """Calls the async function on each item in the iterator concurrently.
819
820        Example
821        -------
822        ```py
823        async def create_user(username: str) -> None:
824            async with aiohttp.request("POST", f'.../{username}') as r:
825                return await r.json()
826
827        async def main():
828            users = sain.into_iter(["danny", "legalia"])
829            results = await users.async_for_each(lambda username: create_user(username))
830            for k, v in results.unwrap().items():
831                ...
832        ```
833
834        Parameters
835        ----------
836        func: `collections.Callable[[Item], Coroutine[None, Any, Any]]`
837            The async function to call on each item in the iterator.
838        """
839        return await futures.join(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def create_user(username: str) -> None:
    async with aiohttp.request("POST", f'.../{username}') as r:
        return await r.json()

async def main():
    users = sain.into_iter(["danny", "legalia"])
    results = await users.async_for_each(lambda username: create_user(username))
    for k, v in results.unwrap().items():
        ...
Parameters
  • func (collections.Callable[[Item], Coroutine[None, Any, Any]]): The async function to call on each item in the iterator.
@rustc_diagnostic_item('todo')
def todo(message: Optional[LiteralString] = None) -> NoReturn:
473@rustc_diagnostic_item("todo")
474def todo(message: typing.LiteralString | None = None) -> typing.NoReturn:
475    """A place holder that indicates unfinished code.
476
477    Example
478    -------
479    ```py
480    from sain import todo
481
482    def from_json(payload: dict[str, int]) -> int:
483        # Calling this function will raise `Error`.
484        todo()
485    ```
486
487    Parameters
488    ----------
489    message : `str | None`
490        Multiple optional arguments to pass if the error was raised.
491    """
492    raise Error(f"not yet implemented: {message}" if message else "not yet implemented")

A place holder that indicates unfinished code.

Example
from sain import todo

def from_json(payload: dict[str, int]) -> int:
    # Calling this function will raise `Error`.
    todo()
Parameters
  • message (str | None): Multiple optional arguments to pass if the error was raised.
  • # Implementations
  • **This function implements todo:
@rustc_diagnostic_item('deprecated')
def deprecated( *, since: Union[Literal['CURRENT_VERSION'], LiteralString, NoneType] = None, removed_in: Optional[LiteralString] = None, use_instead: Optional[LiteralString] = None, hint: Optional[LiteralString] = None) -> 'collections.Callable[[collections.Callable[P, U]], collections.Callable[P, U]]':
388@rustc_diagnostic_item("deprecated")
389def deprecated(
390    *,
391    since: typing.Literal["CURRENT_VERSION"] | typing.LiteralString | None = None,
392    removed_in: typing.LiteralString | None = None,
393    use_instead: typing.LiteralString | None = None,
394    hint: typing.LiteralString | None = None,
395) -> collections.Callable[
396    [collections.Callable[P, U]],
397    collections.Callable[P, U],
398]:
399    """A decorator that marks a function as deprecated.
400
401    An attempt to call the object that's marked will cause a runtime warn.
402
403    Example
404    -------
405    ```py
406    from sain import deprecated
407
408    @deprecated(
409        since = "1.0.0",
410        removed_in ="3.0.0",
411        use_instead = "UserImpl()",
412        hint = "Hint for ux."
413    )
414    class User:
415        ...
416
417    user = User() # This will cause a warning at runtime.
418    ```
419
420    Parameters
421    ----------
422    since : `str`
423        The version that the function was deprecated. the `CURRENT_VERSION` is used internally only.
424    removed_in : `str | None`
425        If provided, It will log when will the object will be removed in.
426    use_instead : `str | None`
427        If provided, This should be the alternative object name that should be used instead.
428    hint: `str`
429        An optional hint for the user.
430    """
431
432    def _create_message(obj: typing.Any) -> str:
433        msg = f"{_obj_type(obj)} `{obj.__module__}.{obj.__name__}` is deprecated."
434
435        if since is not None:
436            if since == "CURRENT_VERSION":
437                from sain import __version__ as _version
438
439                msg += " since " + _version
440            else:
441                msg += " since " + since
442
443        if removed_in:
444            msg += f" Scheduled for removal in `{removed_in}`."
445
446        if use_instead is not None:
447            msg += f" Use `{use_instead}` instead."
448
449        if hint:
450            msg += f" Hint: {hint}"
451        return msg
452
453    def decorator(func: collections.Callable[P, U]) -> collections.Callable[P, U]:
454        message = _create_message(func)
455
456        @functools.wraps(func)
457        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
458            _warn(message)
459            return func(*args, **kwargs)
460
461        # idk why pyright doesn't know the type of wrapper.
462        m = f"\n# Warning ⚠️\n{message}."
463        if wrapper.__doc__:
464            # append this message to an existing document.
465            wrapper.__doc__ = inspect.cleandoc(wrapper.__doc__) + f"{m}"
466        else:
467            wrapper.__doc__ = m
468        return wrapper
469
470    return decorator

A decorator that marks a function as deprecated.

An attempt to call the object that's marked will cause a runtime warn.

Example
from sain import deprecated

@deprecated(
    since = "1.0.0",
    removed_in ="3.0.0",
    use_instead = "UserImpl()",
    hint = "Hint for ux."
)
class User:
    ...

user = User() # This will cause a warning at runtime.
Parameters
  • since (str): The version that the function was deprecated. the CURRENT_VERSION is used internally only.
  • removed_in (str | None): If provided, It will log when will the object will be removed in.
  • use_instead (str | None): If provided, This should be the alternative object name that should be used instead.
  • hint (str): An optional hint for the user.
  • # Implementations
  • **This function implements deprecated:
@rustc_diagnostic_item('unimplemented')
def unimplemented( *, message: Optional[LiteralString] = None, available_in: Optional[LiteralString] = None) -> 'collections.Callable[[collections.Callable[P, U]], collections.Callable[P, U]]':
495@rustc_diagnostic_item("unimplemented")
496def unimplemented(
497    *,
498    message: typing.LiteralString | None = None,
499    available_in: typing.LiteralString | None = None,
500) -> collections.Callable[
501    [collections.Callable[P, U]],
502    collections.Callable[P, U],
503]:
504    """A decorator that marks an object as unimplemented.
505
506    An attempt to call the object that's marked will cause a runtime warn.
507
508    Example
509    -------
510    ```py
511    from sain import unimplemented
512
513    @unimplemented("User object is not implemented yet.")
514    class User:
515        ...
516    ```
517
518    Parameters
519    ----------
520    message : `str | None`
521        An optional message to be displayed when the function is called. Otherwise default message will be used.
522    available_in : `str | None`
523        If provided, This will be shown as what release this object be implemented.
524    """
525
526    def _create_message(obj: typing.Any) -> str:
527        msg = (
528            message
529            or f"{_obj_type(obj)} `{obj.__module__}.{obj.__name__}` is not yet implemented."
530        )  # noqa: W503
531
532        if available_in:
533            msg += f" Available in `{available_in}`."
534        return msg
535
536    def decorator(obj: collections.Callable[P, U]) -> collections.Callable[P, U]:
537        message = _create_message(obj)
538
539        @functools.wraps(obj)
540        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
541            _warn(message)
542            return obj(*args, **kwargs)
543
544        # idk why pyright doesn't know the type of wrapper.
545        m = f"\n# Warning ⚠️\n{message}."
546        if wrapper.__doc__:
547            # append this message to an existing document.
548            wrapper.__doc__ = inspect.cleandoc(wrapper.__doc__) + f"{m}"
549        else:
550            wrapper.__doc__ = m
551        return wrapper
552
553    return decorator

A decorator that marks an object as unimplemented.

An attempt to call the object that's marked will cause a runtime warn.

Example
from sain import unimplemented

@unimplemented("User object is not implemented yet.")
class User:
    ...
Parameters
  • message (str | None): An optional message to be displayed when the function is called. Otherwise default message will be used.
  • available_in (str | None): If provided, This will be shown as what release this object be implemented.
  • # Implementations
  • **This function implements unimplemented:
@rustc_diagnostic_item('doc')
def doc( path: 'Read') -> 'collections.Callable[[collections.Callable[P, U]], collections.Callable[P, U]]':
556@rustc_diagnostic_item("doc")
557def doc(
558    path: Read,
559) -> collections.Callable[
560    [collections.Callable[P, U]],
561    collections.Callable[P, U],
562]:
563    """Set `path` to be the object's documentation.
564
565    Example
566    -------
567    ```py
568    from sain import doc
569    from pathlib import Path
570
571    @doc(Path("../README.md"))
572    class User:
573
574        @doc("bool.html")
575        def bool_docs() -> None:
576            ...
577    ```
578
579    Parameters
580    ----------
581    path: `type[int] | type[str] | type[bytes] | type[PathLike[str]] | type[PathLike[bytes]]`
582        The path to read the content from.
583    """
584
585    def decorator(f: collections.Callable[P, U]) -> collections.Callable[P, U]:
586        with open(path, "r") as file:
587            f.__doc__ = file.read()
588
589        @functools.wraps(f)
590        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
591            return f(*args, **kwargs)
592
593        return wrapper
594
595    return decorator

Set path to be the object's documentation.

Example
from sain import doc
from pathlib import Path

@doc(Path("../README.md"))
class User:

    @doc("bool.html")
    def bool_docs() -> None:
        ...
Parameters
  • path (type[int] | type[str] | type[bytes] | type[PathLike[str]] | type[PathLike[bytes]]): The path to read the content from.
  • # Implementations
  • **This function implements doc:
@rustc_diagnostic_item('include_str')
def include_str(file: LiteralString) -> LiteralString:
297@rustc_diagnostic_item("include_str")
298def include_str(file: typing.LiteralString) -> typing.LiteralString:
299    """Includes a file as literal `str`.
300
301    This function is not magic like Rust's, It is literally defined as
302
303    ```py
304    with open(file, "r") as f:
305        return f.read()
306    ```
307
308    The file name can may be either a relative to the current file or a complate path.
309
310    Example
311    -------
312    ```py
313    from sain.macros import include_str
314
315    def entry() -> None:
316        ...
317
318    entry.__doc__ = include_str("README.md")
319
320    ```
321    """
322    with open(file, "r") as buf:
323        return buf.read()  # pyright: ignore - simulates a `&'static str` slice.

Includes a file as literal str.

This function is not magic like Rust's, It is literally defined as

with open(file, "r") as f:
    return f.read()

The file name can may be either a relative to the current file or a complate path.

Example
from sain.macros import include_str

def entry() -> None:
    ...

entry.__doc__ = include_str("README.md")

Implementations

This function implements include_str in Rust.

@rustc_diagnostic_item('include_bytes')
def include_bytes(file: LiteralString) -> bytes:
267@rustc_diagnostic_item("include_bytes")
268def include_bytes(file: typing.LiteralString) -> bytes:
269    """Includes a file as `bytes`.
270
271    This function is not magic like Rust's, It is literally defined as
272
273    ```py
274    with open(file, "rb") as f:
275        return f.read()
276    ```
277
278    The file name can may be either a relative to the current file or a complate path.
279
280    Example
281    -------
282    File "spanish.in":
283    ```text
284    adiós
285    ```
286    File "main.py":
287    ```py
288    from sain.macros import include_bytes
289    buffer = include_bytes("spanish.in")
290    assert buffer.decode() == "adiós"
291    ```
292    """
293    with open(file, "rb") as buf:
294        return buf.read()

Includes a file as bytes.

This function is not magic like Rust's, It is literally defined as

with open(file, "rb") as f:
    return f.read()

The file name can may be either a relative to the current file or a complate path.

Example

File "spanish.in":

adiós

File "main.py":

from sain.macros import include_bytes
buffer = include_bytes("spanish.in")
assert buffer.decode() == "adiós"

Implementations

This function implements include_bytes in Rust.

@rustc_diagnostic_item('assert_eq')
def assert_eq(left: +T, right: +T) -> None:
227@rustc_diagnostic_item("assert_eq")
228def assert_eq(left: T, right: T) -> None:
229    """Asserts that two expressions are equal to each other.
230
231    This exactly as `assert left == right`, but includes a useful message incase of failure.
232
233    Example
234    -------
235    ```py
236    from sain.macros import assert_eq
237    a = 3
238    b = 1 + 2
239    assert_eq(a, b)
240    ```
241    """
242    assert (
243        left == right
244    ), f'assertion `left == right` failed\nleft: "{left!r}"\nright: "{right!r}"'

Asserts that two expressions are equal to each other.

This exactly as assert left == right, but includes a useful message incase of failure.

Example
from sain.macros import assert_eq
a = 3
b = 1 + 2
assert_eq(a, b)

Implementations

This function implements assert_eq in Rust.

@rustc_diagnostic_item('assert_ne')
def assert_ne(left: +T, right: +T) -> None:
247@rustc_diagnostic_item("assert_ne")
248def assert_ne(left: T, right: T) -> None:
249    """Asserts that two expressions are not equal to each other.
250
251    This exactly as `assert left == right`, but includes a useful message incase of failure.
252
253    Example
254    -------
255    ```py
256    from sain.macros import assert_ne
257    a = 3
258    b = 2 + 2
259    assert_ne(a, b)
260    ```
261    """
262    assert (
263        left != right
264    ), f'assertion `left == right` failed\nleft: "{left!r}"\nright: "{right!r}"'

Asserts that two expressions are not equal to each other.

This exactly as assert left == right, but includes a useful message incase of failure.

Example
from sain.macros import assert_ne
a = 3
b = 2 + 2
assert_ne(a, b)

Implementations

This function implements assert_ne in Rust.

@rustc_diagnostic_item('Ok')
@typing.final
@dataclasses.dataclass(slots=True, frozen=True, repr=False)
class Ok(typing.Generic[~T]):
119@rustc_diagnostic_item("Ok")
120@typing.final
121@dataclasses.dataclass(slots=True, frozen=True, repr=False)
122class Ok(typing.Generic[T]):
123    """Contains the success value of `Result[T, ...]`."""
124
125    _inner: T
126
127    ###############################
128    # * Querying operations. * #
129    ###############################
130
131    def is_ok(self) -> typing.Literal[True]:
132        """Returns `True` if the contained value is `Ok` and `False` if it an `Err`.
133
134        Example
135        -------
136        ```py
137        value: Result[str, None] = Ok("value")
138        assert value.is_ok() == True
139        ```
140        """
141        return True
142
143    def is_ok_and(self, f: F[T, bool]) -> bool:
144        """Returns `True` if the contained value is `Ok` and `f()` returns True.
145
146        Example
147        -------
148        ```py
149        value: Result[str, None] = Ok("value")
150        assert value.is_ok_and(lambda inner: inner == "value")
151        # True
152        ```
153        """
154        return f(self._inner)
155
156    # These are never truthy in an `Ok` instance.
157    def is_err(self) -> typing.Literal[False]:
158        """Returns `True` if the contained value is `Err`.
159
160        Example
161        -------
162        ```py
163        value: Result[str, None] = Ok("value")
164
165        assert value.is_err() == False
166        ```
167        """
168        return False
169
170    def is_err_and(self, f: F[T, bool]) -> typing.Literal[False]:
171        """Returns `True` if the contained value is `Ok` and `f()` returns True.
172
173        Example
174        -------
175        ```py
176        value: Result[str, None] = Ok("value")
177
178        assert value.is_err_and(lambda inner: inner == "value")
179        # False
180        ```
181        """
182        return False
183
184    ###################
185    # * Extractors * #
186    ###################
187
188    def expect(self, message: str, /) -> T:
189        """Return the underlying value if it was `Ok`, Raising `RuntimeError`
190        if it was `Err` with `message` passed to it.
191
192        Example
193        -------
194        ```py
195        ok: Result[str, None] = Ok("owo")
196        ok.expect("err") # owo
197
198        err: Result[str, None] = Err(None)
199        err.expect("err") # RuntimeError("err")
200        ```
201        """
202        return self._inner
203
204    def expect_err(self) -> Never:
205        """Return the `Err` value if `self` is an `Err`, panicking otherwise.
206
207        Example
208        -------
209        ```py
210        ok: Result[str, None] = Ok("owo")
211        ok.expect_err()  # RuntimeError("Called expect_err on `Ok`)
212
213        err: Result[str, None] = Err(None)
214        err.expect_err() # None
215        ```
216        """
217        raise RuntimeError("Called `expect_err` on an `Ok` value.")
218
219    def unwrap(self) -> T:
220        """Return the underlying value if it was `Ok`, Raising `RuntimeError` if it was `Err`.
221
222        Example
223        -------
224        ```py
225        ok: Result[str, None] = Ok("owo")
226        ok.unwrap() # owo
227
228        err: Result[str, None] = Err(None)
229        err.unwrap() # RuntimeError
230        ```
231        """
232        return self._inner
233
234    def unwrap_or(self, default: T, /) -> T:
235        """Return the underlying value if it was `Ok`, returning `default` if it was `Err`.
236
237        Example
238        -------
239        ```py
240        ok: Result[str, None] = Ok("OwO")
241        ok.unwrap_or("uwu") # OwO
242
243        err: Result[str, None] = Err(None)
244        err.unwrap_or("uwu") # uwu
245        ```
246        """
247        return self._inner
248
249    def unwrap_or_else(self, f: F[E, T]) -> T:
250        """Return the contained `Ok` value or computes it from `f()` if it was `Err`.
251
252        Example
253        -------
254        ```py
255        ok: Result[int, str] = Ok(4)
256        ok.unwrap_or_else(lambda e: 0) # 4
257
258        err: Result[int, str] = Err("word")
259        err.unwrap_or_else(lambda e: len(e)) # 4
260        ```
261        """
262        return self._inner
263
264    def unwrap_err(self) -> Never:
265        """Return the contained `Err` value, Raising if it was `Ok`.
266
267        Example
268        -------
269        ```py
270        ok: Result[str, None] = Ok("buh")
271        ok.unwrap_err()  # RuntimeError
272
273        err: Result[str, None] = Err(None)
274        err.unwrap_err() == None
275        # True
276        ```
277        """
278        raise RuntimeError(f"Called `unwrap_err` on an `Ok` variant: {self._inner!r}")
279
280    ############################
281    # * Conversion adapters. * #
282    ############################
283
284    def ok(self) -> Option[T]:
285        """Transform `Result[T, E]` to `Option[T]`, mapping `Ok(v)` to `Some(T)` and `Err(e)` to `None`.
286
287        Example
288        -------
289        ```py
290        value: Result[str, None] = Ok("buh")
291        value.ok().is_some() # True
292
293        value: Result[str, int] = Err(0)
294        value.ok().is_none() # True
295        ```
296        """
297        return _option.Some(self._inner)
298
299    def err(self) -> Option[T]:
300        """Transform `Result[T, E]` to `Option[E]`, mapping `Ok(v)` to `None` and `Err(e)` to `Some(e)`.
301
302        Example
303        -------
304        ```py
305        value: Result[str, None] = Ok("buh")
306        value.err().is_none() # True
307
308        value: Result[str, int] = Err(0)
309        value.err().is_some() # True
310        ```
311        """
312        return _option.NOTHING  # pyright: ignore
313
314    def inspect(self, f: F[T, typing.Any]) -> Self:
315        """Call a function to the contained value if it was `Ok` and do nothing if it was `Err`
316
317        Example
318        -------
319        ```py
320        def sink(value: str) -> None:
321            # do something with value
322            print("Called " + value)
323
324        x: Result[str, None] = Ok("ok")
325        x.inspect(sink) # "Called ok"
326
327        x: Result[str, str] = Err("err")
328        x.inspect(sink) # None
329        ```
330        """
331        f(self._inner)
332        return self
333
334    def inspect_err(self, f: F[E, typing.Any]) -> Self:
335        """Call a function to the contained value if it was `Err` and do nothing if it was `Ok`
336
337        Example
338        -------
339        ```py
340        def sink(value: str) -> None:
341            # do something with value
342            print("Called " + value)
343
344        x: Result[str, None] = Ok("ok")
345        x.inspect_err(sink) # None
346
347        x: Result[str, str] = Err("err")
348        x.inspect_err(sink) # Called err
349        ```
350        """
351        return self
352
353    def map(self, f: F[T, U], /) -> Ok[U]:
354        """Map `Result<T, E>` to `Result<U, E>` by applying a function to the `Ok` value,
355        leaving `Err` untouched.
356
357        Example
358        -------
359        ```py
360        ok: Result[str, int] = Ok("1")
361        ok.map(lambda c: int(c) + 1) # Ok(2)
362
363        err: Result[str, int] = Err(0)
364        err.map(str.upper) # Err(0)
365        ```
366        """
367        return Ok(f(self._inner))
368
369    def map_or(self, f: F[T, U], default: U, /) -> U:
370        """Returns the provided `default` if the contained value is `Err`,
371
372        Otherwise extracts the `Ok` value and maps it to `f()`
373
374        Example
375        -------
376        ```py
377        x: Result[str, str] = Ok("foo")
378        assert x.map_or(lambda c: len(c), 42) == 3
379
380        x: Result[str, str] = Err("bar")
381        assert x.map_or(lambda c: len(c), 42) == 42
382        ```
383        """
384        return f(self._inner)
385
386    def map_or_else(self, f: F[T, U], default: F[E, U], /) -> U:
387        """Maps a Result<T, E> to U by applying fallback function `default` to a contained Err value,
388        or function `f` to a contained Ok value.
389
390        Example
391        -------
392        ```py
393        x: Result[str, str] = Ok("four")
394        assert x.map_or_else(
395            lambda ok: 2 * len(ok),
396            default=lambda err: len(err)
397        ) == 8
398
399        x: Result[str, str] = Err("bar")
400        assert x.map_or_else(
401            lambda c: 2 * len(c),
402            lambda err: len(err)
403        ) == 3
404        ```
405        """
406        return f(self._inner)
407
408    def map_err(self, f: F[E, U], /) -> Self:
409        """Maps a `Result[T, E]` to `Result[T, U]` by applying function `f`, leaving the `Ok` value untouched.
410
411        Example
412        -------
413        ```py
414        x: Result[str, int] = Ok("blue")
415        x.map_err(lambda err: err + 1) # Ok("blue")
416
417        x: Result[str, int] = Err(5)
418        x.map_err(float) # Err(5.0)
419        ```
420        """
421        return self
422
423    ##############################
424    # * Iterator constructors. * #
425    ##############################
426
427    def iter(self) -> _iter.TrustedIter[T]:
428        """An iterator over the possible contained value.
429
430        If `self` was `Ok`, then the iterator will yield the Ok `T`. otherwise yields nothing.
431
432        Example
433        -------
434        ```py
435        c: Result[str, int] = Ok("blue")
436        c.iter().next() == Some("blue")
437
438        c: Result[str, int] = Err(0)
439        c.iter().next() == Some(None)
440        ```
441        """
442        return _iter.TrustedIter((self._inner,))
443
444    def __iter__(self) -> collections.Iterator[T]:
445        yield self._inner
446
447    #################
448    # * Overloads * #
449    #################
450
451    def __repr__(self) -> str:
452        return f"Ok({self._inner!r})"
453
454    def __or__(self, other: T) -> T:
455        return self._inner
456
457    def __invert__(self) -> T:
458        return self._inner

Contains the success value of Result[T, ...].

Implementations

This class implements .Result.html#variant.Ok">Ok in Rust.

Ok(_inner: ~T)
def is_ok(self) -> Literal[True]:
131    def is_ok(self) -> typing.Literal[True]:
132        """Returns `True` if the contained value is `Ok` and `False` if it an `Err`.
133
134        Example
135        -------
136        ```py
137        value: Result[str, None] = Ok("value")
138        assert value.is_ok() == True
139        ```
140        """
141        return True

Returns True if the contained value is Ok and False if it an Err.

Example
value: Result[str, None] = Ok("value")
assert value.is_ok() == True
def is_ok_and(self, f: Callable[[~T], bool]) -> bool:
143    def is_ok_and(self, f: F[T, bool]) -> bool:
144        """Returns `True` if the contained value is `Ok` and `f()` returns True.
145
146        Example
147        -------
148        ```py
149        value: Result[str, None] = Ok("value")
150        assert value.is_ok_and(lambda inner: inner == "value")
151        # True
152        ```
153        """
154        return f(self._inner)

Returns True if the contained value is Ok and f() returns True.

Example
value: Result[str, None] = Ok("value")
assert value.is_ok_and(lambda inner: inner == "value")
# True
def is_err(self) -> Literal[False]:
157    def is_err(self) -> typing.Literal[False]:
158        """Returns `True` if the contained value is `Err`.
159
160        Example
161        -------
162        ```py
163        value: Result[str, None] = Ok("value")
164
165        assert value.is_err() == False
166        ```
167        """
168        return False

Returns True if the contained value is Err.

Example
value: Result[str, None] = Ok("value")

assert value.is_err() == False
def is_err_and(self, f: Callable[[~T], bool]) -> Literal[False]:
170    def is_err_and(self, f: F[T, bool]) -> typing.Literal[False]:
171        """Returns `True` if the contained value is `Ok` and `f()` returns True.
172
173        Example
174        -------
175        ```py
176        value: Result[str, None] = Ok("value")
177
178        assert value.is_err_and(lambda inner: inner == "value")
179        # False
180        ```
181        """
182        return False

Returns True if the contained value is Ok and f() returns True.

Example
value: Result[str, None] = Ok("value")

assert value.is_err_and(lambda inner: inner == "value")
# False
def expect(self, message: str, /) -> ~T:
188    def expect(self, message: str, /) -> T:
189        """Return the underlying value if it was `Ok`, Raising `RuntimeError`
190        if it was `Err` with `message` passed to it.
191
192        Example
193        -------
194        ```py
195        ok: Result[str, None] = Ok("owo")
196        ok.expect("err") # owo
197
198        err: Result[str, None] = Err(None)
199        err.expect("err") # RuntimeError("err")
200        ```
201        """
202        return self._inner

Return the underlying value if it was Ok, Raising RuntimeError if it was Err with message passed to it.

Example
ok: Result[str, None] = Ok("owo")
ok.expect("err") # owo

err: Result[str, None] = Err(None)
err.expect("err") # RuntimeError("err")
def expect_err(self) -> Never:
204    def expect_err(self) -> Never:
205        """Return the `Err` value if `self` is an `Err`, panicking otherwise.
206
207        Example
208        -------
209        ```py
210        ok: Result[str, None] = Ok("owo")
211        ok.expect_err()  # RuntimeError("Called expect_err on `Ok`)
212
213        err: Result[str, None] = Err(None)
214        err.expect_err() # None
215        ```
216        """
217        raise RuntimeError("Called `expect_err` on an `Ok` value.")

Return the Err value if self is an Err, panicking otherwise.

Example
ok: Result[str, None] = Ok("owo")
ok.expect_err()  # RuntimeError("Called expect_err on `Ok`)

err: Result[str, None] = Err(None)
err.expect_err() # None
def unwrap(self) -> ~T:
219    def unwrap(self) -> T:
220        """Return the underlying value if it was `Ok`, Raising `RuntimeError` if it was `Err`.
221
222        Example
223        -------
224        ```py
225        ok: Result[str, None] = Ok("owo")
226        ok.unwrap() # owo
227
228        err: Result[str, None] = Err(None)
229        err.unwrap() # RuntimeError
230        ```
231        """
232        return self._inner

Return the underlying value if it was Ok, Raising RuntimeError if it was Err.

Example
ok: Result[str, None] = Ok("owo")
ok.unwrap() # owo

err: Result[str, None] = Err(None)
err.unwrap() # RuntimeError
def unwrap_or(self, default: ~T, /) -> ~T:
234    def unwrap_or(self, default: T, /) -> T:
235        """Return the underlying value if it was `Ok`, returning `default` if it was `Err`.
236
237        Example
238        -------
239        ```py
240        ok: Result[str, None] = Ok("OwO")
241        ok.unwrap_or("uwu") # OwO
242
243        err: Result[str, None] = Err(None)
244        err.unwrap_or("uwu") # uwu
245        ```
246        """
247        return self._inner

Return the underlying value if it was Ok, returning default if it was Err.

Example
ok: Result[str, None] = Ok("OwO")
ok.unwrap_or("uwu") # OwO

err: Result[str, None] = Err(None)
err.unwrap_or("uwu") # uwu
def unwrap_or_else(self, f: Callable[[~E], ~T]) -> ~T:
249    def unwrap_or_else(self, f: F[E, T]) -> T:
250        """Return the contained `Ok` value or computes it from `f()` if it was `Err`.
251
252        Example
253        -------
254        ```py
255        ok: Result[int, str] = Ok(4)
256        ok.unwrap_or_else(lambda e: 0) # 4
257
258        err: Result[int, str] = Err("word")
259        err.unwrap_or_else(lambda e: len(e)) # 4
260        ```
261        """
262        return self._inner

Return the contained Ok value or computes it from f() if it was Err.

Example
ok: Result[int, str] = Ok(4)
ok.unwrap_or_else(lambda e: 0) # 4

err: Result[int, str] = Err("word")
err.unwrap_or_else(lambda e: len(e)) # 4
def unwrap_err(self) -> Never:
264    def unwrap_err(self) -> Never:
265        """Return the contained `Err` value, Raising if it was `Ok`.
266
267        Example
268        -------
269        ```py
270        ok: Result[str, None] = Ok("buh")
271        ok.unwrap_err()  # RuntimeError
272
273        err: Result[str, None] = Err(None)
274        err.unwrap_err() == None
275        # True
276        ```
277        """
278        raise RuntimeError(f"Called `unwrap_err` on an `Ok` variant: {self._inner!r}")

Return the contained Err value, Raising if it was Ok.

Example
ok: Result[str, None] = Ok("buh")
ok.unwrap_err()  # RuntimeError

err: Result[str, None] = Err(None)
err.unwrap_err() == None
# True
def ok(self) -> 'Option[T]':
284    def ok(self) -> Option[T]:
285        """Transform `Result[T, E]` to `Option[T]`, mapping `Ok(v)` to `Some(T)` and `Err(e)` to `None`.
286
287        Example
288        -------
289        ```py
290        value: Result[str, None] = Ok("buh")
291        value.ok().is_some() # True
292
293        value: Result[str, int] = Err(0)
294        value.ok().is_none() # True
295        ```
296        """
297        return _option.Some(self._inner)

Transform Result[T, E] to Option[T], mapping Ok(v) to Some(T) and Err(e) to None.

Example
value: Result[str, None] = Ok("buh")
value.ok().is_some() # True

value: Result[str, int] = Err(0)
value.ok().is_none() # True
def err(self) -> 'Option[T]':
299    def err(self) -> Option[T]:
300        """Transform `Result[T, E]` to `Option[E]`, mapping `Ok(v)` to `None` and `Err(e)` to `Some(e)`.
301
302        Example
303        -------
304        ```py
305        value: Result[str, None] = Ok("buh")
306        value.err().is_none() # True
307
308        value: Result[str, int] = Err(0)
309        value.err().is_some() # True
310        ```
311        """
312        return _option.NOTHING  # pyright: ignore

Transform Result[T, E] to Option[E], mapping Ok(v) to None and Err(e) to Some(e).

Example
value: Result[str, None] = Ok("buh")
value.err().is_none() # True

value: Result[str, int] = Err(0)
value.err().is_some() # True
def inspect(self, f: Callable[[~T], typing.Any]) -> Self:
314    def inspect(self, f: F[T, typing.Any]) -> Self:
315        """Call a function to the contained value if it was `Ok` and do nothing if it was `Err`
316
317        Example
318        -------
319        ```py
320        def sink(value: str) -> None:
321            # do something with value
322            print("Called " + value)
323
324        x: Result[str, None] = Ok("ok")
325        x.inspect(sink) # "Called ok"
326
327        x: Result[str, str] = Err("err")
328        x.inspect(sink) # None
329        ```
330        """
331        f(self._inner)
332        return self

Call a function to the contained value if it was Ok and do nothing if it was Err

Example
def sink(value: str) -> None:
    # do something with value
    print("Called " + value)

x: Result[str, None] = Ok("ok")
x.inspect(sink) # "Called ok"

x: Result[str, str] = Err("err")
x.inspect(sink) # None
def inspect_err(self, f: Callable[[~E], typing.Any]) -> Self:
334    def inspect_err(self, f: F[E, typing.Any]) -> Self:
335        """Call a function to the contained value if it was `Err` and do nothing if it was `Ok`
336
337        Example
338        -------
339        ```py
340        def sink(value: str) -> None:
341            # do something with value
342            print("Called " + value)
343
344        x: Result[str, None] = Ok("ok")
345        x.inspect_err(sink) # None
346
347        x: Result[str, str] = Err("err")
348        x.inspect_err(sink) # Called err
349        ```
350        """
351        return self

Call a function to the contained value if it was Err and do nothing if it was Ok

Example
def sink(value: str) -> None:
    # do something with value
    print("Called " + value)

x: Result[str, None] = Ok("ok")
x.inspect_err(sink) # None

x: Result[str, str] = Err("err")
x.inspect_err(sink) # Called err
def map(self, f: Callable[[~T], ~U], /) -> Ok[~U]:
353    def map(self, f: F[T, U], /) -> Ok[U]:
354        """Map `Result<T, E>` to `Result<U, E>` by applying a function to the `Ok` value,
355        leaving `Err` untouched.
356
357        Example
358        -------
359        ```py
360        ok: Result[str, int] = Ok("1")
361        ok.map(lambda c: int(c) + 1) # Ok(2)
362
363        err: Result[str, int] = Err(0)
364        err.map(str.upper) # Err(0)
365        ```
366        """
367        return Ok(f(self._inner))

Map Result<T, E> to Result<U, E> by applying a function to the Ok value, leaving Err untouched.

Example
ok: Result[str, int] = Ok("1")
ok.map(lambda c: int(c) + 1) # Ok(2)

err: Result[str, int] = Err(0)
err.map(str.upper) # Err(0)
def map_or(self, f: Callable[[~T], ~U], default: ~U, /) -> ~U:
369    def map_or(self, f: F[T, U], default: U, /) -> U:
370        """Returns the provided `default` if the contained value is `Err`,
371
372        Otherwise extracts the `Ok` value and maps it to `f()`
373
374        Example
375        -------
376        ```py
377        x: Result[str, str] = Ok("foo")
378        assert x.map_or(lambda c: len(c), 42) == 3
379
380        x: Result[str, str] = Err("bar")
381        assert x.map_or(lambda c: len(c), 42) == 42
382        ```
383        """
384        return f(self._inner)

Returns the provided default if the contained value is Err,

Otherwise extracts the Ok value and maps it to f()

Example
x: Result[str, str] = Ok("foo")
assert x.map_or(lambda c: len(c), 42) == 3

x: Result[str, str] = Err("bar")
assert x.map_or(lambda c: len(c), 42) == 42
def map_or_else(self, f: Callable[[~T], ~U], default: Callable[[~E], ~U], /) -> ~U:
386    def map_or_else(self, f: F[T, U], default: F[E, U], /) -> U:
387        """Maps a Result<T, E> to U by applying fallback function `default` to a contained Err value,
388        or function `f` to a contained Ok value.
389
390        Example
391        -------
392        ```py
393        x: Result[str, str] = Ok("four")
394        assert x.map_or_else(
395            lambda ok: 2 * len(ok),
396            default=lambda err: len(err)
397        ) == 8
398
399        x: Result[str, str] = Err("bar")
400        assert x.map_or_else(
401            lambda c: 2 * len(c),
402            lambda err: len(err)
403        ) == 3
404        ```
405        """
406        return f(self._inner)

Maps a Result to U by applying fallback function default to a contained Err value, or function f to a contained Ok value.

Example
x: Result[str, str] = Ok("four")
assert x.map_or_else(
    lambda ok: 2 * len(ok),
    default=lambda err: len(err)
) == 8

x: Result[str, str] = Err("bar")
assert x.map_or_else(
    lambda c: 2 * len(c),
    lambda err: len(err)
) == 3
def map_err(self, f: Callable[[~E], ~U], /) -> Self:
408    def map_err(self, f: F[E, U], /) -> Self:
409        """Maps a `Result[T, E]` to `Result[T, U]` by applying function `f`, leaving the `Ok` value untouched.
410
411        Example
412        -------
413        ```py
414        x: Result[str, int] = Ok("blue")
415        x.map_err(lambda err: err + 1) # Ok("blue")
416
417        x: Result[str, int] = Err(5)
418        x.map_err(float) # Err(5.0)
419        ```
420        """
421        return self

Maps a Result[T, E] to Result[T, U] by applying function f, leaving the Ok value untouched.

Example
x: Result[str, int] = Ok("blue")
x.map_err(lambda err: err + 1) # Ok("blue")

x: Result[str, int] = Err(5)
x.map_err(float) # Err(5.0)
def iter(self) -> sain.iter.TrustedIter[~T]:
427    def iter(self) -> _iter.TrustedIter[T]:
428        """An iterator over the possible contained value.
429
430        If `self` was `Ok`, then the iterator will yield the Ok `T`. otherwise yields nothing.
431
432        Example
433        -------
434        ```py
435        c: Result[str, int] = Ok("blue")
436        c.iter().next() == Some("blue")
437
438        c: Result[str, int] = Err(0)
439        c.iter().next() == Some(None)
440        ```
441        """
442        return _iter.TrustedIter((self._inner,))

An iterator over the possible contained value.

If self was Ok, then the iterator will yield the Ok T. otherwise yields nothing.

Example
c: Result[str, int] = Ok("blue")
c.iter().next() == Some("blue")

c: Result[str, int] = Err(0)
c.iter().next() == Some(None)
@rustc_diagnostic_item('Err')
@typing.final
@dataclasses.dataclass(slots=True, frozen=True, repr=False)
class Err(typing.Generic[~E]):
461@rustc_diagnostic_item("Err")
462@typing.final
463@dataclasses.dataclass(slots=True, frozen=True, repr=False)
464class Err(typing.Generic[E]):
465    """Contains the error value of `Result[..., E]`."""
466
467    _inner: E
468
469    ################################
470    # * Boolean operations. * #
471    ################################
472
473    def is_ok(self) -> typing.Literal[False]:
474        """Returns `True` if the contained value is `Ok` and `False` if it an `Err`.
475
476        Example
477        -------
478        ```py
479        value: Result[str, None] = Err(None)
480
481        assert value.is_ok() == False
482        ```
483        """
484        return False
485
486    def is_ok_and(self, f: F[E, bool]) -> typing.Literal[False]:
487        """Returns `True` if the contained value is `Ok` and `f()` returns True.
488
489        Example
490        -------
491        ```py
492        value: Result[str, None] = Err(None)
493
494        assert value.is_ok_and(lambda inner: inner == "value")
495        # False
496        ```
497        """
498        return False
499
500    # These are never truthy in an `Ok` instance.
501    def is_err(self) -> typing.Literal[True]:
502        """Returns `True` if the contained value is `Err`.
503
504        Example
505        -------
506        ```py
507        value: Result[str, None] = Err(None)
508
509        assert value.is_err() == True
510        ```
511        """
512        return True
513
514    def is_err_and(self, f: F[E, bool]) -> bool:
515        """Returns `True` if the contained value is `Ok` and `f()` returns True..
516
517        Example
518        -------
519        ```py
520        value: Result[str, None] = Err(None)
521
522        assert value.is_err_and(lambda err: err is None)
523        # True
524        ```
525        """
526        return f(self._inner)
527
528    ###################
529    # * Extractors. * #
530    ###################
531
532    def expect(self, msg: str) -> Never:
533        """Return the underlying value if it was `Ok`, Raising `RuntimeError`
534        if it was `Err` with `message` passed to it.
535
536        Example
537        -------
538        ```py
539        ok: Result[str, None] = Ok("owo")
540        ok.expect("err") # owo
541
542        err: Result[str, None] = Err(None)
543        err.expect("err") # RuntimeError("err")
544        ```
545        """
546        raise RuntimeError(msg) from None
547
548    def expect_err(self) -> E:
549        """Return the `Err` if it was `Err`, panicking otherwise.
550
551
552        Example
553        -------
554        ```py
555        x: Result[str, None] = Ok("owo")
556        x.expect_err()  # RuntimeError("Called expect_err on `Ok`)
557
558        x: Result[str, None] = Err(None)
559        x.expect_err() # None
560        ```
561        """
562        return self._inner
563
564    def unwrap(self) -> Never:
565        """Return the underlying value if it was `Ok`, Raising `RuntimeError` if it was `Err`.
566
567        Example
568        -------
569        ```py
570        ok: Result[str, None] = Ok("owo")
571        ok.unwrap() # owo
572
573        err: Result[str, None] = Err(None)
574        err.unwrap() # RuntimeError
575        ```
576        """
577        raise RuntimeError(
578            f"Called `unwrap()` on an `Err` variant: {self._inner!r}"
579        ) from None
580
581    def unwrap_or(self, default: T, /) -> T:
582        """Return the underlying value if it was `Ok`, returning `default` if it was `Err`.
583
584        Example
585        -------
586        ```py
587        ok: Result[str, None] = Ok("OwO")
588        ok.unwrap_or("uwu") # OwO
589
590        err: Result[str, None] = Err(None)
591        err.unwrap_or("uwu") # uwu
592        ```
593        """
594        return default
595
596    def unwrap_or_else(self, f: F[E, T]) -> T:
597        """Return the contained `Ok` value or computes it from `f()` if it was `Err`.
598
599        Example
600        -------
601        ```py
602        ok: Result[int, str] = Ok(4)
603        ok.unwrap_or_else(lambda e: 0) # 4
604
605        err: Result[int, str] = Err("word")
606        err.unwrap_or_else(lambda e: len(e)) # 4
607        ```
608        """
609        return f(self._inner)
610
611    def unwrap_err(self) -> E:
612        """Return the contained `Err` value, Raising if it was `Ok`.
613
614        Example
615        -------
616        ```py
617        ok: Result[str, None] = Ok("buh")
618        ok.unwrap_err()  # RuntimeError
619
620        err: Result[str, None] = Err(None)
621        err.unwrap_err() == None
622        # True
623        ```
624        """
625        return self._inner
626
627    ############################
628    # * Conversion adapters. * #
629    ############################
630
631    def inspect(self, f: F[T, typing.Any]) -> Self:
632        """Call a function to the contained value if it was `Ok` and do nothing if it was `Err`
633
634        Example
635        -------
636        ```py
637        def sink(value: str) -> None:
638            # do something with value
639            print("Called " + value)
640
641        x: Result[str, None] = Ok("ok")
642        x.inspect(sink) # "Called ok"
643
644        x: Result[str, str] = Err("err")
645        x.inspect(sink) # None
646        ```
647        """
648        return self
649
650    def inspect_err(self, f: F[E, typing.Any]) -> Self:
651        """Call a function to the contained value if it was `Err` and do nothing if it was `Ok`
652
653        Example
654        -------
655        ```py
656        def sink(value: str) -> None:
657            # do something with value
658            print("Called " + value)
659
660        x: Result[str, None] = Ok("ok")
661        x.inspect_err(sink) # None
662
663        x: Result[str, str] = Err("err")
664        x.inspect_err(sink) # Called err
665        ```
666        """
667        f(self._inner)
668        return self
669
670    def ok(self) -> Option[None]:
671        """Transform `Result[T, E]` to `Option[T]`, mapping `Ok(v)` to `Some(T)` and `Err(e)` to `None`.
672
673        Example
674        -------
675        ```py
676        value: Result[str, None] = Ok("buh")
677        value.ok().is_some() # True
678
679        value: Result[str, int] = Err(0)
680        value.ok().is_none() # True
681        ```
682        """
683        return _option.NOTHING
684
685    def err(self) -> Option[E]:
686        """Transform `Result[T, E]` to `Option[E]`, mapping `Ok(v)` to `None` and `Err(e)` to `Some(e)`.
687
688        Example
689        -------
690        ```py
691        value: Result[str, None] = Ok("buh")
692        value.err().is_none() # True
693
694        value: Result[str, int] = Err(0)
695        value.err().is_some() # True
696        ```
697        """
698        return _option.Some(self._inner)
699
700    def map(self, f: F[E, U]) -> Self:
701        """Map `Result<T, E>` to `Result<U, E>` by applying a function to the `Ok` value,
702        leaving `Err` untouched.
703
704        Example
705        -------
706        ```py
707        ok: Result[str, int] = Ok("1")
708        ok.map(lambda c: int(c) + 1) # Ok(2)
709
710        err: Result[str, int] = Err(0)
711        err.map(str.upper) # Err(0)
712        ```
713        """
714        return self
715
716    def map_or(self, f: F[E, U], default: U, /) -> U:
717        """Returns the provided `default` if the contained value is `Err`,
718
719        Otherwise extracts the `Ok` value and maps it to `f()`
720
721        Example
722        -------
723        ```py
724        x: Result[str, str] = Ok("foo")
725        assert x.map_or(lambda c: len(c), 42) == 3
726
727        x: Result[str, str] = Err("bar")
728        assert x.map_or(lambda c: len(c), 42) == 42
729        ```
730        """
731        return default
732
733    def map_or_else(self, f: F[T, U], default: F[E, U], /) -> U:
734        """Maps a Result<T, E> to U by applying fallback function `default` to a contained Err value,
735        or function `f` to a contained Ok value.
736
737        Example
738        -------
739        ```py
740        x: Result[str, str] = Ok("four")
741        assert x.map_or_else(
742            lambda ok: 2 * len(ok),
743            default=lambda err: len(err)
744        ) == 8
745
746        x: Result[str, str] = Err("bar")
747        assert x.map_or_else(
748            lambda c: 2 * len(c),
749            lambda err: len(err)
750        ) == 3
751        ```
752        """
753        return default(self._inner)
754
755    def map_err(self, f: F[E, U]) -> Err[U]:
756        """Maps a `Result[T, E]` to `Result[T, U]` by applying function `f`, leaving the `Ok` value untouched.
757
758        Example
759        -------
760        ```py
761        x: Result[str, int] = Ok("blue")
762        x.map_err(lambda err: err + 1) # Ok("blue")
763
764        x: Result[str, int] = Err(5)
765        x.map_err(float) # Err(5.0)
766        ```
767        """
768        return Err(f(self._inner))
769
770    ##############################
771    # * Iterator constructors. * #
772    ##############################
773
774    def iter(self) -> _iter.Empty[Never]:
775        """An iterator over the possible contained value.
776
777        If `self` was `Ok`, then the iterator will yield `T`, otherwise yields nothing.
778
779        Example
780        -------
781        ```py
782        c: Result[str, int] = Ok("blue")
783        c.iter().next() == Some("blue")
784
785        c: Result[str, int] = Err(0)
786        c.iter().next() == Some(None)
787        ```
788        """
789        return _iter.Empty()
790
791    def __iter__(self) -> collections.Iterator[Never]:
792        yield from ()
793
794    #################
795    # * Overloads * #
796    #################
797
798    def __repr__(self) -> str:
799        return f"Err({self._inner!r})"
800
801    def __or__(self, other: T) -> T:
802        return other
803
804    def __invert__(self) -> Never:
805        self.unwrap()

Contains the error value of Result[..., E].

Implementations

This class implements .Result.html#variant.Err">Err in Rust.

Err(_inner: ~E)
def is_ok(self) -> Literal[False]:
473    def is_ok(self) -> typing.Literal[False]:
474        """Returns `True` if the contained value is `Ok` and `False` if it an `Err`.
475
476        Example
477        -------
478        ```py
479        value: Result[str, None] = Err(None)
480
481        assert value.is_ok() == False
482        ```
483        """
484        return False

Returns True if the contained value is Ok and False if it an Err.

Example
value: Result[str, None] = Err(None)

assert value.is_ok() == False
def is_ok_and(self, f: Callable[[~E], bool]) -> Literal[False]:
486    def is_ok_and(self, f: F[E, bool]) -> typing.Literal[False]:
487        """Returns `True` if the contained value is `Ok` and `f()` returns True.
488
489        Example
490        -------
491        ```py
492        value: Result[str, None] = Err(None)
493
494        assert value.is_ok_and(lambda inner: inner == "value")
495        # False
496        ```
497        """
498        return False

Returns True if the contained value is Ok and f() returns True.

Example
value: Result[str, None] = Err(None)

assert value.is_ok_and(lambda inner: inner == "value")
# False
def is_err(self) -> Literal[True]:
501    def is_err(self) -> typing.Literal[True]:
502        """Returns `True` if the contained value is `Err`.
503
504        Example
505        -------
506        ```py
507        value: Result[str, None] = Err(None)
508
509        assert value.is_err() == True
510        ```
511        """
512        return True

Returns True if the contained value is Err.

Example
value: Result[str, None] = Err(None)

assert value.is_err() == True
def is_err_and(self, f: Callable[[~E], bool]) -> bool:
514    def is_err_and(self, f: F[E, bool]) -> bool:
515        """Returns `True` if the contained value is `Ok` and `f()` returns True..
516
517        Example
518        -------
519        ```py
520        value: Result[str, None] = Err(None)
521
522        assert value.is_err_and(lambda err: err is None)
523        # True
524        ```
525        """
526        return f(self._inner)

Returns True if the contained value is Ok and f() returns True..

Example
value: Result[str, None] = Err(None)

assert value.is_err_and(lambda err: err is None)
# True
def expect(self, msg: str) -> Never:
532    def expect(self, msg: str) -> Never:
533        """Return the underlying value if it was `Ok`, Raising `RuntimeError`
534        if it was `Err` with `message` passed to it.
535
536        Example
537        -------
538        ```py
539        ok: Result[str, None] = Ok("owo")
540        ok.expect("err") # owo
541
542        err: Result[str, None] = Err(None)
543        err.expect("err") # RuntimeError("err")
544        ```
545        """
546        raise RuntimeError(msg) from None

Return the underlying value if it was Ok, Raising RuntimeError if it was Err with message passed to it.

Example
ok: Result[str, None] = Ok("owo")
ok.expect("err") # owo

err: Result[str, None] = Err(None)
err.expect("err") # RuntimeError("err")
def expect_err(self) -> ~E:
548    def expect_err(self) -> E:
549        """Return the `Err` if it was `Err`, panicking otherwise.
550
551
552        Example
553        -------
554        ```py
555        x: Result[str, None] = Ok("owo")
556        x.expect_err()  # RuntimeError("Called expect_err on `Ok`)
557
558        x: Result[str, None] = Err(None)
559        x.expect_err() # None
560        ```
561        """
562        return self._inner

Return the Err if it was Err, panicking otherwise.

Example
x: Result[str, None] = Ok("owo")
x.expect_err()  # RuntimeError("Called expect_err on `Ok`)

x: Result[str, None] = Err(None)
x.expect_err() # None
def unwrap(self) -> Never:
564    def unwrap(self) -> Never:
565        """Return the underlying value if it was `Ok`, Raising `RuntimeError` if it was `Err`.
566
567        Example
568        -------
569        ```py
570        ok: Result[str, None] = Ok("owo")
571        ok.unwrap() # owo
572
573        err: Result[str, None] = Err(None)
574        err.unwrap() # RuntimeError
575        ```
576        """
577        raise RuntimeError(
578            f"Called `unwrap()` on an `Err` variant: {self._inner!r}"
579        ) from None

Return the underlying value if it was Ok, Raising RuntimeError if it was Err.

Example
ok: Result[str, None] = Ok("owo")
ok.unwrap() # owo

err: Result[str, None] = Err(None)
err.unwrap() # RuntimeError
def unwrap_or(self, default: ~T, /) -> ~T:
581    def unwrap_or(self, default: T, /) -> T:
582        """Return the underlying value if it was `Ok`, returning `default` if it was `Err`.
583
584        Example
585        -------
586        ```py
587        ok: Result[str, None] = Ok("OwO")
588        ok.unwrap_or("uwu") # OwO
589
590        err: Result[str, None] = Err(None)
591        err.unwrap_or("uwu") # uwu
592        ```
593        """
594        return default

Return the underlying value if it was Ok, returning default if it was Err.

Example
ok: Result[str, None] = Ok("OwO")
ok.unwrap_or("uwu") # OwO

err: Result[str, None] = Err(None)
err.unwrap_or("uwu") # uwu
def unwrap_or_else(self, f: Callable[[~E], ~T]) -> ~T:
596    def unwrap_or_else(self, f: F[E, T]) -> T:
597        """Return the contained `Ok` value or computes it from `f()` if it was `Err`.
598
599        Example
600        -------
601        ```py
602        ok: Result[int, str] = Ok(4)
603        ok.unwrap_or_else(lambda e: 0) # 4
604
605        err: Result[int, str] = Err("word")
606        err.unwrap_or_else(lambda e: len(e)) # 4
607        ```
608        """
609        return f(self._inner)

Return the contained Ok value or computes it from f() if it was Err.

Example
ok: Result[int, str] = Ok(4)
ok.unwrap_or_else(lambda e: 0) # 4

err: Result[int, str] = Err("word")
err.unwrap_or_else(lambda e: len(e)) # 4
def unwrap_err(self) -> ~E:
611    def unwrap_err(self) -> E:
612        """Return the contained `Err` value, Raising if it was `Ok`.
613
614        Example
615        -------
616        ```py
617        ok: Result[str, None] = Ok("buh")
618        ok.unwrap_err()  # RuntimeError
619
620        err: Result[str, None] = Err(None)
621        err.unwrap_err() == None
622        # True
623        ```
624        """
625        return self._inner

Return the contained Err value, Raising if it was Ok.

Example
ok: Result[str, None] = Ok("buh")
ok.unwrap_err()  # RuntimeError

err: Result[str, None] = Err(None)
err.unwrap_err() == None
# True
def inspect(self, f: Callable[[~T], typing.Any]) -> Self:
631    def inspect(self, f: F[T, typing.Any]) -> Self:
632        """Call a function to the contained value if it was `Ok` and do nothing if it was `Err`
633
634        Example
635        -------
636        ```py
637        def sink(value: str) -> None:
638            # do something with value
639            print("Called " + value)
640
641        x: Result[str, None] = Ok("ok")
642        x.inspect(sink) # "Called ok"
643
644        x: Result[str, str] = Err("err")
645        x.inspect(sink) # None
646        ```
647        """
648        return self

Call a function to the contained value if it was Ok and do nothing if it was Err

Example
def sink(value: str) -> None:
    # do something with value
    print("Called " + value)

x: Result[str, None] = Ok("ok")
x.inspect(sink) # "Called ok"

x: Result[str, str] = Err("err")
x.inspect(sink) # None
def inspect_err(self, f: Callable[[~E], typing.Any]) -> Self:
650    def inspect_err(self, f: F[E, typing.Any]) -> Self:
651        """Call a function to the contained value if it was `Err` and do nothing if it was `Ok`
652
653        Example
654        -------
655        ```py
656        def sink(value: str) -> None:
657            # do something with value
658            print("Called " + value)
659
660        x: Result[str, None] = Ok("ok")
661        x.inspect_err(sink) # None
662
663        x: Result[str, str] = Err("err")
664        x.inspect_err(sink) # Called err
665        ```
666        """
667        f(self._inner)
668        return self

Call a function to the contained value if it was Err and do nothing if it was Ok

Example
def sink(value: str) -> None:
    # do something with value
    print("Called " + value)

x: Result[str, None] = Ok("ok")
x.inspect_err(sink) # None

x: Result[str, str] = Err("err")
x.inspect_err(sink) # Called err
def ok(self) -> 'Option[None]':
670    def ok(self) -> Option[None]:
671        """Transform `Result[T, E]` to `Option[T]`, mapping `Ok(v)` to `Some(T)` and `Err(e)` to `None`.
672
673        Example
674        -------
675        ```py
676        value: Result[str, None] = Ok("buh")
677        value.ok().is_some() # True
678
679        value: Result[str, int] = Err(0)
680        value.ok().is_none() # True
681        ```
682        """
683        return _option.NOTHING

Transform Result[T, E] to Option[T], mapping Ok(v) to Some(T) and Err(e) to None.

Example
value: Result[str, None] = Ok("buh")
value.ok().is_some() # True

value: Result[str, int] = Err(0)
value.ok().is_none() # True
def err(self) -> 'Option[E]':
685    def err(self) -> Option[E]:
686        """Transform `Result[T, E]` to `Option[E]`, mapping `Ok(v)` to `None` and `Err(e)` to `Some(e)`.
687
688        Example
689        -------
690        ```py
691        value: Result[str, None] = Ok("buh")
692        value.err().is_none() # True
693
694        value: Result[str, int] = Err(0)
695        value.err().is_some() # True
696        ```
697        """
698        return _option.Some(self._inner)

Transform Result[T, E] to Option[E], mapping Ok(v) to None and Err(e) to Some(e).

Example
value: Result[str, None] = Ok("buh")
value.err().is_none() # True

value: Result[str, int] = Err(0)
value.err().is_some() # True
def map(self, f: Callable[[~E], ~U]) -> Self:
700    def map(self, f: F[E, U]) -> Self:
701        """Map `Result<T, E>` to `Result<U, E>` by applying a function to the `Ok` value,
702        leaving `Err` untouched.
703
704        Example
705        -------
706        ```py
707        ok: Result[str, int] = Ok("1")
708        ok.map(lambda c: int(c) + 1) # Ok(2)
709
710        err: Result[str, int] = Err(0)
711        err.map(str.upper) # Err(0)
712        ```
713        """
714        return self

Map Result<T, E> to Result<U, E> by applying a function to the Ok value, leaving Err untouched.

Example
ok: Result[str, int] = Ok("1")
ok.map(lambda c: int(c) + 1) # Ok(2)

err: Result[str, int] = Err(0)
err.map(str.upper) # Err(0)
def map_or(self, f: Callable[[~E], ~U], default: ~U, /) -> ~U:
716    def map_or(self, f: F[E, U], default: U, /) -> U:
717        """Returns the provided `default` if the contained value is `Err`,
718
719        Otherwise extracts the `Ok` value and maps it to `f()`
720
721        Example
722        -------
723        ```py
724        x: Result[str, str] = Ok("foo")
725        assert x.map_or(lambda c: len(c), 42) == 3
726
727        x: Result[str, str] = Err("bar")
728        assert x.map_or(lambda c: len(c), 42) == 42
729        ```
730        """
731        return default

Returns the provided default if the contained value is Err,

Otherwise extracts the Ok value and maps it to f()

Example
x: Result[str, str] = Ok("foo")
assert x.map_or(lambda c: len(c), 42) == 3

x: Result[str, str] = Err("bar")
assert x.map_or(lambda c: len(c), 42) == 42
def map_or_else(self, f: Callable[[~T], ~U], default: Callable[[~E], ~U], /) -> ~U:
733    def map_or_else(self, f: F[T, U], default: F[E, U], /) -> U:
734        """Maps a Result<T, E> to U by applying fallback function `default` to a contained Err value,
735        or function `f` to a contained Ok value.
736
737        Example
738        -------
739        ```py
740        x: Result[str, str] = Ok("four")
741        assert x.map_or_else(
742            lambda ok: 2 * len(ok),
743            default=lambda err: len(err)
744        ) == 8
745
746        x: Result[str, str] = Err("bar")
747        assert x.map_or_else(
748            lambda c: 2 * len(c),
749            lambda err: len(err)
750        ) == 3
751        ```
752        """
753        return default(self._inner)

Maps a Result to U by applying fallback function default to a contained Err value, or function f to a contained Ok value.

Example
x: Result[str, str] = Ok("four")
assert x.map_or_else(
    lambda ok: 2 * len(ok),
    default=lambda err: len(err)
) == 8

x: Result[str, str] = Err("bar")
assert x.map_or_else(
    lambda c: 2 * len(c),
    lambda err: len(err)
) == 3
def map_err(self, f: Callable[[~E], ~U]) -> Err[~U]:
755    def map_err(self, f: F[E, U]) -> Err[U]:
756        """Maps a `Result[T, E]` to `Result[T, U]` by applying function `f`, leaving the `Ok` value untouched.
757
758        Example
759        -------
760        ```py
761        x: Result[str, int] = Ok("blue")
762        x.map_err(lambda err: err + 1) # Ok("blue")
763
764        x: Result[str, int] = Err(5)
765        x.map_err(float) # Err(5.0)
766        ```
767        """
768        return Err(f(self._inner))

Maps a Result[T, E] to Result[T, U] by applying function f, leaving the Ok value untouched.

Example
x: Result[str, int] = Ok("blue")
x.map_err(lambda err: err + 1) # Ok("blue")

x: Result[str, int] = Err(5)
x.map_err(float) # Err(5.0)
def iter(self) -> sain.iter.Empty[typing.Never]:
774    def iter(self) -> _iter.Empty[Never]:
775        """An iterator over the possible contained value.
776
777        If `self` was `Ok`, then the iterator will yield `T`, otherwise yields nothing.
778
779        Example
780        -------
781        ```py
782        c: Result[str, int] = Ok("blue")
783        c.iter().next() == Some("blue")
784
785        c: Result[str, int] = Err(0)
786        c.iter().next() == Some(None)
787        ```
788        """
789        return _iter.Empty()

An iterator over the possible contained value.

If self was Ok, then the iterator will yield T, otherwise yields nothing.

Example
c: Result[str, int] = Ok("blue")
c.iter().next() == Some("blue")

c: Result[str, int] = Err(0)
c.iter().next() == Some(None)
Result = 'Ok[T] | Err[E]'
@rustc_diagnostic_item('Vec')
@typing.final
class Vec(typing.Generic[~T]):
 70@rustc_diagnostic_item("Vec")
 71@typing.final
 72class Vec(typing.Generic[T]):
 73    """A contiguous growable alternative to builtin `list` with extra functionalities.
 74
 75    The layout of `Vec` is almost the same as `list`.
 76
 77    When initializing a vec, it will not build the underlying list until the first element gets pushed.
 78    Which saves a little bit of memory.
 79
 80    Example
 81    -------
 82    ```py
 83    names = Vec()
 84    names.push('foo')
 85    names.push('bar')
 86
 87    print(names) # ['foo', 'bar']
 88    assert names.len() == 2
 89    ```
 90
 91    Constructing
 92    ------------
 93    * `Vec()`: Create an unallocated vec, Which means the underlying list will be `None` until you start pushing into it
 94    * `Vec(other_list)`: Create a vec which points to `other_list`
 95    * `Vec((1, 2, 3))`: Create a vec with `[1, 2, 3]` pre-allocated
 96    * `Vec.with_capacity(5)`: Create a vec that can hold up to 5 elements
 97    * `from_args(1, 2, 3)`: Create a vec from arguments. This is not a classmethod
 98
 99    Iterating over `Vec`
100    -------------------
101    There're two ways to iterate over a `Vec`. The first is to normally use `for` loop.
102
103    ```py
104    for i in names:
105        print(i)
106
107    # foo
108    # bar
109    ```
110
111    The second is to use `Vec.iter`, which yields all items in this `Vec` from start to end.
112    Then the iterator gets exhausted as usual, See `sain.Iterator`.
113
114    ```py
115    iterator = names.iter()
116    for name in iterator.map(str.upper):
117        print(name)
118
119    # FOO
120    # BAR
121
122    # No more items, The actual vec is left unchanged.
123    assert iterator.next().is_none()
124    ```
125
126    ## Comparison operators
127    A `Vec` may be compared with another `Vec` or a `list`, which is what this type is built on-top of.
128    any other type will return `False`
129
130    ```py
131    vec = Vec([1, 2, 3])
132    assert vec == [1, 2, 3] # True
133    assert not vec == (1, 2, 3)
134    ```
135
136    Zero-Copy
137    ---------
138    A vec that gets initialized from a `list` will *point* to it and doesn't copy it.
139    So any element that gets appended to the list will also get pushed into the vec
140    thats pointing to it.
141
142    ```py
143    cells: list[str] = []
144    vec = Vec(cells) # This DOES NOT copy the `cells`.
145
146    cells.append("foo")
147    vec[0] == "foo"  # True
148    ```
149
150    The opposite of the above is to initialize the vec from either
151    an iterable or args, or copy the list.
152
153    ```py
154    from sain.collections import vec, Vec
155
156    # Creates a new vec and extend it with the elements.
157    from_args = vec.from_args("foo", "bar")
158
159    # inlined from another iterable.
160    from_iter = Vec(["foo", "bar"])
161
162    # Copy the list into a vec.
163    vec = Vec(cells[:])
164    cells.append("bar")
165
166    vec[1] # IndexError: "bar" doesn't exist in vec.
167    ```
168    """
169
170    __slots__ = ("_ptr", "_capacity")
171
172    @typing.overload
173    def __init__(self) -> None: ...
174
175    @typing.overload
176    def __init__(self, iterable: collections.Iterable[T]) -> None: ...
177
178    def __init__(self, iterable: collections.Iterable[T] | None = None) -> None:
179        # We won't allocate to build the list here.
180        # Instead, On first push or fist indexed set
181        # we allocate if it was None.
182        if isinstance(iterable, list):
183            # Calling `list()` on another list will copy it, So instead we just point to it.
184            self._ptr = iterable
185        elif isinstance(iterable, Vec):
186            self._ptr = iterable._ptr
187        # any other iterable that ain't a list needs to get copied into a new list.
188        else:
189            self._ptr: list[T] | None = list(iterable) if iterable else None
190
191        self._capacity: int | None = None
192
193    @classmethod
194    def with_capacity(cls, capacity: int) -> Vec[T]:
195        """Create a new `Vec` with at least the specified capacity.
196        This vec will be able to hold `capacity` elements without pushing further.
197
198        Check out `Vec.push_within_capacity` as well.
199
200        Example
201        -------
202        ```py
203        vec = Vec.with_capacity(3)
204        assert vec.len() == 0 and vec.capacity() >= 3
205
206        vec.push(1)
207        vec.push(2)
208        vec.push(3)
209        print(vec.len()) # 3
210
211        # This won't push.
212        vec.push(4)
213        ```
214        """
215        v = cls()
216        v._capacity = capacity
217        return v
218
219    def as_ref(self) -> collections.Collection[T]:
220        """Return an immutable view over this vector elements.
221
222        This will *copy* `self` elements into a new tuple.
223
224        Example
225        -------
226        ```py
227        vec = Vec((1,2,3))
228        assert vec.as_ref() == (1, 2, 3)
229        ```
230        """
231        return tuple(self)
232
233    def len(self) -> int:
234        """Return the number of elements in this vector.
235
236        Example
237        -------
238        ```py
239        vec = Vec((1,2,3))
240
241        assert vec.len() == 3
242        ```
243        """
244        return self.__len__()
245
246    def capacity(self) -> int:
247        """Return the capacity of this vector if set. 0 if not .
248
249        Example
250        -------
251        ```py
252        vec_with_cap = Vec.with_capacity(3)
253        assert vec_with_cap.capacity().unwrap() == 3
254
255        vec = Vec([1, 2, 3])
256        assert vec.capacity() == 0
257        ```
258        """
259        return 0 if self._capacity is None else self._capacity
260
261    def iter(self) -> _iter.TrustedIter[T]:
262        """Returns an iterator over this vector elements.
263
264        Example
265        -------
266        ```py
267        vec = Vec([1 ,2, 3])
268        for element in vec.iter().map(str):
269            print(element)
270        ```
271        """
272        return _iter.TrustedIter(self._ptr or ())
273
274    def is_empty(self) -> bool:
275        """Returns true if the vector contains no elements."""
276        return not self._ptr
277
278    def split_off(self, at: int) -> Vec[T]:
279        """Split the vector off at the specified position, returning a new
280        vec at the range of `[at : len]`, leaving `self` at `[at : vec_len]`.
281
282        if this vec is empty, `self` is returned unchanged.
283
284        Example
285        -------
286        ```py
287        origin = Vec((1, 2, 3, 4))
288        split = vec.split_off(2)
289
290        print(origin, split)  # [1, 2], [3, 4]
291        ```
292
293        Raises
294        ------
295        `RuntimeError`
296            This method will raise if `at` > `len(self)`
297        """
298        len_ = self.len()
299        if at > len_:
300            raise RuntimeError(
301                f"Index `at` ({at}) should be <= than len of vector ({len_}) "
302            ) from None
303
304        # Either the list is empty or uninit.
305        if not self._ptr:
306            return self
307
308        split = self[at:len_]  # split the items into a new vec.
309        del self._ptr[at:len_]  # remove the items from the original list.
310        return split
311
312    def split_first(self) -> _option.Option[tuple[T, collections.Sequence[T]]]:
313        """Split the first and rest elements of the vector, If empty, `None` is returned.
314
315        Example
316        -------
317        ```py
318        vec = Vec([1, 2, 3])
319        split = vec.split_first()
320        assert split == Some((1, [2, 3]))
321
322        vec: Vec[int] = Vec()
323        split = vec.split_first()
324        assert split.is_none()
325        ```
326        """
327        if not self._ptr:
328            return _option.NOTHING  # pyright: ignore
329
330        # optimized to only one element in the vector.
331        if self.len() == 1:
332            return _option.Some((self[0], ()))
333
334        first, *rest = self._ptr
335        return _option.Some((first, rest))
336
337    def split_last(self) -> _option.Option[tuple[T, collections.Sequence[T]]]:
338        """Split the last and rest elements of the vector, If empty, `None` is returned.
339
340        Example
341        -------
342        ```py
343        vec = Vec([1, 2, 3])
344        last, rest = vec.split_last().unwrap()
345        assert (last, rest) == [3, [1, 2]]
346        ```
347        """
348        if not self._ptr:
349            return _option.NOTHING  # pyright: ignore
350
351        # optimized to only one element in the vector.
352        if self.len() == 1:
353            return _option.Some((self[0], ()))
354
355        last = self[-1]
356        return _option.Some((last, [*self[:-1]]))
357
358    def split_at(self, mid: int) -> tuple[Vec[T], Vec[T]]:
359        """Divide `self` into two at an index.
360
361        The first will contain all elements from `[0:mid]` excluding `mid` it self.
362        and the second will contain the remaninig elements.
363
364        if `mid` > `self.len()`, Then all elements will be moved to the left,
365        returning an empty vec in right.
366
367        Example
368        -------
369        ```py
370        buffer = Vec((1, 2, 3, 4))
371        left, right = buffer.split_at(0)
372        assert left == [] and right == [1, 2, 3, 4]
373
374        left, right = buffer.split_at(2)
375        assert left == [1, 2] and right == [2, 3]
376        ```
377
378        The is roughly the implementation
379        ```py
380        self[0:mid], self[mid:]
381        ```
382        """
383        return self[0:mid], self[mid:]
384
385    def swap(self, a: int, b: int):
386        """Swap two elements in the vec.
387
388        if `a` equals to `b` then it's guaranteed that elements won't change value.
389
390        Example
391        -------
392        ```py
393        buf = Vec([1, 2, 3, 4])
394        buf.swap(0, 3)
395        assert buf == [4, 2, 3, 1]
396        ```
397
398        Raises
399        ------
400        IndexError
401            If the positions of `a` or `b` are out of index.
402        """
403        if self[a] == self[b]:
404            return
405
406        self[a], self[b] = self[b], self[a]
407
408    def swap_unchecked(self, a: int, b: int):
409        """Swap two elements in the vec. without checking if `a` == `b`.
410
411        If you care about `a` and `b` equality, see `Vec.swap`.
412
413        Example
414        -------
415        ```py
416        buf = Vec([1, 2, 3, 1])
417        buf.swap_unchecked(0, 3)
418        assert buf == [1, 2, 3, 1]
419        ```
420
421        Raises
422        ------
423        IndexError
424            If the positions of `a` or `b` are out of index.
425        """
426        self[a], self[b] = self[b], self[a]
427
428    def first(self) -> _option.Option[T]:
429        """Get the first element in this vec, returning `None` if there's none.
430
431        Example
432        -------
433        ```py
434        vec = Vec((1,2,3))
435        first = vec.first()
436        assert ~first == 1
437        ```
438        """
439        return self.get(0)
440
441    def last(self) -> _option.Option[T]:
442        """Get the last element in this vec, returning `None` if there's none.
443
444        Example
445        -------
446        ```py
447        vec = Vec([1, 2, 3, 4])
448        first = vec.last()
449        assert ~first == 4
450        ```
451        """
452        return self.get(-1)
453
454    def truncate(self, size: int) -> None:
455        """Shortens the vec, keeping the first `size` elements and dropping the rest.
456
457        Example
458        -------
459        ```py
460        vec = Vec([1,2,3])
461        vec.truncate(1)
462        assert vec == [1]
463        ```
464        """
465        if not self._ptr:
466            return
467
468        del self._ptr[size:]
469
470    def retain(self, f: collections.Callable[[T], bool]) -> None:
471        """Remove elements from this vec in-place while `f()` returns `True`.
472
473        In other words, filter this vector based on `f()`.
474
475        Example
476        -------
477        ```py
478        vec = Vec([1, 2, 3])
479        vec.retain(lambda elem: elem > 1)
480
481        assert vec == [2, 3]
482        ```
483        """
484        if not self._ptr:
485            return
486
487        for idx, e in enumerate(self._ptr):
488            if f(e):
489                del self._ptr[idx]
490
491    def swap_remove(self, item: T) -> T:
492        """Remove the first appearance of `item` from this vector and return it.
493
494        Raises
495        ------
496        * `ValueError`: if `item` is not in this vector.
497        * `MemoryError`: if this vector hasn't allocated, Aka nothing has been pushed to it.
498
499        Example
500        -------
501        ```py
502        vec = Vec(('a', 'b', 'c'))
503        element = vec.remove('a')
504        assert vec == ['b', 'c'] and element == 'a'
505        ```
506        """
507        if self._ptr is None:
508            raise MemoryError("Vec is unallocated.") from None
509
510        return self._ptr.pop(self.index(item))
511
512    def fill(self, value: T) -> None:
513        """Fill `self` with the given `value`.
514
515        Nothing happens if the vec is empty or unallocated.
516
517        Example
518        ```py
519        a = Vec([0, 1, 2, 3])
520        a.fill(0)
521        assert a == [0, 0, 0, 0]
522        ```
523        """
524        if not self._ptr:
525            return
526
527        for n, _ in enumerate(self):
528            self[n] = value
529
530    def push(self, item: T) -> None:
531        """Push an element at the end of the vector.
532
533        Example
534        -------
535        ```py
536        vec = Vec()
537        vec.push(1)
538
539        assert vec == [1]
540        ```
541        """
542        if self._capacity is not None:
543            self.push_within_capacity(item)
544            return
545
546        if self._ptr is None:
547            self._ptr = []
548
549        self._ptr.append(item)
550
551    def push_within_capacity(self, x: T) -> Result[None, T]:
552        """Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element.
553
554        Example
555        -------
556        ```py
557        vec: Vec[int] = Vec.with_capacity(3)
558        for i in range(3):
559            match vec.push_within_capacity(i):
560                case Ok(_):
561                    print("All good.")
562                case Err(elem):
563                    print("Reached max cap :< cant push", elem)
564        ```
565
566        Or you can also just call `Vec.push` and it will push if theres is sufficient capacity.
567        ```py
568        vec: Vec[int] = Vec.with_capacity(3)
569
570        vec.extend((1, 2, 3))
571        vec.push(4)
572
573        assert vec.len() == 3
574        ```
575        """
576        if self._ptr is None:
577            self._ptr = []
578
579        if self.len() == self._capacity:
580            return _result.Err(x)
581
582        self._ptr.append(x)
583        return _result.Ok(None)
584
585    def reserve(self, additional: int) -> None:
586        """Reserves capacity for at least additional more elements to be inserted in the given Vec<T>.
587
588        Example
589        -------
590        ```py
591        vec = Vec.with_capacity(3)
592        is_vip = random.choice((True, False))
593
594        for i in range(4):
595            match vec.push_within_capacity(i):
596                case Ok(_):
597                    print("All good")
598                case Err(person):
599                    # If the person is a VIP, then reserve for one more.
600                    if is_vip:
601                        vec.reserve(1)
602                        continue
603
604                    # is_vip was false.
605                    print("Can't reserve for non-VIP members...", person)
606                    break
607        ```
608        """
609        if self._capacity is not None:
610            self._capacity += additional
611
612    def shrink_to_fit(self) -> None:
613        """Shrink the capacity of this `Vec` to match its length.
614
615        If `self` is initialized with no capacity, This is a `NOP`.
616
617        Example
618        -------
619        ```py
620        s = Vec([1, 2, 3, 4])
621
622        s.reserve(100)
623        s.shrink_to_fit()
624        assert s.capacity() == 4
625        ```
626        """
627        if self._capacity is None:
628            return
629
630        # The capacity is never less than the length.
631        self._capacity = min(self.__len__(), self._capacity)
632
633    def shrink_to(self, min_capacity: int) -> None:
634        """Shrink the capacity of this `Vec` to a minimum specified capacity.
635
636        If `self` is initialized with no capacity or the current capacity is less than the lower limit,
637        This is a `NOP`.
638
639        Example
640        -------
641        ```py
642        vec = Vec.with_capacity(10)
643        vec.extend([1, 2, 3])
644        assert vec.capacity() >= 10
645        vec.shrink_to(4)
646        assert vec.capacity() >= 4
647        vec.shrink_to(0)
648        ```
649        """
650        if self._capacity is None or self._capacity <= min_capacity:
651            return
652
653        # Ensure the capacity is not reduced below the current length of the vector.
654        self._capacity = max(self.__len__(), min_capacity)
655
656    ##########################
657    # * Builtin Operations *
658    ##########################
659
660    # For people how are used to calling list.append
661    append = push
662    """An alias for `Vec.push` method."""
663
664    def get(self, index: int) -> _option.Option[T]:
665        """Get the item at the given index, or `Some[None]` if its out of bounds.
666
667        Example
668        -------
669        ```py
670        vec = Vec((1, 2, 3))
671        vec.get(0) == Some(1)
672        vec.get(3) == Some(None)
673        ```
674        """
675        try:
676            return _option.Some(self[index])
677        except IndexError:
678            return _option.NOTHING  # pyright: ignore
679
680    def insert(self, index: int, value: T) -> None:
681        """Insert an element at the position `index`.
682
683        Example
684        --------
685        ```py
686        vec = Vec((2, 3))
687        vec.insert(0, 1)
688        assert vec == [1, 2, 3]
689        ```
690        """
691        self.__setitem__(index, value)
692
693    def pop(self, index: int = -1) -> _option.Option[T]:
694        """Removes the last element from a vector and returns it, or `sain.Some(None)` if it is empty.
695
696        Example
697        -------
698        ```py
699        vec = Vec((1, 2, 3))
700        assert vec.pop() == Some(3)
701        assert vec == [1, 2]
702        ```
703        """
704        if not self._ptr:
705            return _option.NOTHING  # pyright: ignore
706
707        return _option.Some(self._ptr.pop(index))
708
709    def pop_if(self, pred: collections.Callable[[T], bool]) -> _option.Option[T]:
710        """Removes the last element from a vector and returns it if `f` returns `True`,
711        or `None` if it is empty.
712
713        Example
714        -------
715        ```py
716        vec = Vec((1, 2, 3))
717        assert vec.pop_if(lambda num: num * 2 == 6) == Some(3)
718        assert vec == [1, 2]
719        ```
720        """
721        if not self._ptr:
722            return _option.NOTHING  # pyright: ignore
723
724        if pred(self[-1]):
725            return self.pop()
726
727        return _option.NOTHING  # pyright: ignore
728
729    def dedup(self) -> None:
730        """Removes duplicate elements from `self` in-place.
731
732        Example
733        -------
734        ```py
735        vec = Vec([1, 2, 3, 3, 4, 1])
736        vec.dedup()
737        assert vec == [1, 2, 3, 4]
738        """
739
740        if not self._ptr:
741            return
742
743        seen: set[T] = set()
744        write_idx = 0
745
746        for read_idx, _ in enumerate(self._ptr):
747            if self._ptr[read_idx] not in seen:
748                seen.add(self._ptr[read_idx])
749                self._ptr[write_idx] = self._ptr[read_idx]
750                write_idx += 1
751
752        del self._ptr[write_idx:]
753
754    def remove(self, item: T) -> None:
755        """Remove the first appearance of `item` from this vector.
756
757        Example
758        -------
759        ```py
760        vec = Vec(('a', 'b', 'c'))
761        vec.remove('a')
762        assert vec == ['b', 'c']
763        ```
764        """
765        if not self._ptr:
766            return
767
768        self._ptr.remove(item)
769
770    def extend(self, iterable: collections.Iterable[T]) -> None:
771        """Extend this vector from another iterable.
772
773        Example
774        -------
775        ```py
776        vec = Vec((1, 2, 3))
777        vec.extend((4, 5, 6))
778
779        assert vec == [1, 2, 3, 4, 5, 6]
780        ```
781        """
782        if self._ptr is None:
783            self._ptr = []
784
785        self._ptr.extend(iterable)
786
787    def copy(self) -> Vec[T]:
788        """Create a vector that copies all of its elements and place it into the new one.
789
790        Example
791        -------
792        ```py
793        original = Vec((1,2,3))
794        copy = original.copy()
795        copy.push(4)
796
797        print(original) # [1, 2, 3]
798        ```
799        """
800        return Vec(self._ptr[:]) if self._ptr else Vec()
801
802    def clear(self) -> None:
803        """Clear all elements of this vector.
804
805        Example
806        -------
807        ```py
808        vec = Vec((1,2,3))
809        vec.clear()
810        assert vec.len() == 0
811        ```
812        """
813        if not self._ptr:
814            return
815
816        self._ptr.clear()
817
818    def sort(
819        self,
820        *,
821        key: collections.Callable[[T], SupportsRichComparison] | None = None,
822        reverse: bool = False,
823    ) -> None:
824        """This method sorts the list in place, using only < comparisons between items.
825
826        Example
827        -------
828        ```py
829        vec = Vec((2, 1, 3))
830        vec.sort()
831        assert vec == [1, 2, 3]
832        ```
833        """
834        if not self._ptr:
835            return
836
837        # key can be `None` here just fine, idk why pyright is complaining.
838        self._ptr.sort(key=key, reverse=reverse)  # pyright: ignore
839
840    def index(
841        self, item: T, start: typing.SupportsIndex = 0, end: int = _sys.maxsize
842    ) -> int:
843        # << Official documentation >>
844        """Return zero-based index in the vec of the first item whose value is equal to `item`.
845        Raises a ValueError if there is no such item.
846
847        Example
848        -------
849        ```py
850        vec = Vec((1, 2, 3))
851        assert vec.index(2) == 1
852        ```
853        """
854        if self._ptr is None:
855            raise ValueError from None
856
857        return self._ptr.index(item, start, end)
858
859    def count(self, item: T) -> int:
860        """Return the number of occurrences of `item` in the vec.
861
862        `0` is returned if the vector is empty or hasn't been initialized, as well if them item not found.
863
864        Example
865        --------
866        ```py
867        vec = Vec((1, 2, 3, 3))
868        assert vec.count(3) == 2
869        ```
870        """
871        if self._ptr is None:
872            return 0
873
874        return self._ptr.count(item)
875
876    def __len__(self) -> int:
877        return len(self._ptr) if self._ptr else 0
878
879    def __setitem__(self, index: int, value: T):
880        if not self._ptr:
881            raise IndexError from None
882
883        self._ptr[index] = value
884
885    @typing.overload
886    def __getitem__(self, index: slice) -> Vec[T]: ...
887
888    @typing.overload
889    def __getitem__(self, index: int) -> T: ...
890
891    def __getitem__(self, index: int | slice) -> T | Vec[T]:
892        if not self._ptr:
893            raise IndexError("Index out of range")
894
895        if isinstance(index, slice):
896            return Vec(self._ptr[index])
897
898        return self._ptr[index]
899
900    def __delitem__(self, index: int) -> None:
901        if not self._ptr:
902            return
903
904        del self._ptr[index]
905
906    def __contains__(self, element: T) -> bool:
907        return element in self._ptr if self._ptr else False
908
909    def __iter__(self) -> collections.Iterator[T]:
910        if self._ptr is None:
911            return iter(())
912
913        return self._ptr.__iter__()
914
915    def __repr__(self) -> str:
916        return _LIST_REPR if not self._ptr else repr(self._ptr)
917
918    def __eq__(self, other: object) -> bool:
919        if isinstance(other, Vec):
920            return self._ptr == other._ptr
921
922        elif isinstance(other, list):
923            return self._ptr == other
924
925        return NotImplemented
926
927    def __ne__(self, other: object) -> bool:
928        return not self.__eq__(other)
929
930    def __le__(self, other: list[T]) -> bool:
931        if not self._ptr:
932            return False
933
934        return self._ptr <= other
935
936    def __ge__(self, other: list[T]) -> bool:
937        if not self._ptr:
938            return False
939
940        return self._ptr >= other
941
942    def __lt__(self, other: list[T]) -> bool:
943        if not self._ptr:
944            return False
945
946        return self._ptr < other
947
948    def __gt__(self, other: list[T]) -> bool:
949        if not self._ptr:
950            return False
951
952        return self._ptr > other
953
954    def __bool__(self) -> bool:
955        return bool(self._ptr)

A contiguous growable alternative to builtin list with extra functionalities.

The layout of Vec is almost the same as list.

When initializing a vec, it will not build the underlying list until the first element gets pushed. Which saves a little bit of memory.

Example
names = Vec()
names.push('foo')
names.push('bar')

print(names) # ['foo', 'bar']
assert names.len() == 2
Constructing
  • Vec(): Create an unallocated vec, Which means the underlying list will be None until you start pushing into it
  • Vec(other_list): Create a vec which points to other_list
  • Vec((1, 2, 3)): Create a vec with [1, 2, 3] pre-allocated
  • Vec.with_capacity(5): Create a vec that can hold up to 5 elements
  • from_args(1, 2, 3): Create a vec from arguments. This is not a classmethod

Iterating over Vec

There're two ways to iterate over a Vec. The first is to normally use for loop.

for i in names:
    print(i)

# foo
# bar

The second is to use Vec.iter, which yields all items in this Vec from start to end. Then the iterator gets exhausted as usual, See sain.Iterator.

iterator = names.iter()
for name in iterator.map(str.upper):
    print(name)

# FOO
# BAR

# No more items, The actual vec is left unchanged.
assert iterator.next().is_none()

Comparison operators

A Vec may be compared with another Vec or a list, which is what this type is built on-top of. any other type will return False

vec = Vec([1, 2, 3])
assert vec == [1, 2, 3] # True
assert not vec == (1, 2, 3)

Zero-Copy

A vec that gets initialized from a list will point to it and doesn't copy it. So any element that gets appended to the list will also get pushed into the vec thats pointing to it.

cells: list[str] = []
vec = Vec(cells) # This DOES NOT copy the `cells`.

cells.append("foo")
vec[0] == "foo"  # True

The opposite of the above is to initialize the vec from either an iterable or args, or copy the list.

from sain.collections import vec, Vec

# Creates a new vec and extend it with the elements.
from_args = vec.from_args("foo", "bar")

# inlined from another iterable.
from_iter = Vec(["foo", "bar"])

# Copy the list into a vec.
vec = Vec(cells[:])
cells.append("bar")

vec[1] # IndexError: "bar" doesn't exist in vec.

Implementations

This class implements Vec in Rust.

Vec(iterable: Iterable[~T] | None = None)
178    def __init__(self, iterable: collections.Iterable[T] | None = None) -> None:
179        # We won't allocate to build the list here.
180        # Instead, On first push or fist indexed set
181        # we allocate if it was None.
182        if isinstance(iterable, list):
183            # Calling `list()` on another list will copy it, So instead we just point to it.
184            self._ptr = iterable
185        elif isinstance(iterable, Vec):
186            self._ptr = iterable._ptr
187        # any other iterable that ain't a list needs to get copied into a new list.
188        else:
189            self._ptr: list[T] | None = list(iterable) if iterable else None
190
191        self._capacity: int | None = None
@classmethod
def with_capacity(cls, capacity: int) -> Vec[~T]:
193    @classmethod
194    def with_capacity(cls, capacity: int) -> Vec[T]:
195        """Create a new `Vec` with at least the specified capacity.
196        This vec will be able to hold `capacity` elements without pushing further.
197
198        Check out `Vec.push_within_capacity` as well.
199
200        Example
201        -------
202        ```py
203        vec = Vec.with_capacity(3)
204        assert vec.len() == 0 and vec.capacity() >= 3
205
206        vec.push(1)
207        vec.push(2)
208        vec.push(3)
209        print(vec.len()) # 3
210
211        # This won't push.
212        vec.push(4)
213        ```
214        """
215        v = cls()
216        v._capacity = capacity
217        return v

Create a new Vec with at least the specified capacity. This vec will be able to hold capacity elements without pushing further.

Check out Vec.push_within_capacity as well.

Example
vec = Vec.with_capacity(3)
assert vec.len() == 0 and vec.capacity() >= 3

vec.push(1)
vec.push(2)
vec.push(3)
print(vec.len()) # 3

# This won't push.
vec.push(4)
def as_ref(self) -> Collection[~T]:
219    def as_ref(self) -> collections.Collection[T]:
220        """Return an immutable view over this vector elements.
221
222        This will *copy* `self` elements into a new tuple.
223
224        Example
225        -------
226        ```py
227        vec = Vec((1,2,3))
228        assert vec.as_ref() == (1, 2, 3)
229        ```
230        """
231        return tuple(self)

Return an immutable view over this vector elements.

This will copy self elements into a new tuple.

Example
vec = Vec((1,2,3))
assert vec.as_ref() == (1, 2, 3)
def len(self) -> int:
233    def len(self) -> int:
234        """Return the number of elements in this vector.
235
236        Example
237        -------
238        ```py
239        vec = Vec((1,2,3))
240
241        assert vec.len() == 3
242        ```
243        """
244        return self.__len__()

Return the number of elements in this vector.

Example
vec = Vec((1,2,3))

assert vec.len() == 3
def capacity(self) -> int:
246    def capacity(self) -> int:
247        """Return the capacity of this vector if set. 0 if not .
248
249        Example
250        -------
251        ```py
252        vec_with_cap = Vec.with_capacity(3)
253        assert vec_with_cap.capacity().unwrap() == 3
254
255        vec = Vec([1, 2, 3])
256        assert vec.capacity() == 0
257        ```
258        """
259        return 0 if self._capacity is None else self._capacity

Return the capacity of this vector if set. 0 if not .

Example
vec_with_cap = Vec.with_capacity(3)
assert vec_with_cap.capacity().unwrap() == 3

vec = Vec([1, 2, 3])
assert vec.capacity() == 0
def iter(self) -> sain.iter.TrustedIter[~T]:
261    def iter(self) -> _iter.TrustedIter[T]:
262        """Returns an iterator over this vector elements.
263
264        Example
265        -------
266        ```py
267        vec = Vec([1 ,2, 3])
268        for element in vec.iter().map(str):
269            print(element)
270        ```
271        """
272        return _iter.TrustedIter(self._ptr or ())

Returns an iterator over this vector elements.

Example
vec = Vec([1 ,2, 3])
for element in vec.iter().map(str):
    print(element)
def is_empty(self) -> bool:
274    def is_empty(self) -> bool:
275        """Returns true if the vector contains no elements."""
276        return not self._ptr

Returns true if the vector contains no elements.

def split_off(self, at: int) -> Vec[~T]:
278    def split_off(self, at: int) -> Vec[T]:
279        """Split the vector off at the specified position, returning a new
280        vec at the range of `[at : len]`, leaving `self` at `[at : vec_len]`.
281
282        if this vec is empty, `self` is returned unchanged.
283
284        Example
285        -------
286        ```py
287        origin = Vec((1, 2, 3, 4))
288        split = vec.split_off(2)
289
290        print(origin, split)  # [1, 2], [3, 4]
291        ```
292
293        Raises
294        ------
295        `RuntimeError`
296            This method will raise if `at` > `len(self)`
297        """
298        len_ = self.len()
299        if at > len_:
300            raise RuntimeError(
301                f"Index `at` ({at}) should be <= than len of vector ({len_}) "
302            ) from None
303
304        # Either the list is empty or uninit.
305        if not self._ptr:
306            return self
307
308        split = self[at:len_]  # split the items into a new vec.
309        del self._ptr[at:len_]  # remove the items from the original list.
310        return split

Split the vector off at the specified position, returning a new vec at the range of [at : len], leaving self at [at : vec_len].

if this vec is empty, self is returned unchanged.

Example
origin = Vec((1, 2, 3, 4))
split = vec.split_off(2)

print(origin, split)  # [1, 2], [3, 4]
Raises
  • RuntimeError: This method will raise if at > len(self)
def split_first(self) -> '_option.Option[tuple[T, collections.Sequence[T]]]':
312    def split_first(self) -> _option.Option[tuple[T, collections.Sequence[T]]]:
313        """Split the first and rest elements of the vector, If empty, `None` is returned.
314
315        Example
316        -------
317        ```py
318        vec = Vec([1, 2, 3])
319        split = vec.split_first()
320        assert split == Some((1, [2, 3]))
321
322        vec: Vec[int] = Vec()
323        split = vec.split_first()
324        assert split.is_none()
325        ```
326        """
327        if not self._ptr:
328            return _option.NOTHING  # pyright: ignore
329
330        # optimized to only one element in the vector.
331        if self.len() == 1:
332            return _option.Some((self[0], ()))
333
334        first, *rest = self._ptr
335        return _option.Some((first, rest))

Split the first and rest elements of the vector, If empty, None is returned.

Example
vec = Vec([1, 2, 3])
split = vec.split_first()
assert split == Some((1, [2, 3]))

vec: Vec[int] = Vec()
split = vec.split_first()
assert split.is_none()
def split_last(self) -> '_option.Option[tuple[T, collections.Sequence[T]]]':
337    def split_last(self) -> _option.Option[tuple[T, collections.Sequence[T]]]:
338        """Split the last and rest elements of the vector, If empty, `None` is returned.
339
340        Example
341        -------
342        ```py
343        vec = Vec([1, 2, 3])
344        last, rest = vec.split_last().unwrap()
345        assert (last, rest) == [3, [1, 2]]
346        ```
347        """
348        if not self._ptr:
349            return _option.NOTHING  # pyright: ignore
350
351        # optimized to only one element in the vector.
352        if self.len() == 1:
353            return _option.Some((self[0], ()))
354
355        last = self[-1]
356        return _option.Some((last, [*self[:-1]]))

Split the last and rest elements of the vector, If empty, None is returned.

Example
vec = Vec([1, 2, 3])
last, rest = vec.split_last().unwrap()
assert (last, rest) == [3, [1, 2]]
def split_at( self, mid: int) -> tuple[Vec[~T], Vec[~T]]:
358    def split_at(self, mid: int) -> tuple[Vec[T], Vec[T]]:
359        """Divide `self` into two at an index.
360
361        The first will contain all elements from `[0:mid]` excluding `mid` it self.
362        and the second will contain the remaninig elements.
363
364        if `mid` > `self.len()`, Then all elements will be moved to the left,
365        returning an empty vec in right.
366
367        Example
368        -------
369        ```py
370        buffer = Vec((1, 2, 3, 4))
371        left, right = buffer.split_at(0)
372        assert left == [] and right == [1, 2, 3, 4]
373
374        left, right = buffer.split_at(2)
375        assert left == [1, 2] and right == [2, 3]
376        ```
377
378        The is roughly the implementation
379        ```py
380        self[0:mid], self[mid:]
381        ```
382        """
383        return self[0:mid], self[mid:]

Divide self into two at an index.

The first will contain all elements from [0:mid] excluding mid it self. and the second will contain the remaninig elements.

if mid > self.len(), Then all elements will be moved to the left, returning an empty vec in right.

Example
buffer = Vec((1, 2, 3, 4))
left, right = buffer.split_at(0)
assert left == [] and right == [1, 2, 3, 4]

left, right = buffer.split_at(2)
assert left == [1, 2] and right == [2, 3]

The is roughly the implementation

self[0:mid], self[mid:]
def swap(self, a: int, b: int):
385    def swap(self, a: int, b: int):
386        """Swap two elements in the vec.
387
388        if `a` equals to `b` then it's guaranteed that elements won't change value.
389
390        Example
391        -------
392        ```py
393        buf = Vec([1, 2, 3, 4])
394        buf.swap(0, 3)
395        assert buf == [4, 2, 3, 1]
396        ```
397
398        Raises
399        ------
400        IndexError
401            If the positions of `a` or `b` are out of index.
402        """
403        if self[a] == self[b]:
404            return
405
406        self[a], self[b] = self[b], self[a]

Swap two elements in the vec.

if a equals to b then it's guaranteed that elements won't change value.

Example
buf = Vec([1, 2, 3, 4])
buf.swap(0, 3)
assert buf == [4, 2, 3, 1]
Raises
  • IndexError: If the positions of a or b are out of index.
def swap_unchecked(self, a: int, b: int):
408    def swap_unchecked(self, a: int, b: int):
409        """Swap two elements in the vec. without checking if `a` == `b`.
410
411        If you care about `a` and `b` equality, see `Vec.swap`.
412
413        Example
414        -------
415        ```py
416        buf = Vec([1, 2, 3, 1])
417        buf.swap_unchecked(0, 3)
418        assert buf == [1, 2, 3, 1]
419        ```
420
421        Raises
422        ------
423        IndexError
424            If the positions of `a` or `b` are out of index.
425        """
426        self[a], self[b] = self[b], self[a]

Swap two elements in the vec. without checking if a == b.

If you care about a and b equality, see Vec.swap.

Example
buf = Vec([1, 2, 3, 1])
buf.swap_unchecked(0, 3)
assert buf == [1, 2, 3, 1]
Raises
  • IndexError: If the positions of a or b are out of index.
def first(self) -> '_option.Option[T]':
428    def first(self) -> _option.Option[T]:
429        """Get the first element in this vec, returning `None` if there's none.
430
431        Example
432        -------
433        ```py
434        vec = Vec((1,2,3))
435        first = vec.first()
436        assert ~first == 1
437        ```
438        """
439        return self.get(0)

Get the first element in this vec, returning None if there's none.

Example
vec = Vec((1,2,3))
first = vec.first()
assert ~first == 1
def last(self) -> '_option.Option[T]':
441    def last(self) -> _option.Option[T]:
442        """Get the last element in this vec, returning `None` if there's none.
443
444        Example
445        -------
446        ```py
447        vec = Vec([1, 2, 3, 4])
448        first = vec.last()
449        assert ~first == 4
450        ```
451        """
452        return self.get(-1)

Get the last element in this vec, returning None if there's none.

Example
vec = Vec([1, 2, 3, 4])
first = vec.last()
assert ~first == 4
def truncate(self, size: int) -> None:
454    def truncate(self, size: int) -> None:
455        """Shortens the vec, keeping the first `size` elements and dropping the rest.
456
457        Example
458        -------
459        ```py
460        vec = Vec([1,2,3])
461        vec.truncate(1)
462        assert vec == [1]
463        ```
464        """
465        if not self._ptr:
466            return
467
468        del self._ptr[size:]

Shortens the vec, keeping the first size elements and dropping the rest.

Example
vec = Vec([1,2,3])
vec.truncate(1)
assert vec == [1]
def retain(self, f: Callable[[~T], bool]) -> None:
470    def retain(self, f: collections.Callable[[T], bool]) -> None:
471        """Remove elements from this vec in-place while `f()` returns `True`.
472
473        In other words, filter this vector based on `f()`.
474
475        Example
476        -------
477        ```py
478        vec = Vec([1, 2, 3])
479        vec.retain(lambda elem: elem > 1)
480
481        assert vec == [2, 3]
482        ```
483        """
484        if not self._ptr:
485            return
486
487        for idx, e in enumerate(self._ptr):
488            if f(e):
489                del self._ptr[idx]

Remove elements from this vec in-place while f() returns True.

In other words, filter this vector based on f().

Example
vec = Vec([1, 2, 3])
vec.retain(lambda elem: elem > 1)

assert vec == [2, 3]
def swap_remove(self, item: ~T) -> ~T:
491    def swap_remove(self, item: T) -> T:
492        """Remove the first appearance of `item` from this vector and return it.
493
494        Raises
495        ------
496        * `ValueError`: if `item` is not in this vector.
497        * `MemoryError`: if this vector hasn't allocated, Aka nothing has been pushed to it.
498
499        Example
500        -------
501        ```py
502        vec = Vec(('a', 'b', 'c'))
503        element = vec.remove('a')
504        assert vec == ['b', 'c'] and element == 'a'
505        ```
506        """
507        if self._ptr is None:
508            raise MemoryError("Vec is unallocated.") from None
509
510        return self._ptr.pop(self.index(item))

Remove the first appearance of item from this vector and return it.

Raises
  • * ValueError (if item is not in this vector.):

  • * MemoryError (if this vector hasn't allocated, Aka nothing has been pushed to it.):

Example
vec = Vec(('a', 'b', 'c'))
element = vec.remove('a')
assert vec == ['b', 'c'] and element == 'a'
def fill(self, value: ~T) -> None:
512    def fill(self, value: T) -> None:
513        """Fill `self` with the given `value`.
514
515        Nothing happens if the vec is empty or unallocated.
516
517        Example
518        ```py
519        a = Vec([0, 1, 2, 3])
520        a.fill(0)
521        assert a == [0, 0, 0, 0]
522        ```
523        """
524        if not self._ptr:
525            return
526
527        for n, _ in enumerate(self):
528            self[n] = value

Fill self with the given value.

Nothing happens if the vec is empty or unallocated.

Example

a = Vec([0, 1, 2, 3])
a.fill(0)
assert a == [0, 0, 0, 0]
def push(self, item: ~T) -> None:
530    def push(self, item: T) -> None:
531        """Push an element at the end of the vector.
532
533        Example
534        -------
535        ```py
536        vec = Vec()
537        vec.push(1)
538
539        assert vec == [1]
540        ```
541        """
542        if self._capacity is not None:
543            self.push_within_capacity(item)
544            return
545
546        if self._ptr is None:
547            self._ptr = []
548
549        self._ptr.append(item)

Push an element at the end of the vector.

Example
vec = Vec()
vec.push(1)

assert vec == [1]
def push_within_capacity(self, x: ~T) -> 'Result[None, T]':
551    def push_within_capacity(self, x: T) -> Result[None, T]:
552        """Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element.
553
554        Example
555        -------
556        ```py
557        vec: Vec[int] = Vec.with_capacity(3)
558        for i in range(3):
559            match vec.push_within_capacity(i):
560                case Ok(_):
561                    print("All good.")
562                case Err(elem):
563                    print("Reached max cap :< cant push", elem)
564        ```
565
566        Or you can also just call `Vec.push` and it will push if theres is sufficient capacity.
567        ```py
568        vec: Vec[int] = Vec.with_capacity(3)
569
570        vec.extend((1, 2, 3))
571        vec.push(4)
572
573        assert vec.len() == 3
574        ```
575        """
576        if self._ptr is None:
577            self._ptr = []
578
579        if self.len() == self._capacity:
580            return _result.Err(x)
581
582        self._ptr.append(x)
583        return _result.Ok(None)

Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element.

Example
vec: Vec[int] = Vec.with_capacity(3)
for i in range(3):
    match vec.push_within_capacity(i):
        case Ok(_):
            print("All good.")
        case Err(elem):
            print("Reached max cap :< cant push", elem)

Or you can also just call Vec.push and it will push if theres is sufficient capacity.

vec: Vec[int] = Vec.with_capacity(3)

vec.extend((1, 2, 3))
vec.push(4)

assert vec.len() == 3
def reserve(self, additional: int) -> None:
585    def reserve(self, additional: int) -> None:
586        """Reserves capacity for at least additional more elements to be inserted in the given Vec<T>.
587
588        Example
589        -------
590        ```py
591        vec = Vec.with_capacity(3)
592        is_vip = random.choice((True, False))
593
594        for i in range(4):
595            match vec.push_within_capacity(i):
596                case Ok(_):
597                    print("All good")
598                case Err(person):
599                    # If the person is a VIP, then reserve for one more.
600                    if is_vip:
601                        vec.reserve(1)
602                        continue
603
604                    # is_vip was false.
605                    print("Can't reserve for non-VIP members...", person)
606                    break
607        ```
608        """
609        if self._capacity is not None:
610            self._capacity += additional

Reserves capacity for at least additional more elements to be inserted in the given Vec.

Example
vec = Vec.with_capacity(3)
is_vip = random.choice((True, False))

for i in range(4):
    match vec.push_within_capacity(i):
        case Ok(_):
            print("All good")
        case Err(person):
            # If the person is a VIP, then reserve for one more.
            if is_vip:
                vec.reserve(1)
                continue

            # is_vip was false.
            print("Can't reserve for non-VIP members...", person)
            break
def shrink_to_fit(self) -> None:
612    def shrink_to_fit(self) -> None:
613        """Shrink the capacity of this `Vec` to match its length.
614
615        If `self` is initialized with no capacity, This is a `NOP`.
616
617        Example
618        -------
619        ```py
620        s = Vec([1, 2, 3, 4])
621
622        s.reserve(100)
623        s.shrink_to_fit()
624        assert s.capacity() == 4
625        ```
626        """
627        if self._capacity is None:
628            return
629
630        # The capacity is never less than the length.
631        self._capacity = min(self.__len__(), self._capacity)

Shrink the capacity of this Vec to match its length.

If self is initialized with no capacity, This is a NOP.

Example
s = Vec([1, 2, 3, 4])

s.reserve(100)
s.shrink_to_fit()
assert s.capacity() == 4
def shrink_to(self, min_capacity: int) -> None:
633    def shrink_to(self, min_capacity: int) -> None:
634        """Shrink the capacity of this `Vec` to a minimum specified capacity.
635
636        If `self` is initialized with no capacity or the current capacity is less than the lower limit,
637        This is a `NOP`.
638
639        Example
640        -------
641        ```py
642        vec = Vec.with_capacity(10)
643        vec.extend([1, 2, 3])
644        assert vec.capacity() >= 10
645        vec.shrink_to(4)
646        assert vec.capacity() >= 4
647        vec.shrink_to(0)
648        ```
649        """
650        if self._capacity is None or self._capacity <= min_capacity:
651            return
652
653        # Ensure the capacity is not reduced below the current length of the vector.
654        self._capacity = max(self.__len__(), min_capacity)

Shrink the capacity of this Vec to a minimum specified capacity.

If self is initialized with no capacity or the current capacity is less than the lower limit, This is a NOP.

Example
vec = Vec.with_capacity(10)
vec.extend([1, 2, 3])
assert vec.capacity() >= 10
vec.shrink_to(4)
assert vec.capacity() >= 4
vec.shrink_to(0)
def append(self, item: ~T) -> None:
530    def push(self, item: T) -> None:
531        """Push an element at the end of the vector.
532
533        Example
534        -------
535        ```py
536        vec = Vec()
537        vec.push(1)
538
539        assert vec == [1]
540        ```
541        """
542        if self._capacity is not None:
543            self.push_within_capacity(item)
544            return
545
546        if self._ptr is None:
547            self._ptr = []
548
549        self._ptr.append(item)

An alias for Vec.push method.

def get(self, index: int) -> '_option.Option[T]':
664    def get(self, index: int) -> _option.Option[T]:
665        """Get the item at the given index, or `Some[None]` if its out of bounds.
666
667        Example
668        -------
669        ```py
670        vec = Vec((1, 2, 3))
671        vec.get(0) == Some(1)
672        vec.get(3) == Some(None)
673        ```
674        """
675        try:
676            return _option.Some(self[index])
677        except IndexError:
678            return _option.NOTHING  # pyright: ignore

Get the item at the given index, or Some[None] if its out of bounds.

Example
vec = Vec((1, 2, 3))
vec.get(0) == Some(1)
vec.get(3) == Some(None)
def insert(self, index: int, value: ~T) -> None:
680    def insert(self, index: int, value: T) -> None:
681        """Insert an element at the position `index`.
682
683        Example
684        --------
685        ```py
686        vec = Vec((2, 3))
687        vec.insert(0, 1)
688        assert vec == [1, 2, 3]
689        ```
690        """
691        self.__setitem__(index, value)

Insert an element at the position index.

Example
vec = Vec((2, 3))
vec.insert(0, 1)
assert vec == [1, 2, 3]
def pop(self, index: int = -1) -> '_option.Option[T]':
693    def pop(self, index: int = -1) -> _option.Option[T]:
694        """Removes the last element from a vector and returns it, or `sain.Some(None)` if it is empty.
695
696        Example
697        -------
698        ```py
699        vec = Vec((1, 2, 3))
700        assert vec.pop() == Some(3)
701        assert vec == [1, 2]
702        ```
703        """
704        if not self._ptr:
705            return _option.NOTHING  # pyright: ignore
706
707        return _option.Some(self._ptr.pop(index))

Removes the last element from a vector and returns it, or sain.Some(None) if it is empty.

Example
vec = Vec((1, 2, 3))
assert vec.pop() == Some(3)
assert vec == [1, 2]
def pop_if(self, pred: Callable[[~T], bool]) -> '_option.Option[T]':
709    def pop_if(self, pred: collections.Callable[[T], bool]) -> _option.Option[T]:
710        """Removes the last element from a vector and returns it if `f` returns `True`,
711        or `None` if it is empty.
712
713        Example
714        -------
715        ```py
716        vec = Vec((1, 2, 3))
717        assert vec.pop_if(lambda num: num * 2 == 6) == Some(3)
718        assert vec == [1, 2]
719        ```
720        """
721        if not self._ptr:
722            return _option.NOTHING  # pyright: ignore
723
724        if pred(self[-1]):
725            return self.pop()
726
727        return _option.NOTHING  # pyright: ignore

Removes the last element from a vector and returns it if f returns True, or None if it is empty.

Example
vec = Vec((1, 2, 3))
assert vec.pop_if(lambda num: num * 2 == 6) == Some(3)
assert vec == [1, 2]
def dedup(self) -> None:
729    def dedup(self) -> None:
730        """Removes duplicate elements from `self` in-place.
731
732        Example
733        -------
734        ```py
735        vec = Vec([1, 2, 3, 3, 4, 1])
736        vec.dedup()
737        assert vec == [1, 2, 3, 4]
738        """
739
740        if not self._ptr:
741            return
742
743        seen: set[T] = set()
744        write_idx = 0
745
746        for read_idx, _ in enumerate(self._ptr):
747            if self._ptr[read_idx] not in seen:
748                seen.add(self._ptr[read_idx])
749                self._ptr[write_idx] = self._ptr[read_idx]
750                write_idx += 1
751
752        del self._ptr[write_idx:]

Removes duplicate elements from self in-place.

Example

```py vec = Vec([1, 2, 3, 3, 4, 1]) vec.dedup() assert vec == [1, 2, 3, 4]

def remove(self, item: ~T) -> None:
754    def remove(self, item: T) -> None:
755        """Remove the first appearance of `item` from this vector.
756
757        Example
758        -------
759        ```py
760        vec = Vec(('a', 'b', 'c'))
761        vec.remove('a')
762        assert vec == ['b', 'c']
763        ```
764        """
765        if not self._ptr:
766            return
767
768        self._ptr.remove(item)

Remove the first appearance of item from this vector.

Example
vec = Vec(('a', 'b', 'c'))
vec.remove('a')
assert vec == ['b', 'c']
def extend(self, iterable: Iterable[~T]) -> None:
770    def extend(self, iterable: collections.Iterable[T]) -> None:
771        """Extend this vector from another iterable.
772
773        Example
774        -------
775        ```py
776        vec = Vec((1, 2, 3))
777        vec.extend((4, 5, 6))
778
779        assert vec == [1, 2, 3, 4, 5, 6]
780        ```
781        """
782        if self._ptr is None:
783            self._ptr = []
784
785        self._ptr.extend(iterable)

Extend this vector from another iterable.

Example
vec = Vec((1, 2, 3))
vec.extend((4, 5, 6))

assert vec == [1, 2, 3, 4, 5, 6]
def copy(self) -> Vec[~T]:
787    def copy(self) -> Vec[T]:
788        """Create a vector that copies all of its elements and place it into the new one.
789
790        Example
791        -------
792        ```py
793        original = Vec((1,2,3))
794        copy = original.copy()
795        copy.push(4)
796
797        print(original) # [1, 2, 3]
798        ```
799        """
800        return Vec(self._ptr[:]) if self._ptr else Vec()

Create a vector that copies all of its elements and place it into the new one.

Example
original = Vec((1,2,3))
copy = original.copy()
copy.push(4)

print(original) # [1, 2, 3]
def clear(self) -> None:
802    def clear(self) -> None:
803        """Clear all elements of this vector.
804
805        Example
806        -------
807        ```py
808        vec = Vec((1,2,3))
809        vec.clear()
810        assert vec.len() == 0
811        ```
812        """
813        if not self._ptr:
814            return
815
816        self._ptr.clear()

Clear all elements of this vector.

Example
vec = Vec((1,2,3))
vec.clear()
assert vec.len() == 0
def sort( self, *, key: 'collections.Callable[[T], SupportsRichComparison] | None' = None, reverse: bool = False) -> None:
818    def sort(
819        self,
820        *,
821        key: collections.Callable[[T], SupportsRichComparison] | None = None,
822        reverse: bool = False,
823    ) -> None:
824        """This method sorts the list in place, using only < comparisons between items.
825
826        Example
827        -------
828        ```py
829        vec = Vec((2, 1, 3))
830        vec.sort()
831        assert vec == [1, 2, 3]
832        ```
833        """
834        if not self._ptr:
835            return
836
837        # key can be `None` here just fine, idk why pyright is complaining.
838        self._ptr.sort(key=key, reverse=reverse)  # pyright: ignore

This method sorts the list in place, using only < comparisons between items.

Example
vec = Vec((2, 1, 3))
vec.sort()
assert vec == [1, 2, 3]
def index( self, item: ~T, start: <class 'SupportsIndex'> = 0, end: int = 9223372036854775807) -> int:
840    def index(
841        self, item: T, start: typing.SupportsIndex = 0, end: int = _sys.maxsize
842    ) -> int:
843        # << Official documentation >>
844        """Return zero-based index in the vec of the first item whose value is equal to `item`.
845        Raises a ValueError if there is no such item.
846
847        Example
848        -------
849        ```py
850        vec = Vec((1, 2, 3))
851        assert vec.index(2) == 1
852        ```
853        """
854        if self._ptr is None:
855            raise ValueError from None
856
857        return self._ptr.index(item, start, end)

Return zero-based index in the vec of the first item whose value is equal to item. Raises a ValueError if there is no such item.

Example
vec = Vec((1, 2, 3))
assert vec.index(2) == 1
def count(self, item: ~T) -> int:
859    def count(self, item: T) -> int:
860        """Return the number of occurrences of `item` in the vec.
861
862        `0` is returned if the vector is empty or hasn't been initialized, as well if them item not found.
863
864        Example
865        --------
866        ```py
867        vec = Vec((1, 2, 3, 3))
868        assert vec.count(3) == 2
869        ```
870        """
871        if self._ptr is None:
872            return 0
873
874        return self._ptr.count(item)

Return the number of occurrences of item in the vec.

0 is returned if the vector is empty or hasn't been initialized, as well if them item not found.

Example
vec = Vec((1, 2, 3, 3))
assert vec.count(3) == 2
@rustc_diagnostic_item('Error')
@typing.runtime_checkable
class Error(sain.ToString, typing.Protocol):
 68@rustc_diagnostic_item("Error")
 69@typing.runtime_checkable
 70class Error(ToString, typing.Protocol):
 71    """`Error` is an interface usually used for values that returns `sain.Result[T, E]`
 72
 73    where `E` is an implementation of this interface.
 74
 75    Example
 76    -------
 77    ```py
 78    import requests
 79    from dataclasses import dataclass
 80
 81    from sain import Error, Option, Some
 82    from sain import Result, Ok, Err
 83
 84    # Base error.
 85    class HTTPError(Error): ...
 86
 87    @dataclass
 88    class NotFound(HTTPError):
 89        message = "The response returned [404]: not found."
 90        http_status = 404
 91        response: requests.Response
 92
 93        def description(self) -> str:
 94            return "Couldn't find what you're looking for " + self.response.url
 95
 96        # It is not necessary to define this method,
 97        # it just gives more context to the user handling this error.
 98        def source(self) -> Option[type[HTTPError]]:
 99            return Some(HTTPError)
100
101    @dataclass
102    class UserNotFound(NotFound):
103        user_id: int
104
105        def __post_init__(self) -> None:
106            request = self.response.request
107            self.message = f"User {self.user_id} fetched from {request.path_url} was not found."
108
109        # It is not necessary to define this method,
110        # it just gives more context to the user handling this error.
111        def source(self) -> Option[type[NotFound]]:
112            return Some(NotFound)
113
114        def description(self) -> str:
115            return f"Couldn't find the resource: {self.response.raw}."
116
117    # A simple request that handles [404] responses.
118    def request(
119        url: str,
120        resourceful: bool = False,
121        uid: int
122    ) -> Result[requests.Response, HTTPError]:
123        response = requests.get(
124            url,
125            json={"resourceful": True, "user_id": uid}
126            if resourceful else None
127        )
128
129        if response.status_code == 404:
130            if resourceful:
131                return Err(UserNotFound(response, uid))
132            return Err(NotFound(response))
133
134        return Ok(response)
135
136    # Execute the request
137    match request("some-url.com', True, uid=0):
138        case Ok(response):
139            # Deal with the response
140            ...
141        case Err(why):
142            # Deal with the error.
143            print(why.message)
144    ```
145    """
146
147    __slots__ = ("message",)
148
149    def __init__(self, message: str = "") -> None:
150        self.message = message
151        """A basic error message."""
152
153    def source(self) -> Option[type[Error]]:
154        """The source of this error, if any."""
155        return _option.NOTHING  # pyright: ignore
156
157    def description(self) -> str:
158        """Context for this error."""
159        return ""
160
161    def to_string(self) -> str:
162        return self.__repr__()
163
164    def __repr__(self) -> str:
165        source = None if (src := self.source()).is_none() else src
166        return (
167            f'{type(self).__qualname__}(message: "{self.message}, source: {source!r})'
168        )
169
170    def __str__(self) -> str:
171        return self.message
172
173    # An error is always falsy.
174    def __bool__(self) -> typing.Literal[False]:
175        return False

Error is an interface usually used for values that returns sain.Result[T, E]

where E is an implementation of this interface.

Example
import requests
from dataclasses import dataclass

from sain import Error, Option, Some
from sain import Result, Ok, Err

# Base error.
class HTTPError(Error): ...

@dataclass
class NotFound(HTTPError):
    message = "The response returned [404]: not found."
    http_status = 404
    response: requests.Response

    def description(self) -> str:
        return "Couldn't find what you're looking for " + self.response.url

    # It is not necessary to define this method,
    # it just gives more context to the user handling this error.
    def source(self) -> Option[type[HTTPError]]:
        return Some(HTTPError)

@dataclass
class UserNotFound(NotFound):
    user_id: int

    def __post_init__(self) -> None:
        request = self.response.request
        self.message = f"User {self.user_id} fetched from {request.path_url} was not found."

    # It is not necessary to define this method,
    # it just gives more context to the user handling this error.
    def source(self) -> Option[type[NotFound]]:
        return Some(NotFound)

    def description(self) -> str:
        return f"Couldn't find the resource: {self.response.raw}."

# A simple request that handles [404] responses.
def request(
    url: str,
    resourceful: bool = False,
    uid: int
) -> Result[requests.Response, HTTPError]:
    response = requests.get(
        url,
        json={"resourceful": True, "user_id": uid}
        if resourceful else None
    )

    if response.status_code == 404:
        if resourceful:
            return Err(UserNotFound(response, uid))
        return Err(NotFound(response))

    return Ok(response)

# Execute the request
match request("some-url.com', True, uid=0):
    case Ok(response):
        # Deal with the response
        ...
    case Err(why):
        # Deal with the error.
        print(why.message)

Implementations

This class implements Error in Rust.

Error(message: str = '')
149    def __init__(self, message: str = "") -> None:
150        self.message = message
151        """A basic error message."""
message

A basic error message.

def source(self) -> 'Option[type[Error]]':
153    def source(self) -> Option[type[Error]]:
154        """The source of this error, if any."""
155        return _option.NOTHING  # pyright: ignore

The source of this error, if any.

def description(self) -> str:
157    def description(self) -> str:
158        """Context for this error."""
159        return ""

Context for this error.

def to_string(self) -> str:
161    def to_string(self) -> str:
162        return self.__repr__()

Converts the given value to a str.

Example
i = 5  # assume `int` implements `ToString`
five = "5"
assert five == i.to_string()
@typing.final
class Box(typing.Generic[+T]):
 58@typing.final
 59class Box(typing.Generic[T]):
 60    """The box object for expiring data. not thread-safe.
 61
 62    A box is an object that contains a value of type `T` which expires it after the given amount of time,
 63    The box won't start expiring the data until its first access with `Box.get` method.
 64
 65    Example
 66    -------
 67    ```py
 68    # Initializing a box doesn't mean it started expiring. instead,
 69    # getting the value the first time will start the process.
 70    cache: dict[str, Box[int]] = {"sora": Box(999, timedelta(seconds=5)}
 71
 72    # first start expiring here.
 73    cache["sora"].get().unwrap()
 74    time.sleep(6)
 75    assert cache["sora"].has_expired()
 76    ```
 77    """
 78
 79    __slots__ = ("_inner", "_expire_in", "_on_expire", "_mono")
 80
 81    def __init__(self, value: T, expire_in: int | float | datetime.timedelta) -> None:
 82        if isinstance(expire_in, datetime.timedelta):
 83            expire_in = expire_in.total_seconds()
 84        else:
 85            expire_in = float(expire_in)
 86
 87        if expire_in <= 0:
 88            raise ValueError("expire_in must be more than 0 seconds.")
 89
 90        # We set the last call on the first access to the value.
 91        self._mono: float | None = None
 92        self._inner: Option[T] = option.Some(value)
 93        self._on_expire: collections.Callable[[T], typing.Any] | None = None
 94        self._expire_in = expire_in
 95
 96    @property
 97    def has_expired(self) -> bool:
 98        """Returns True if the value has expired."""
 99        # return self._mono is not None and not self._expire_in <= (
100        # time.monotonic() - self._mono
101        # )
102        return self._mono is not None and (
103            not self._mono or self._expire_in <= (time.monotonic() - self._mono)
104        )
105
106    def on_expire(self, callback: collections.Callable[[T], typing.Any]) -> Self:
107        """Set a callback that will be invoked when this value gets expired.
108
109        Both async and sync callbacks are supported.
110
111        Example
112        -------
113        ```py
114        async def sink(message: str) -> None:
115            await client.create_message(message)
116            print("Sinked", message)
117
118        box = Box("bluh", 5).on_expire(sink)
119
120        while box.get().is_some():
121            time.sleep(5)
122        ```
123        First `.get` call on an expired box, the `sink` callback will be invoked,
124        also the inner value will be set to `Some(None)`.
125
126        After 5 seconds.
127        ```py
128        assert box.get() == Some("bluh") # This last call invokes the callback.
129        # Sinked bluh
130        assert box.get().is_none()
131        ```
132        """
133        self._on_expire = callback
134        return self
135
136    def remaining(self) -> float:
137        """Returns when this box will expire in seconds.
138
139        Example
140        --------
141        ```py
142        jogo = Box("jogo", 3)
143        assert jogo.get().unwrap() == "jogo"
144
145        time.sleep(1)
146        assert jogo.remaining() == 2
147        ```
148        """
149        if not self._mono:
150            return 0.0
151
152        return math.floor(
153            (self._expire_in - (time.monotonic() - self._mono) + 1) * 0.99
154        )
155
156    def get(self) -> Option[T]:
157        """Get the contained value if it was not expired, otherwise `Some(None)` is returned.
158
159        Example
160        -------
161        ```py
162        pizza = Box("pizza", timedelta(days=1))
163
164        while not pizza.get().is_none():
165            # Do stuff with the value while its not expired.
166
167        # After 1 day.
168        assert pizza.get().is_none()
169        ```
170        """
171        if self.has_expired:
172            if self._on_expire is not None:
173                try:
174                    if asyncio.iscoroutinefunction(self._on_expire):
175                        futures.loop().run_until_complete(
176                            self._on_expire(self._inner.unwrap_unchecked())
177                        )
178                    else:
179                        self._on_expire(self._inner.unwrap_unchecked())
180                finally:
181                    self._on_expire = None
182
183            self._inner.take()
184            self._mono = None
185            # SAFETY: The value is expired, therefore we always return None.
186            return option.NOTHING  # pyright: ignore
187
188        if self._mono is None:
189            self._mono = time.monotonic()
190
191        return self._inner
192
193    def __repr__(self) -> str:
194        return f"Box(value: {self._inner}, expired: {self.has_expired})"
195
196    __str__ = __repr__
197
198    def __eq__(self, value: object, /) -> bool:
199        if not isinstance(value, Box):
200            return NotImplemented
201
202        return (
203            self._inner == value._inner
204            and not self.has_expired
205            and not value.has_expired
206        )
207
208    def __ne__(self, value: object, /) -> bool:
209        return not self.__eq__(value)
210
211    def __hash__(self) -> int:
212        return hash(self._inner)
213
214    def __bool__(self) -> bool:
215        return not self.has_expired

The box object for expiring data. not thread-safe.

A box is an object that contains a value of type T which expires it after the given amount of time, The box won't start expiring the data until its first access with Box.get method.

Example
# Initializing a box doesn't mean it started expiring. instead,
# getting the value the first time will start the process.
cache: dict[str, Box[int]] = {"sora": Box(999, timedelta(seconds=5)}

# first start expiring here.
cache["sora"].get().unwrap()
time.sleep(6)
assert cache["sora"].has_expired()
Box(value: +T, expire_in: int | float | datetime.timedelta)
81    def __init__(self, value: T, expire_in: int | float | datetime.timedelta) -> None:
82        if isinstance(expire_in, datetime.timedelta):
83            expire_in = expire_in.total_seconds()
84        else:
85            expire_in = float(expire_in)
86
87        if expire_in <= 0:
88            raise ValueError("expire_in must be more than 0 seconds.")
89
90        # We set the last call on the first access to the value.
91        self._mono: float | None = None
92        self._inner: Option[T] = option.Some(value)
93        self._on_expire: collections.Callable[[T], typing.Any] | None = None
94        self._expire_in = expire_in
has_expired: bool
 96    @property
 97    def has_expired(self) -> bool:
 98        """Returns True if the value has expired."""
 99        # return self._mono is not None and not self._expire_in <= (
100        # time.monotonic() - self._mono
101        # )
102        return self._mono is not None and (
103            not self._mono or self._expire_in <= (time.monotonic() - self._mono)
104        )

Returns True if the value has expired.

def on_expire(self, callback: Callable[[+T], typing.Any]) -> Self:
106    def on_expire(self, callback: collections.Callable[[T], typing.Any]) -> Self:
107        """Set a callback that will be invoked when this value gets expired.
108
109        Both async and sync callbacks are supported.
110
111        Example
112        -------
113        ```py
114        async def sink(message: str) -> None:
115            await client.create_message(message)
116            print("Sinked", message)
117
118        box = Box("bluh", 5).on_expire(sink)
119
120        while box.get().is_some():
121            time.sleep(5)
122        ```
123        First `.get` call on an expired box, the `sink` callback will be invoked,
124        also the inner value will be set to `Some(None)`.
125
126        After 5 seconds.
127        ```py
128        assert box.get() == Some("bluh") # This last call invokes the callback.
129        # Sinked bluh
130        assert box.get().is_none()
131        ```
132        """
133        self._on_expire = callback
134        return self

Set a callback that will be invoked when this value gets expired.

Both async and sync callbacks are supported.

Example
async def sink(message: str) -> None:
    await client.create_message(message)
    print("Sinked", message)

box = Box("bluh", 5).on_expire(sink)

while box.get().is_some():
    time.sleep(5)

First .get call on an expired box, the sink callback will be invoked, also the inner value will be set to Some(None).

After 5 seconds.

assert box.get() == Some("bluh") # This last call invokes the callback.
# Sinked bluh
assert box.get().is_none()
def remaining(self) -> float:
136    def remaining(self) -> float:
137        """Returns when this box will expire in seconds.
138
139        Example
140        --------
141        ```py
142        jogo = Box("jogo", 3)
143        assert jogo.get().unwrap() == "jogo"
144
145        time.sleep(1)
146        assert jogo.remaining() == 2
147        ```
148        """
149        if not self._mono:
150            return 0.0
151
152        return math.floor(
153            (self._expire_in - (time.monotonic() - self._mono) + 1) * 0.99
154        )

Returns when this box will expire in seconds.

Example
jogo = Box("jogo", 3)
assert jogo.get().unwrap() == "jogo"

time.sleep(1)
assert jogo.remaining() == 2
def get(self) -> 'Option[T]':
156    def get(self) -> Option[T]:
157        """Get the contained value if it was not expired, otherwise `Some(None)` is returned.
158
159        Example
160        -------
161        ```py
162        pizza = Box("pizza", timedelta(days=1))
163
164        while not pizza.get().is_none():
165            # Do stuff with the value while its not expired.
166
167        # After 1 day.
168        assert pizza.get().is_none()
169        ```
170        """
171        if self.has_expired:
172            if self._on_expire is not None:
173                try:
174                    if asyncio.iscoroutinefunction(self._on_expire):
175                        futures.loop().run_until_complete(
176                            self._on_expire(self._inner.unwrap_unchecked())
177                        )
178                    else:
179                        self._on_expire(self._inner.unwrap_unchecked())
180                finally:
181                    self._on_expire = None
182
183            self._inner.take()
184            self._mono = None
185            # SAFETY: The value is expired, therefore we always return None.
186            return option.NOTHING  # pyright: ignore
187
188        if self._mono is None:
189            self._mono = time.monotonic()
190
191        return self._inner

Get the contained value if it was not expired, otherwise Some(None) is returned.

Example
pizza = Box("pizza", timedelta(days=1))

while not pizza.get().is_none():
    # Do stuff with the value while its not expired.

# After 1 day.
assert pizza.get().is_none()
@rustc_diagnostic_item('From')
@typing.runtime_checkable
class From(typing.Protocol[-T_co]):
117@rustc_diagnostic_item("From")
118@typing.runtime_checkable
119class From(typing.Protocol[T_co]):
120    """Used to do value-to-value conversions while consuming the input value. It is the reciprocal of Into.
121
122    As the Rust documentation says, One should always prefer implementing From over Into
123    because implementing From automatically provides one with an implementation of Into.
124
125    But there's no such thing in Python, as it's impossible to auto-impl `Into<T>` for all types
126    that impl `From<T>`.
127
128    So for the sake of simplicity, You should implement whichever interface you want deal with,
129    Or simply, implement both as the same time.
130
131    Example
132    -------
133    ```py
134    @dataclass
135    class Id(From[str]):
136        value: int
137
138        @classmethod
139        def from_t(cls, value: str) -> Self:
140            return cls(value=int(value))
141
142    ```
143    """
144
145    __slots__ = ()
146
147    @classmethod
148    def from_t(cls, value: T_co) -> Self:
149        """Perform the conversion."""
150        raise NotImplementedError

Used to do value-to-value conversions while consuming the input value. It is the reciprocal of Into.

As the Rust documentation says, One should always prefer implementing From over Into because implementing From automatically provides one with an implementation of Into.

But there's no such thing in Python, as it's impossible to auto-impl Into<T> for all types that impl From<T>.

So for the sake of simplicity, You should implement whichever interface you want deal with, Or simply, implement both as the same time.

Example
@dataclass
class Id(From[str]):
    value: int

    @classmethod
    def from_t(cls, value: str) -> Self:
        return cls(value=int(value))

Implementations

This class implements From in Rust.

From(*args, **kwargs)
1941def _no_init_or_replace_init(self, *args, **kwargs):
1942    cls = type(self)
1943
1944    if cls._is_protocol:
1945        raise TypeError('Protocols cannot be instantiated')
1946
1947    # Already using a custom `__init__`. No need to calculate correct
1948    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1949    if cls.__init__ is not _no_init_or_replace_init:
1950        return
1951
1952    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1953    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1954    # searches for a proper new `__init__` in the MRO. The new `__init__`
1955    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1956    # instantiation of the protocol subclass will thus use the new
1957    # `__init__` and no longer call `_no_init_or_replace_init`.
1958    for base in cls.__mro__:
1959        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1960        if init is not _no_init_or_replace_init:
1961            cls.__init__ = init
1962            break
1963    else:
1964        # should not happen
1965        cls.__init__ = object.__init__
1966
1967    cls.__init__(self, *args, **kwargs)
@classmethod
def from_t(cls, value: -T_co) -> Self:
147    @classmethod
148    def from_t(cls, value: T_co) -> Self:
149        """Perform the conversion."""
150        raise NotImplementedError

Perform the conversion.

@rustc_diagnostic_item('TryFrom')
@typing.runtime_checkable
class TryFrom(typing.Protocol[-T_co, ~E]):
153@rustc_diagnostic_item("TryFrom")
154@typing.runtime_checkable
155class TryFrom(typing.Protocol[T_co, E]):
156    """Simple and safe type conversions that may fail in a controlled way under some circumstances.
157    It is the reciprocal of `TryInto`.
158
159    It is useful to implement this when you know that the conversion may fail in some way.
160
161    Generic Implementations
162    -------------------
163    This interface takes two type arguments, and return `Result<Self, E>`
164
165    * `T`: Which's the first generic `T` is the type that's being converted from.
166    * `E`: If the conversion fails in a way, this is what will return as the error.
167    * `Self`: Which's the instance of the class that is being converted into.
168
169    Example
170    -------
171    ```py
172    @dataclass
173    class Id(TryFrom[str, str]):
174        value: int
175
176        @classmethod
177        def try_from(cls, value: str) -> Result[Self, str]:
178            if not value.isnumeric():
179                # NaN
180                return Err(f"Couldn't convert: {value} to self")
181            # otherwise convert it to an Id instance.
182            return Ok(value=cls(int(value)))
183    ```
184    """
185
186    __slots__ = ()
187
188    @classmethod
189    def try_from(cls, value: T_co) -> Result[Self, E]:
190        """Perform the conversion."""
191        raise NotImplementedError

Simple and safe type conversions that may fail in a controlled way under some circumstances. It is the reciprocal of TryInto.

It is useful to implement this when you know that the conversion may fail in some way.

Generic Implementations

This interface takes two type arguments, and return Result<Self, E>

  • T: Which's the first generic T is the type that's being converted from.
  • E: If the conversion fails in a way, this is what will return as the error.
  • Self: Which's the instance of the class that is being converted into.
Example
@dataclass
class Id(TryFrom[str, str]):
    value: int

    @classmethod
    def try_from(cls, value: str) -> Result[Self, str]:
        if not value.isnumeric():
            # NaN
            return Err(f"Couldn't convert: {value} to self")
        # otherwise convert it to an Id instance.
        return Ok(value=cls(int(value)))

Implementations

This class implements TryFrom in Rust.

TryFrom(*args, **kwargs)
1941def _no_init_or_replace_init(self, *args, **kwargs):
1942    cls = type(self)
1943
1944    if cls._is_protocol:
1945        raise TypeError('Protocols cannot be instantiated')
1946
1947    # Already using a custom `__init__`. No need to calculate correct
1948    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1949    if cls.__init__ is not _no_init_or_replace_init:
1950        return
1951
1952    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1953    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1954    # searches for a proper new `__init__` in the MRO. The new `__init__`
1955    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1956    # instantiation of the protocol subclass will thus use the new
1957    # `__init__` and no longer call `_no_init_or_replace_init`.
1958    for base in cls.__mro__:
1959        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1960        if init is not _no_init_or_replace_init:
1961            cls.__init__ = init
1962            break
1963    else:
1964        # should not happen
1965        cls.__init__ = object.__init__
1966
1967    cls.__init__(self, *args, **kwargs)
@classmethod
def try_from(cls, value: -T_co) -> 'Result[Self, E]':
188    @classmethod
189    def try_from(cls, value: T_co) -> Result[Self, E]:
190        """Perform the conversion."""
191        raise NotImplementedError

Perform the conversion.

@rustc_diagnostic_item('TryFrom')
@typing.runtime_checkable
class Into(typing.Protocol[+T_cov]):
194@rustc_diagnostic_item("TryFrom")
195@typing.runtime_checkable
196class Into(typing.Protocol[T_cov]):
197    """Conversion from `self`, which may or may not be expensive.
198
199    Example
200    -------
201    ```py
202    @dataclass
203    class Id(Into[str]):
204        value: int
205
206        def into(self) -> str:
207            return str(self.value)
208    ```
209    """
210
211    __slots__ = ()
212
213    def into(self) -> T_cov:
214        """Perform the conversion."""
215        raise NotImplementedError

Conversion from self, which may or may not be expensive.

Example
@dataclass
class Id(Into[str]):
    value: int

    def into(self) -> str:
        return str(self.value)

Implementations

This class implements TryFrom in Rust.

Into(*args, **kwargs)
1941def _no_init_or_replace_init(self, *args, **kwargs):
1942    cls = type(self)
1943
1944    if cls._is_protocol:
1945        raise TypeError('Protocols cannot be instantiated')
1946
1947    # Already using a custom `__init__`. No need to calculate correct
1948    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1949    if cls.__init__ is not _no_init_or_replace_init:
1950        return
1951
1952    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1953    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1954    # searches for a proper new `__init__` in the MRO. The new `__init__`
1955    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1956    # instantiation of the protocol subclass will thus use the new
1957    # `__init__` and no longer call `_no_init_or_replace_init`.
1958    for base in cls.__mro__:
1959        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1960        if init is not _no_init_or_replace_init:
1961            cls.__init__ = init
1962            break
1963    else:
1964        # should not happen
1965        cls.__init__ = object.__init__
1966
1967    cls.__init__(self, *args, **kwargs)
def into(self) -> +T_cov:
213    def into(self) -> T_cov:
214        """Perform the conversion."""
215        raise NotImplementedError

Perform the conversion.

@rustc_diagnostic_item('TryInto')
@typing.runtime_checkable
class TryInto(typing.Protocol[~T, ~E]):
218@rustc_diagnostic_item("TryInto")
219@typing.runtime_checkable
220class TryInto(typing.Protocol[T, E]):
221    """An attempted conversion from `self`, which may or may not be expensive.
222
223    It is useful to implement this when you know that the conversion may fail in some way.
224
225    Generic Implementations
226    -------------------
227    This interface takes two type arguments, and return `Result<T, E>`
228
229    * `T`: The first generic `T` is the type that's being converted into.
230    * `E`: If the conversion fails in a way, this is what will return as the error.
231
232    Example
233    -------
234    ```py
235    @dataclass
236    class Id(TryInto[int, str]):
237        value: str
238
239        def try_into(self) -> Result[int, str]:
240            if not self.value.isnumeric():
241                return Err(f"{self.value} is not a number...")
242            return Ok(int(self.value))
243    ```
244    """
245
246    __slots__ = ()
247
248    def try_into(self) -> Result[T, E]:
249        """Perform the conversion."""
250        raise NotImplementedError

An attempted conversion from self, which may or may not be expensive.

It is useful to implement this when you know that the conversion may fail in some way.

Generic Implementations

This interface takes two type arguments, and return Result<T, E>

  • T: The first generic T is the type that's being converted into.
  • E: If the conversion fails in a way, this is what will return as the error.
Example
@dataclass
class Id(TryInto[int, str]):
    value: str

    def try_into(self) -> Result[int, str]:
        if not self.value.isnumeric():
            return Err(f"{self.value} is not a number...")
        return Ok(int(self.value))

Implementations

This class implements TryInto in Rust.

TryInto(*args, **kwargs)
1941def _no_init_or_replace_init(self, *args, **kwargs):
1942    cls = type(self)
1943
1944    if cls._is_protocol:
1945        raise TypeError('Protocols cannot be instantiated')
1946
1947    # Already using a custom `__init__`. No need to calculate correct
1948    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1949    if cls.__init__ is not _no_init_or_replace_init:
1950        return
1951
1952    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1953    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1954    # searches for a proper new `__init__` in the MRO. The new `__init__`
1955    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1956    # instantiation of the protocol subclass will thus use the new
1957    # `__init__` and no longer call `_no_init_or_replace_init`.
1958    for base in cls.__mro__:
1959        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1960        if init is not _no_init_or_replace_init:
1961            cls.__init__ = init
1962            break
1963    else:
1964        # should not happen
1965        cls.__init__ = object.__init__
1966
1967    cls.__init__(self, *args, **kwargs)
def try_into(self) -> 'Result[T, E]':
248    def try_into(self) -> Result[T, E]:
249        """Perform the conversion."""
250        raise NotImplementedError

Perform the conversion.

@rustc_diagnostic_item('ToString')
@typing.runtime_checkable
class ToString(typing.Protocol):
253@rustc_diagnostic_item("ToString")
254@typing.runtime_checkable
255class ToString(typing.Protocol):
256    """A trait for explicitly converting a value to a `str`.
257
258    Example
259    -------
260    ```py
261    class Value[T: bytes](ToString):
262        buffer: T
263
264        def to_string(self) -> str:
265            return self.buffer.decode("utf-8")
266    ```
267    """
268
269    __slots__ = ()
270
271    def to_string(self) -> str:
272        """Converts the given value to a `str`.
273
274        Example
275        --------
276        ```py
277        i = 5  # assume `int` implements `ToString`
278        five = "5"
279        assert five == i.to_string()
280        ```
281        """
282        raise NotImplementedError
283
284    def __str__(self) -> str:
285        return self.to_string()

A trait for explicitly converting a value to a str.

Example
class Value[T: bytes](ToString):
    buffer: T

    def to_string(self) -> str:
        return self.buffer.decode("utf-8")

Implementations

This class implements ToString in Rust.

ToString(*args, **kwargs)
1941def _no_init_or_replace_init(self, *args, **kwargs):
1942    cls = type(self)
1943
1944    if cls._is_protocol:
1945        raise TypeError('Protocols cannot be instantiated')
1946
1947    # Already using a custom `__init__`. No need to calculate correct
1948    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1949    if cls.__init__ is not _no_init_or_replace_init:
1950        return
1951
1952    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1953    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1954    # searches for a proper new `__init__` in the MRO. The new `__init__`
1955    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1956    # instantiation of the protocol subclass will thus use the new
1957    # `__init__` and no longer call `_no_init_or_replace_init`.
1958    for base in cls.__mro__:
1959        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1960        if init is not _no_init_or_replace_init:
1961            cls.__init__ = init
1962            break
1963    else:
1964        # should not happen
1965        cls.__init__ = object.__init__
1966
1967    cls.__init__(self, *args, **kwargs)
def to_string(self) -> str:
271    def to_string(self) -> str:
272        """Converts the given value to a `str`.
273
274        Example
275        --------
276        ```py
277        i = 5  # assume `int` implements `ToString`
278        five = "5"
279        assert five == i.to_string()
280        ```
281        """
282        raise NotImplementedError

Converts the given value to a str.

Example
i = 5  # assume `int` implements `ToString`
five = "5"
assert five == i.to_string()