sain.sync API documentation

# sain.sync

Synchronization primitives.

View Source

     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"""Synchronization primitives."""
    31
    32from __future__ import annotations
    33
    34__all__ = ("Lazy", "Once", "LazyFuture", "AsyncOnce")
    35
    36from .lazy import Lazy
    37from .lazy import LazyFuture
    38from .once import AsyncOnce
    39from .once import Once

@rustc_diagnostic_item('Lazy')
@typing.final
class Lazy(typing.Generic[~T]): View Source

     49@rustc_diagnostic_item("Lazy")
     50@typing.final
     51class Lazy(typing.Generic[T]):
     52    """A thread-safe value that gets lazily initialized at first access.
     53
     54    This type is thread-safe and may be called from multiple threads since this value
     55    can be initialized from multiple threads, however, any calls to `Lazy.get` will block
     56    if another thread is initializing it.
     57
     58    Example
     59    -------
     60    ```py
     61    # some expensive call that returns a `str`
     62    def expensive_string() -> str:
     63        return "hehehe"
     64
     65    STRING: Lazy[str] = Lazy(expensive_string)
     66    print(STRING.get()) # The string is built, stored in the lazy lock and returned.
     67    print(STRING.get()) # The string is retrieved from the lazy lock.
     68    ```
     69    """
     70
     71    __slots__ = ("__inner", "__lock")
     72
     73    def __init__(self, f: collections.Callable[[], T]) -> None:
     74        self.__inner: T | collections.Callable[[], T] = f
     75        self.__lock: threading.Lock | None = None
     76
     77    def get(self) -> T:
     78        """Get the value if it was initialized, otherwise initialize it and return it.
     79
     80        Its guaranteed to not block if the value has been initialized.
     81
     82        Example
     83        -------
     84        ```py
     85        # some expensive call that returns a `str`
     86        def expensive_string() -> str:
     87            return "hehehe"
     88
     89        STRING: Lazy[str] = Lazy(expensive_string)
     90        print(STRING.get()) # The string is built, stored in the lazy lock and returned.
     91        print(STRING.get()) # The string is retrieved from the lazy lock.
     92        ```
     93        """
     94        if not callable(self.__inner):
     95            # value is already initialized, no need to make a call.
     96            return self.__inner
     97
     98        if self.__lock is None:
     99            self.__lock = threading.Lock()
    100
    101        with self.__lock:
    102            # TYPE SAFETY: We know we need to call this function.
    103            self.__inner = self.__inner()  # type: ignore
    104            return self.__inner  # type: ignore
    105
    106    def __repr__(self) -> str:
    107        return f"Lazy(value: {self.__inner!r})"
    108
    109    __str__ = __repr__

A thread-safe value that gets lazily initialized at first access.

This type is thread-safe and may be called from multiple threads since this value can be initialized from multiple threads, however, any calls to `Lazy.get` will block if another thread is initializing it.

###### Example

    # some expensive call that returns a `str`
    def expensive_string() -> str:
        return "hehehe"

    STRING: Lazy[str] = Lazy(expensive_string)
    print(STRING.get()) # The string is built, stored in the lazy lock and returned.
    print(STRING.get()) # The string is retrieved from the lazy lock.

# Implementations

This class implements Lazy in Rust.

Lazy(f: Callable[[], ~T]) View Source

    73    def __init__(self, f: collections.Callable[[], T]) -> None:
    74        self.__inner: T | collections.Callable[[], T] = f
    75        self.__lock: threading.Lock | None = None

def get(self) -> ~T: View Source

     77    def get(self) -> T:
     78        """Get the value if it was initialized, otherwise initialize it and return it.
     79
     80        Its guaranteed to not block if the value has been initialized.
     81
     82        Example
     83        -------
     84        ```py
     85        # some expensive call that returns a `str`
     86        def expensive_string() -> str:
     87            return "hehehe"
     88
     89        STRING: Lazy[str] = Lazy(expensive_string)
     90        print(STRING.get()) # The string is built, stored in the lazy lock and returned.
     91        print(STRING.get()) # The string is retrieved from the lazy lock.
     92        ```
     93        """
     94        if not callable(self.__inner):
     95            # value is already initialized, no need to make a call.
     96            return self.__inner
     97
     98        if self.__lock is None:
     99            self.__lock = threading.Lock()
    100
    101        with self.__lock:
    102            # TYPE SAFETY: We know we need to call this function.
    103            self.__inner = self.__inner()  # type: ignore
    104            return self.__inner  # type: ignore

Get the value if it was initialized, otherwise initialize it and return it.

Its guaranteed to not block if the value has been initialized.

###### Example

    # some expensive call that returns a `str`
    def expensive_string() -> str:
        return "hehehe"

    STRING: Lazy[str] = Lazy(expensive_string)
    print(STRING.get()) # The string is built, stored in the lazy lock and returned.
    print(STRING.get()) # The string is retrieved from the lazy lock.

@macros.rustc_diagnostic_item('Once')
@typing.final
class Once(typing.Generic[~T]): View Source

     54@macros.rustc_diagnostic_item("Once")
     55@typing.final
     56class Once(typing.Generic[T]):
     57    """A synchronization primitive which can be written to only once.
     58
     59    Example
     60    -------
     61    ```py
     62    from sain.once import Once
     63    from uuid import uuid4, UUID
     64
     65    UUID: Once[UUID] = Once()
     66
     67    def start() -> None:
     68        assert UUID.get().is_none()
     69
     70        # First initialization.
     71        UUID.get_or(uuid4()) # some-uuid
     72
     73        # Won't set, returns the same uuid that got initialized first.
     74        UUID.get_or(uuid4()) # some-uuid
     75    ```
     76    """
     77
     78    __slots__ = ("_inner", "_lock")
     79
     80    def __init__(self) -> None:
     81        self._lock: threading.Lock | None = None
     82        self._inner: T | None = None
     83
     84    @property
     85    def is_set(self) -> bool:
     86        return self._inner is not None
     87
     88    def get(self) -> Option[T]:
     89        """Gets the stored value, returning `None` if not initialized.
     90
     91        This method will never block.
     92        """
     93        return _option.Some(self._inner) if self.is_set else _option.NOTHING
     94
     95    @macros.unsafe
     96    def get_unchecked(self) -> T:
     97        """Get the contained value without checking if it was initialized.
     98
     99        Example
    100        -------
    101        ```py
    102        cell = Once[float]()
    103        inner = cell.get_unchecked() # Undefined Behavior!!
    104
    105        # Initialize it first.
    106        cell.get_or(math.sqrt(2.0))
    107
    108        # At this point of the program,
    109        # it is guaranteed that the value is initialized.
    110        inner = cell.get_unchecked()
    111        ```
    112        """
    113        # SAFETY: The caller guarantees that the value is initialized.
    114        return self.get().unwrap_unchecked()
    115
    116    def set(self, v: T) -> _result.Result[None, T]:
    117        """Set the const value if its not set. returning `T` if its already set.
    118
    119        This method may block if another thread is trying to initialize the value.
    120        The value is guaranteed to be set, just not necessarily the one provided.
    121
    122        Example
    123        --------
    124        ```py
    125        flag = Once[bool]()
    126        # flag is empty.
    127        assert flag.get_or(True) is True.
    128
    129        # flag is not empty, so it returns the value we set first.
    130        assert flag.set(False) == Err(True)
    131        ```
    132
    133        Returns
    134        -------
    135        `sain.Result[None, T]`
    136            This cell returns `Ok(None)` if it was empty. otherwise `Err(T)` if it was full.
    137        """
    138        if self._inner is not None:
    139            return _result.Err(self._inner)
    140
    141        self._inner = self.get_or(v)
    142        self._lock = None
    143        return _result.Ok(None)
    144
    145    def clear(self) -> None:
    146        """Clear the inner value, Setting it to `None`."""
    147        self._lock = None
    148        self._inner = None
    149
    150    def get_or(self, init: T) -> T:
    151        """Get the value if it was not initialized, Otherwise set `init` value and returning it.
    152
    153        Many threads may call `get_or` concurrently with different
    154        initializing functions, but it is guaranteed that only one function
    155        will be executed.
    156
    157        Example
    158        -------
    159        ```py
    160        UUID: Once[UUID] = Once()
    161
    162        def main() -> None:
    163            assert UUID.get().is_none()
    164
    165            # First initialization.
    166            UUID.get_or(uuid4()) # some-uuid
    167
    168            # Won't set, returns the same uuid that got initialized first.
    169            UUID.get_or(uuid4()) # some-uuid
    170            ```
    171        """
    172
    173        # If the value is not empty we return it immediately.
    174        if self._inner is not None:
    175            return self._inner
    176
    177        if self._lock is None:
    178            self._lock = threading.Lock()
    179
    180        with self._lock:
    181            self._inner = init
    182            return init
    183
    184    def get_or_with(self, f: collections.Callable[..., T]) -> T:
    185        """Gets the contents of the cell, initializing it with `f` if the cell
    186        was empty.
    187
    188        Many threads may call `get_or_with` concurrently with different
    189        initializing functions, but it is guaranteed that only one function
    190        will be executed.
    191
    192        Examples
    193        --------
    194        ```py
    195        cell = Once[int]()
    196        value = cell.get_or_with(lambda: 92)
    197        assert value == 92
    198
    199        value = cell.get_or_with(lambda: 0)
    200        assert value == 92
    201        ```
    202        """
    203        # If the value is not empty we return it immediately.
    204        if self._inner is not None:
    205            return self._inner
    206
    207        if self._lock is None:
    208            self._lock = threading.Lock()
    209
    210        with self._lock:
    211            v = f()
    212            self._inner = v
    213            return v
    214
    215    def __repr__(self) -> str:
    216        if not self.is_set:
    217            return "<uninit>"
    218
    219        return f"Once(inner: {self._inner!r})"
    220
    221    __str__ = __repr__
    222
    223    def __bool__(self) -> bool:
    224        return self.is_set

A synchronization primitive which can be written to only once.

###### Example

    from sain.once import Once
    from uuid import uuid4, UUID

    UUID: Once[UUID] = Once()

    def start() -> None:
        assert UUID.get().is_none()

        # First initialization.
        UUID.get_or(uuid4()) # some-uuid

        # Won't set, returns the same uuid that got initialized first.
        UUID.get_or(uuid4()) # some-uuid

# Implementations

This class implements Once in Rust.

is_set: bool View Source

    84    @property
    85    def is_set(self) -> bool:
    86        return self._inner is not None

def get(self) -> 'Option[T]': View Source

    88    def get(self) -> Option[T]:
    89        """Gets the stored value, returning `None` if not initialized.
    90
    91        This method will never block.
    92        """
    93        return _option.Some(self._inner) if self.is_set else _option.NOTHING

Gets the stored value, returning `None` if not initialized.

This method will never block.

@macros.unsafe
def get_unchecked(self) -> ~T: View Source

     95    @macros.unsafe
     96    def get_unchecked(self) -> T:
     97        """Get the contained value without checking if it was initialized.
     98
     99        Example
    100        -------
    101        ```py
    102        cell = Once[float]()
    103        inner = cell.get_unchecked() # Undefined Behavior!!
    104
    105        # Initialize it first.
    106        cell.get_or(math.sqrt(2.0))
    107
    108        # At this point of the program,
    109        # it is guaranteed that the value is initialized.
    110        inner = cell.get_unchecked()
    111        ```
    112        """
    113        # SAFETY: The caller guarantees that the value is initialized.
    114        return self.get().unwrap_unchecked()

Get the contained value without checking if it was initialized.

###### Example

    cell = Once[float]()
    inner = cell.get_unchecked() # Undefined Behavior!!

    # Initialize it first.
    cell.get_or(math.sqrt(2.0))

    # At this point of the program,
    # it is guaranteed that the value is initialized.
    inner = cell.get_unchecked()

# Safety ⚠️

Calling this method without knowing the output is considered undefined behavior.

def set(self, v: ~T) -> '_result.Result[None, T]': View Source

    116    def set(self, v: T) -> _result.Result[None, T]:
    117        """Set the const value if its not set. returning `T` if its already set.
    118
    119        This method may block if another thread is trying to initialize the value.
    120        The value is guaranteed to be set, just not necessarily the one provided.
    121
    122        Example
    123        --------
    124        ```py
    125        flag = Once[bool]()
    126        # flag is empty.
    127        assert flag.get_or(True) is True.
    128
    129        # flag is not empty, so it returns the value we set first.
    130        assert flag.set(False) == Err(True)
    131        ```
    132
    133        Returns
    134        -------
    135        `sain.Result[None, T]`
    136            This cell returns `Ok(None)` if it was empty. otherwise `Err(T)` if it was full.
    137        """
    138        if self._inner is not None:
    139            return _result.Err(self._inner)
    140
    141        self._inner = self.get_or(v)
    142        self._lock = None
    143        return _result.Ok(None)

Set the const value if its not set. returning `T` if its already set.

This method may block if another thread is trying to initialize the value. The value is guaranteed to be set, just not necessarily the one provided.

###### Example

    flag = Once[bool]()
    # flag is empty.
    assert flag.get_or(True) is True.

    # flag is not empty, so it returns the value we set first.
    assert flag.set(False) == Err(True)

###### Returns

- `sain.Result[None, T]`: This cell returns `Ok(None)` if it was empty. otherwise `Err(T)` if it was full.

def clear(self) -> None: View Source

    145    def clear(self) -> None:
    146        """Clear the inner value, Setting it to `None`."""
    147        self._lock = None
    148        self._inner = None

Clear the inner value, Setting it to `None`.

def get_or(self, init: ~T) -> ~T: View Source

    150    def get_or(self, init: T) -> T:
    151        """Get the value if it was not initialized, Otherwise set `init` value and returning it.
    152
    153        Many threads may call `get_or` concurrently with different
    154        initializing functions, but it is guaranteed that only one function
    155        will be executed.
    156
    157        Example
    158        -------
    159        ```py
    160        UUID: Once[UUID] = Once()
    161
    162        def main() -> None:
    163            assert UUID.get().is_none()
    164
    165            # First initialization.
    166            UUID.get_or(uuid4()) # some-uuid
    167
    168            # Won't set, returns the same uuid that got initialized first.
    169            UUID.get_or(uuid4()) # some-uuid
    170            ```
    171        """
    172
    173        # If the value is not empty we return it immediately.
    174        if self._inner is not None:
    175            return self._inner
    176
    177        if self._lock is None:
    178            self._lock = threading.Lock()
    179
    180        with self._lock:
    181            self._inner = init
    182            return init

Get the value if it was not initialized, Otherwise set `init` value and returning it.

Many threads may call `get_or` concurrently with different initializing functions, but it is guaranteed that only one function will be executed.

###### Example

    UUID: Once[UUID] = Once()

    def main() -> None:
        assert UUID.get().is_none()

        # First initialization.
        UUID.get_or(uuid4()) # some-uuid

        # Won't set, returns the same uuid that got initialized first.
        UUID.get_or(uuid4()) # some-uuid

def get_or_with(self, f: Callable[..., ~T]) -> ~T: View Source

    184    def get_or_with(self, f: collections.Callable[..., T]) -> T:
    185        """Gets the contents of the cell, initializing it with `f` if the cell
    186        was empty.
    187
    188        Many threads may call `get_or_with` concurrently with different
    189        initializing functions, but it is guaranteed that only one function
    190        will be executed.
    191
    192        Examples
    193        --------
    194        ```py
    195        cell = Once[int]()
    196        value = cell.get_or_with(lambda: 92)
    197        assert value == 92
    198
    199        value = cell.get_or_with(lambda: 0)
    200        assert value == 92
    201        ```
    202        """
    203        # If the value is not empty we return it immediately.
    204        if self._inner is not None:
    205            return self._inner
    206
    207        if self._lock is None:
    208            self._lock = threading.Lock()
    209
    210        with self._lock:
    211            v = f()
    212            self._inner = v
    213            return v

Gets the contents of the cell, initializing it with `f` if the cell was empty.

Many threads may call `get_or_with` concurrently with different initializing functions, but it is guaranteed that only one function will be executed.

###### Examples

    cell = Once[int]()
    value = cell.get_or_with(lambda: 92)
    assert value == 92

    value = cell.get_or_with(lambda: 0)
    assert value == 92

@typing.final
class LazyFuture(typing.Generic[~T]): View Source

    112@typing.final
    113class LazyFuture(typing.Generic[T]):
    114    """A thread-safe value that gets lazily initialized asynchronously at first access.
    115
    116    This type is thread-safe and may be called from multiple threads since this value
    117    can be initialized from multiple threads, however, any calls to `Lazy.get` will block
    118    if another thread is initializing it.
    119
    120    Example
    121    -------
    122    ```py
    123    # some expensive call that returns a `str`
    124    async def fetch_expensive_string(filtered: bool) -> str:
    125        return "hehehe" if filtered else "whahaha"
    126
    127    STRING: LazyFuture[str] = LazyFuture(lambda: expensive_string(True))
    128    print(await STRING.get()) # The string is built, stored in the lazy lock and returned.
    129    print(await STRING.get()) # The string is retrieved from the lazy lock.
    130    ```
    131    """
    132
    133    __slots__ = ("__inner", "__lock")
    134
    135    def __init__(
    136        self,
    137        f: collections.Callable[[], collections.Coroutine[typing.Any, typing.Any, T]],
    138    ) -> None:
    139        self.__inner: (
    140            T
    141            | collections.Callable[[], collections.Coroutine[typing.Any, typing.Any, T]]
    142        ) = f
    143        self.__lock: asyncio.Lock | None = asyncio.Lock()
    144
    145    async def get(self) -> T:
    146        """Get the value if it was initialized, otherwise initialize it and return it.
    147
    148        Example
    149        -------
    150        ```py
    151        # some expensive call that returns a `str`
    152        async def fetch_expensive_string(filtered: bool) -> str:
    153            return "hehehe" if filtered else "whahaha"
    154
    155        STRING: LazyFuture[str] = LazyFuture(lambda: fetch_expensive_string(True))
    156        print(await STRING.get()) # The string is built, stored in the lazy lock and returned.
    157        print(await STRING.get()) # The string is retrieved from the lazy lock.
    158        ```
    159        """
    160        if not callable(self.__inner):
    161            # value is already initialized, no need to make a call.
    162            return self.__inner
    163
    164        if self.__lock is None:
    165            self.__lock = asyncio.Lock()
    166
    167        async with self.__lock:
    168            # calling self.__inner will make self.__inner type T
    169            v = await self.__inner()  # pyright: ignore
    170            self.__inner = v
    171            return v  # pyright: ignore
    172
    173    def __repr__(self) -> str:
    174        return f"LazyFuture(value: {self.__inner!r})"
    175
    176    __str__ = __repr__

A thread-safe value that gets lazily initialized asynchronously at first access.

This type is thread-safe and may be called from multiple threads since this value can be initialized from multiple threads, however, any calls to `Lazy.get` will block if another thread is initializing it.

###### Example

    # some expensive call that returns a `str`
    async def fetch_expensive_string(filtered: bool) -> str:
        return "hehehe" if filtered else "whahaha"

    STRING: LazyFuture[str] = LazyFuture(lambda: expensive_string(True))
    print(await STRING.get()) # The string is built, stored in the lazy lock and returned.
    print(await STRING.get()) # The string is retrieved from the lazy lock.

LazyFuture(f: Callable[[], Coroutine[typing.Any, typing.Any, ~T]]) View Source

    135    def __init__(
    136        self,
    137        f: collections.Callable[[], collections.Coroutine[typing.Any, typing.Any, T]],
    138    ) -> None:
    139        self.__inner: (
    140            T
    141            | collections.Callable[[], collections.Coroutine[typing.Any, typing.Any, T]]
    142        ) = f
    143        self.__lock: asyncio.Lock | None = asyncio.Lock()

async def get(self) -> ~T: View Source

    145    async def get(self) -> T:
    146        """Get the value if it was initialized, otherwise initialize it and return it.
    147
    148        Example
    149        -------
    150        ```py
    151        # some expensive call that returns a `str`
    152        async def fetch_expensive_string(filtered: bool) -> str:
    153            return "hehehe" if filtered else "whahaha"
    154
    155        STRING: LazyFuture[str] = LazyFuture(lambda: fetch_expensive_string(True))
    156        print(await STRING.get()) # The string is built, stored in the lazy lock and returned.
    157        print(await STRING.get()) # The string is retrieved from the lazy lock.
    158        ```
    159        """
    160        if not callable(self.__inner):
    161            # value is already initialized, no need to make a call.
    162            return self.__inner
    163
    164        if self.__lock is None:
    165            self.__lock = asyncio.Lock()
    166
    167        async with self.__lock:
    168            # calling self.__inner will make self.__inner type T
    169            v = await self.__inner()  # pyright: ignore
    170            self.__inner = v
    171            return v  # pyright: ignore

Get the value if it was initialized, otherwise initialize it and return it.

###### Example

    # some expensive call that returns a `str`
    async def fetch_expensive_string(filtered: bool) -> str:
        return "hehehe" if filtered else "whahaha"

    STRING: LazyFuture[str] = LazyFuture(lambda: fetch_expensive_string(True))
    print(await STRING.get()) # The string is built, stored in the lazy lock and returned.
    print(await STRING.get()) # The string is retrieved from the lazy lock.

@typing.final
class AsyncOnce(typing.Generic[~T]): View Source

    227@typing.final
    228class AsyncOnce(typing.Generic[T]):
    229    """A synchronization primitive which can be written to only once.
    230
    231    This is an `async` version of `Once`.
    232
    233    Example
    234    -------
    235    ```py
    236    from sain.once import Once
    237    from uuid import uuid4, UUID
    238
    239    # A global uuid
    240    UUID: AsyncOnce[UUID] = AsyncOnce()
    241
    242    async def start() -> None:
    243        assert UUID.get().is_none()
    244        # First initialization.
    245        await UUID.get_or(uuid4()) # some-uuid
    246        # Won't set, returns the same uuid that got initialized first.
    247        await UUID.get_or(uuid4()) # some-uuid
    248    ```
    249    """
    250
    251    __slots__ = ("_inner", "_lock")
    252
    253    def __init__(self) -> None:
    254        self._lock: asyncio.Lock | None = None
    255        self._inner: T | None = None
    256
    257    @property
    258    def is_set(self) -> bool:
    259        """Whether this inner value has ben initialized or not."""
    260        return self._inner is not None
    261
    262    def get(self) -> Option[T]:
    263        """Gets the stored value. `Some(None)` is returned if nothing is stored.
    264
    265        This method will never block.
    266        """
    267        return _option.Some(self._inner) if self.is_set else _option.NOTHING
    268
    269    @macros.unsafe
    270    def get_unchecked(self) -> T:
    271        """Get the contained value without checking if it was initialized.
    272
    273        Example
    274        -------
    275        ```py
    276        cell = AsyncOnce[float]()
    277        inner = cell.get_unchecked() # Undefined Behavior!!
    278
    279        # Initialize it first.
    280        cell.get_or(math.sqrt(2.0))
    281
    282        # At this point of the program,
    283        # it is guaranteed that the value is initialized.
    284        inner = cell.get_unchecked()
    285        ```
    286        """
    287        # SAFETY: The caller guarantees that the value is initialized.
    288        return self.get().unwrap_unchecked()
    289
    290    async def set(self, v: T) -> _result.Result[None, T]:
    291        """Set the const value if its not set. returning `T` if its already set.
    292
    293        if another thread is trying to initialize the value, The value is guaranteed to be set,
    294        just not necessarily the one provided.
    295
    296        Example
    297        --------
    298        ```py
    299        flag = AsyncOnce[bool]()
    300        # flag is empty.
    301        assert await flag.get_or(True) is True.
    302        # flag is not empty, so it returns the value we set first.
    303        assert await flag.set(False) == Err(True)
    304        ```
    305
    306        Returns
    307        -------
    308        `sain.Result[None, T]`
    309            This cell returns `Ok(None)` if it was empty. otherwise `Err(T)` if it was full.
    310        """
    311        if self._inner is not None:
    312            return _result.Err(self._inner)
    313
    314        self._inner = await self.get_or(v)
    315        self._lock = None
    316        return _result.Ok(None)
    317
    318    def clear(self) -> None:
    319        """Clear the inner value, Setting it to `None`."""
    320        self._lock = None
    321        self._inner = None
    322
    323    async def get_or(self, init: T) -> T:
    324        """Gets the contents of the cell, initializing it with `init` if the cell
    325        was empty.
    326
    327        Many threads may call `get_or` concurrently with different
    328        initializing functions, but it is guaranteed that only one function
    329        will be executed.
    330
    331        Examples
    332        --------
    333        ```py
    334        from sain.sync import AsyncOnce
    335
    336        cell = AsyncOnce[int]()
    337        value = await cell.get_or(92)
    338        assert value == 92
    339
    340        value = await cell.get_or(0)
    341        assert value == 92
    342        ```
    343        """
    344        # If the value is not empty we return it immediately.
    345        if self._inner is not None:
    346            return self._inner
    347
    348        if self._lock is None:
    349            self._lock = asyncio.Lock()
    350
    351        async with self._lock:
    352            self._inner = init
    353            return init
    354
    355    async def get_or_with(self, f: collections.Callable[..., T]) -> T:
    356        """Gets the contents of the cell, initializing it with `f` if the cell
    357        was empty.
    358
    359        Many threads may call `get_or_with` concurrently with different
    360        initializing functions, but it is guaranteed that only one function
    361        will be executed.
    362
    363        Examples
    364        --------
    365        ```py
    366        from sain.sync import AsyncOnce
    367
    368        cell = AsyncOnce[int]()
    369        value = await cell.get_or_with(lambda: 92)
    370        assert value == 92
    371
    372        value = await cell.get_or_init(lambda: 0)
    373        assert value == 92
    374        ```
    375        """
    376        # If the value is not empty we return it immediately.
    377        if self._inner is not None:
    378            return self._inner
    379
    380        if self._lock is None:
    381            self._lock = asyncio.Lock()
    382
    383        async with self._lock:
    384            v = f()
    385            self._inner = v
    386            return v
    387
    388    def __repr__(self) -> str:
    389        if self._inner is not None:
    390            return f"AsyncOnce(value: {self._inner})"
    391        return "<async_uninit>"
    392
    393    __str__ = __repr__
    394
    395    def __bool__(self) -> bool:
    396        return self.is_set

A synchronization primitive which can be written to only once.

This is an `async` version of `Once`.

###### Example

    from sain.once import Once
    from uuid import uuid4, UUID

    # A global uuid
    UUID: AsyncOnce[UUID] = AsyncOnce()

    async def start() -> None:
        assert UUID.get().is_none()
        # First initialization.
        await UUID.get_or(uuid4()) # some-uuid
        # Won't set, returns the same uuid that got initialized first.
        await UUID.get_or(uuid4()) # some-uuid

is_set: bool View Source

    257    @property
    258    def is_set(self) -> bool:
    259        """Whether this inner value has ben initialized or not."""
    260        return self._inner is not None

Whether this inner value has ben initialized or not.

def get(self) -> 'Option[T]': View Source

    262    def get(self) -> Option[T]:
    263        """Gets the stored value. `Some(None)` is returned if nothing is stored.
    264
    265        This method will never block.
    266        """
    267        return _option.Some(self._inner) if self.is_set else _option.NOTHING

Gets the stored value. `Some(None)` is returned if nothing is stored.

This method will never block.

@macros.unsafe
def get_unchecked(self) -> ~T: View Source

    269    @macros.unsafe
    270    def get_unchecked(self) -> T:
    271        """Get the contained value without checking if it was initialized.
    272
    273        Example
    274        -------
    275        ```py
    276        cell = AsyncOnce[float]()
    277        inner = cell.get_unchecked() # Undefined Behavior!!
    278
    279        # Initialize it first.
    280        cell.get_or(math.sqrt(2.0))
    281
    282        # At this point of the program,
    283        # it is guaranteed that the value is initialized.
    284        inner = cell.get_unchecked()
    285        ```
    286        """
    287        # SAFETY: The caller guarantees that the value is initialized.
    288        return self.get().unwrap_unchecked()

Get the contained value without checking if it was initialized.

###### Example

    cell = AsyncOnce[float]()
    inner = cell.get_unchecked() # Undefined Behavior!!

    # Initialize it first.
    cell.get_or(math.sqrt(2.0))

    # At this point of the program,
    # it is guaranteed that the value is initialized.
    inner = cell.get_unchecked()

# Safety ⚠️

Calling this method without knowing the output is considered undefined behavior.

async def set(self, v: ~T) -> '_result.Result[None, T]': View Source

    290    async def set(self, v: T) -> _result.Result[None, T]:
    291        """Set the const value if its not set. returning `T` if its already set.
    292
    293        if another thread is trying to initialize the value, The value is guaranteed to be set,
    294        just not necessarily the one provided.
    295
    296        Example
    297        --------
    298        ```py
    299        flag = AsyncOnce[bool]()
    300        # flag is empty.
    301        assert await flag.get_or(True) is True.
    302        # flag is not empty, so it returns the value we set first.
    303        assert await flag.set(False) == Err(True)
    304        ```
    305
    306        Returns
    307        -------
    308        `sain.Result[None, T]`
    309            This cell returns `Ok(None)` if it was empty. otherwise `Err(T)` if it was full.
    310        """
    311        if self._inner is not None:
    312            return _result.Err(self._inner)
    313
    314        self._inner = await self.get_or(v)
    315        self._lock = None
    316        return _result.Ok(None)

Set the const value if its not set. returning `T` if its already set.

if another thread is trying to initialize the value, The value is guaranteed to be set, just not necessarily the one provided.

###### Example

    flag = AsyncOnce[bool]()
    # flag is empty.
    assert await flag.get_or(True) is True.
    # flag is not empty, so it returns the value we set first.
    assert await flag.set(False) == Err(True)

###### Returns

- `sain.Result[None, T]`: This cell returns `Ok(None)` if it was empty. otherwise `Err(T)` if it was full.

def clear(self) -> None: View Source

    318    def clear(self) -> None:
    319        """Clear the inner value, Setting it to `None`."""
    320        self._lock = None
    321        self._inner = None

Clear the inner value, Setting it to `None`.

async def get_or(self, init: ~T) -> ~T: View Source

    323    async def get_or(self, init: T) -> T:
    324        """Gets the contents of the cell, initializing it with `init` if the cell
    325        was empty.
    326
    327        Many threads may call `get_or` concurrently with different
    328        initializing functions, but it is guaranteed that only one function
    329        will be executed.
    330
    331        Examples
    332        --------
    333        ```py
    334        from sain.sync import AsyncOnce
    335
    336        cell = AsyncOnce[int]()
    337        value = await cell.get_or(92)
    338        assert value == 92
    339
    340        value = await cell.get_or(0)
    341        assert value == 92
    342        ```
    343        """
    344        # If the value is not empty we return it immediately.
    345        if self._inner is not None:
    346            return self._inner
    347
    348        if self._lock is None:
    349            self._lock = asyncio.Lock()
    350
    351        async with self._lock:
    352            self._inner = init
    353            return init

Gets the contents of the cell, initializing it with `init` if the cell was empty.

Many threads may call `get_or` concurrently with different initializing functions, but it is guaranteed that only one function will be executed.

###### Examples

    from sain.sync import AsyncOnce

    cell = AsyncOnce[int]()
    value = await cell.get_or(92)
    assert value == 92

    value = await cell.get_or(0)
    assert value == 92

async def get_or_with(self, f: Callable[..., ~T]) -> ~T: View Source

    355    async def get_or_with(self, f: collections.Callable[..., T]) -> T:
    356        """Gets the contents of the cell, initializing it with `f` if the cell
    357        was empty.
    358
    359        Many threads may call `get_or_with` concurrently with different
    360        initializing functions, but it is guaranteed that only one function
    361        will be executed.
    362
    363        Examples
    364        --------
    365        ```py
    366        from sain.sync import AsyncOnce
    367
    368        cell = AsyncOnce[int]()
    369        value = await cell.get_or_with(lambda: 92)
    370        assert value == 92
    371
    372        value = await cell.get_or_init(lambda: 0)
    373        assert value == 92
    374        ```
    375        """
    376        # If the value is not empty we return it immediately.
    377        if self._inner is not None:
    378            return self._inner
    379
    380        if self._lock is None:
    381            self._lock = asyncio.Lock()
    382
    383        async with self._lock:
    384            v = f()
    385            self._inner = v
    386            return v

Gets the contents of the cell, initializing it with `f` if the cell was empty.

Many threads may call `get_or_with` concurrently with different initializing functions, but it is guaranteed that only one function will be executed.

###### Examples

    from sain.sync import AsyncOnce

    cell = AsyncOnce[int]()
    value = await cell.get_or_with(lambda: 92)
    assert value == 92

    value = await cell.get_or_init(lambda: 0)
    assert value == 92