sain.collections API documentation

# sain.collections

Dynamically growable collections and containers.

These collections are basic implementations of Rust's standard collections crate. from under the hood, they're an extended and more rich implementations of the built-in sequences such as `list` and `bytearray`.

### When Should You Use Which Collection?

This question's answer should be pretty straightforward.

- Use `Vec` when you want to replace `list`.
- Use `Bytes` when you want to store read-only bytes. The underlying sequence is an `array` of type `u8`.
- Use `BytesMut` when you want a mutable version of `Bytes`.
- Use `HashMap` when you want to replace `dict`.

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"""Dynamically growable collections and containers.
    31
    32These collections are basic implementations of Rust's standard collections crate. from under the hood, they're an extended
    33and more rich implementations of the built-in sequences such as `list` and `bytearray`.
    34
    35### When Should You Use Which Collection?
    36This question's answer should be pretty straightforward.
    37
    38* Use `Vec` when you want to replace `list`.
    39* Use `Bytes` when you want to store read-only bytes. The underlying sequence is an `array` of type `u8`.
    40* Use `BytesMut` when you want a mutable version of `Bytes`.
    41* Use `HashMap` when you want to replace `dict`.
    42"""
    43
    44from __future__ import annotations
    45
    46__all__ = ("Vec", "Bytes", "BytesMut", "vec", "buf", "slice", "hash_map", "HashMap")
    47
    48from . import buf
    49from . import hash_map
    50from . import slice
    51from . import vec
    52from .buf import Bytes
    53from .buf import BytesMut
    54from .hash_map import HashMap
    55from .vec import Vec

@rustc_diagnostic_item('Vec')
@typing.final
class Vec(typing.Generic[~T], collections.abc.MutableSequence[~T], sain.collections.slice.SpecContains[~T]): View Source

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

A contiguous growable alternative to builtin `list` with extra functionalities.

The layout of `Vec<T>` is exactly the same as `list<T>`. Which means `list<T>`'s methods are inherited into `Vec<T>`.

###### Example

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

    print(names) # ['foo', 'bar']
    assert names.len() == 2

###### Constructing

- `Vec()`: Create an empty vec, this will not allocate the initial buffer.
- `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(iterable)`: Create a vec from an `iterable`, This is `O(n)` where `n` is the number of elements, since it copies `iterable`'s elements into a new list.
- `Vec.with_capacity(5)`: Create a vec that can hold up to 5 elements

## 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`, any other type will return `False`

    vec = Vec([1, 2, 3])
    assert vec == [1, 2, 3] # True
    assert 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 that's pointing to it and vice-versa.

    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

    # 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) View Source

    170    def __init__(self, iterable: collections.Iterable[T] | None = None) -> None:
    171        """Create an empty `Vec<T>`.
    172
    173        The vector will not allocate until elements are pushed onto it.
    174
    175        Example
    176        ------
    177        ```py
    178        vec: Vec[float] = Vec()
    179        ```
    180        """
    181        # We won't allocate to build the list here.
    182        # Instead, On first push or fist indexed set
    183        # we allocate if it was None.
    184        if isinstance(iterable, list):
    185            # Calling `list()` on another list will copy it, So instead we just point to it.
    186            self._ptr = iterable
    187        elif isinstance(iterable, Vec):
    188            self._ptr = iterable._ptr
    189        # any other iterable that ain't a list needs to get copied into a new list.
    190        else:
    191            self._ptr: list[T] | None = list(iterable) if iterable else None
    192
    193        self._capacity: int | None = None

Create an empty `Vec<T>`.

The vector will not allocate until elements are pushed onto it.

###### Example

    vec: Vec[float] = Vec()

@classmethod
def with_capacity(cls, capacity: int) -> Vec[~T]: View Source

    195    @classmethod
    196    def with_capacity(cls, capacity: int) -> Vec[T]:
    197        """Create a new `Vec` with at least the specified capacity.
    198        This vec will be able to hold `capacity` elements without pushing further.
    199
    200        Check out `Vec.push_within_capacity` as well.
    201
    202        Example
    203        -------
    204        ```py
    205        vec = Vec.with_capacity(3)
    206        assert vec.len() == 0 and vec.capacity() >= 3
    207
    208        vec.push(1)
    209        vec.push(2)
    210        vec.push(3)
    211        print(vec.len()) # 3
    212
    213        # This won't push.
    214        vec.push(4)
    215        ```
    216        """
    217        v = cls()
    218        v._capacity = capacity
    219        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) -> sain.collections.slice.Slice[~T]: View Source

    221    def as_ref(self) -> Slice[T]:
    222        """Return an immutable view over this vector elements.
    223
    224        No copying occurs.
    225
    226        Example
    227        -------
    228        ```py
    229        def send_bytes(v: Slice[int]) -> None:
    230            # access `vec` in a read-only mode.
    231            socket.write_all(v)
    232
    233        buf = Vec([1, 2, 3])
    234        send_bytes(buf.as_ref())
    235        ```
    236        """
    237        return Slice(self)

Return an immutable view over this vector elements.

No copying occurs.

###### Example

    def send_bytes(v: Slice[int]) -> None:
        # access `vec` in a read-only mode.
        socket.write_all(v)

    buf = Vec([1, 2, 3])
    send_bytes(buf.as_ref())

def as_mut(self) -> sain.collections.slice.SliceMut[~T]: View Source

    239    def as_mut(self) -> SliceMut[T]:
    240        """Return a mutable view over this vector elements.
    241
    242        No copying occurs.
    243
    244        Example
    245        -------
    246        ```py
    247        def read_bytes(buf: SliceMut[int]) -> None:
    248            socket.read_to_end(buf.as_mut())
    249
    250        buf: Vec[int] = Vec()
    251        read_bytes(buf.as_mut()) # or just `buf`
    252        assert vec.len() >= 1
    253        ```
    254        """
    255        return SliceMut(self)

Return a mutable view over this vector elements.

No copying occurs.

###### Example

    def read_bytes(buf: SliceMut[int]) -> None:
        socket.read_to_end(buf.as_mut())

    buf: Vec[int] = Vec()
    read_bytes(buf.as_mut()) # or just `buf`
    assert vec.len() >= 1

def len(self) -> int: View Source

    257    def len(self) -> int:
    258        """Return the number of elements in this vector.
    259
    260        Example
    261        -------
    262        ```py
    263        vec = Vec((1,2,3))
    264
    265        assert vec.len() == 3
    266        ```
    267        """
    268        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: View Source

    270    def capacity(self) -> int:
    271        """Return the capacity of this vector if set, 0 if not .
    272
    273        The number `0` here has two different Meanings:
    274        - The first means the `Vec` doesn't have a specific capacity set.
    275        - The second means the `Vec` literally initialized with `0` capacity.
    276
    277        Example
    278        -------
    279        ```py
    280        vec_with_cap = Vec.with_capacity(3)
    281        assert vec_with_cap.capacity().unwrap() == 3
    282
    283        vec = Vec([1, 2, 3])
    284        assert vec.capacity() == 0
    285        ```
    286        """
    287        return 0 if self._capacity is None else self._capacity

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

The number `0` here has two different Meanings:

- The first means the `Vec` doesn't have a specific capacity set.
- The second means the `Vec` literally initialized with `0` capacity.

###### 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]: View Source

    289    def iter(self) -> _iter.TrustedIter[T]:
    290        """Returns an iterator over this vector elements.
    291
    292        Example
    293        -------
    294        ```py
    295        vec = Vec([1 ,2, 3])
    296        for element in vec.iter().map(str):
    297            print(element)
    298        ```
    299        """
    300        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: View Source

    302    def is_empty(self) -> bool:
    303        """Returns true if the vector contains no elements.
    304
    305        Inlined into:
    306        ```py
    307        not self.vec
    308        ```
    309        """
    310        return not self._ptr

Returns true if the vector contains no elements.

Inlined into:

    not self.vec

def leak(self) -> list[~T]: View Source

    312    def leak(self) -> list[T]:
    313        """Consumes and leaks the Vec, returning a mutable reference to the contents.
    314
    315        After calling this, this vec will no longer reference the underlying buffer,
    316        therefore, it becomes unusable.
    317
    318        if `self` is uninitialized, an empty list is returned.
    319
    320        This function is only useful when you want to detach from a `Vec<T>` and get a `list[T]` without
    321        any copies.
    322
    323        Example
    324        -------
    325        ```py
    326        x = Vec([1, 2, 3])
    327        owned = x.leak()
    328        # x is now unusable.
    329        owned[0] += 1
    330        assert owned == [2, 2, 3]
    331        ```
    332        """
    333        if self._ptr is not None:
    334            # don't point to `_ptr` anymore.
    335            tmp = self._ptr
    336            del self._ptr
    337            return tmp
    338
    339        return []

Consumes and leaks the Vec, returning a mutable reference to the contents.

After calling this, this vec will no longer reference the underlying buffer, therefore, it becomes unusable.

if `self` is uninitialized, an empty list is returned.

This function is only useful when you want to detach from a `Vec<T>` and get a `list[T]` without any copies.

###### Example

    x = Vec([1, 2, 3])
    owned = x.leak()
    # x is now unusable.
    owned[0] += 1
    assert owned == [2, 2, 3]

def split_off(self, at: int) -> Vec[~T]: View Source

    341    def split_off(self, at: int) -> Vec[T]:
    342        """Split the vector off at the specified position, returning a new
    343        vec at the range of `[at : len]`, leaving `self` at `[at : vec_len]`.
    344
    345        if this vec is empty, `self` is returned unchanged.
    346
    347        Example
    348        -------
    349        ```py
    350        origin = Vec((1, 2, 3, 4))
    351        split = vec.split_off(2)
    352
    353        print(origin, split)  # [1, 2], [3, 4]
    354        ```
    355
    356        Raises
    357        ------
    358        `IndexError`
    359            This method will raise if `at` > `len(self)`
    360        """
    361        len_ = self.len()
    362        if at > len_:
    363            raise IndexError(
    364                f"Index `at` ({at}) should be <= than len of vector ({len_}) "
    365            ) from None
    366
    367        # Either the list is empty or uninit.
    368        if not self._ptr:
    369            return self
    370
    371        split = self[at:len_]  # split the items into a new vec.
    372        del self._ptr[at:len_]  # remove the items from the original list.
    373        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

- `IndexError`: This method will raise if `at` > `len(self)`

def split_first(self) -> '_option.Option[tuple[T, collections.Sequence[T]]]': View Source

    375    def split_first(self) -> _option.Option[tuple[T, collections.Sequence[T]]]:
    376        """Split the first and rest elements of the vector, If empty, `None` is returned.
    377
    378        Example
    379        -------
    380        ```py
    381        vec = Vec([1, 2, 3])
    382        split = vec.split_first()
    383        assert split == Some((1, [2, 3]))
    384
    385        vec: Vec[int] = Vec()
    386        split = vec.split_first()
    387        assert split.is_none()
    388        ```
    389        """
    390        if not self._ptr:
    391            return _option.NOTHING
    392
    393        # optimized to only one element in the vector.
    394        if self.len() == 1:
    395            return _option.Some((self[0], ()))
    396
    397        first, *rest = self._ptr
    398        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]]]': View Source

    400    def split_last(self) -> _option.Option[tuple[T, collections.Sequence[T]]]:
    401        """Split the last and rest elements of the vector, If empty, `None` is returned.
    402
    403        Example
    404        -------
    405        ```py
    406        vec = Vec([1, 2, 3])
    407        last, rest = vec.split_last().unwrap()
    408        assert (last, rest) == [3, [1, 2]]
    409        ```
    410        """
    411        if not self._ptr:
    412            return _option.NOTHING
    413
    414        # optimized to only one element in the vector.
    415        if self.len() == 1:
    416            return _option.Some((self[0], ()))
    417
    418        last, *rest = self._ptr[-1], *self._ptr[:-1]
    419        return _option.Some((last, rest))

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]]: View Source

    421    def split_at(self, mid: int) -> tuple[Vec[T], Vec[T]]:
    422        """Divide `self` into two at an index.
    423
    424        The first will contain all elements from `[0:mid]` excluding `mid` it self.
    425        and the second will contain the remaining elements.
    426
    427        if `mid` > `self.len()`, Then all elements will be moved to the left,
    428        returning an empty vec in right.
    429
    430        Example
    431        -------
    432        ```py
    433        buffer = Vec((1, 2, 3, 4))
    434        left, right = buffer.split_at(0)
    435        assert left == [] and right == [1, 2, 3, 4]
    436
    437        left, right = buffer.split_at(2)
    438        assert left == [1, 2] and right == [2, 3]
    439        ```
    440
    441        The is roughly the implementation
    442        ```py
    443        vec[0:mid], vec[mid:]
    444        ```
    445        """
    446        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 remaining 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

    vec[0:mid], vec[mid:]

def swap(self, a: int, b: int): View Source

    448    def swap(self, a: int, b: int):
    449        """Swap two elements in the vec.
    450
    451        if `a` equals to `b` then it's guaranteed that elements won't change value.
    452
    453        Example
    454        -------
    455        ```py
    456        buf = Vec([1, 2, 3, 4])
    457        buf.swap(0, 3)
    458        assert buf == [4, 2, 3, 1]
    459        ```
    460
    461        Raises
    462        ------
    463        IndexError
    464            If the positions of `a` or `b` are out of index.
    465        """
    466        if self[a] == self[b]:
    467            return
    468
    469        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): View Source

    471    def swap_unchecked(self, a: int, b: int):
    472        """Swap two elements in the vec. without checking if `a` == `b`.
    473
    474        If you care about `a` and `b` equality, see `Vec.swap`.
    475
    476        Example
    477        -------
    478        ```py
    479        buf = Vec([1, 2, 3, 1])
    480        buf.swap_unchecked(0, 3)
    481        assert buf == [1, 2, 3, 1]
    482        ```
    483
    484        Raises
    485        ------
    486        IndexError
    487            If the positions of `a` or `b` are out of index.
    488        """
    489        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]': View Source

    491    def first(self) -> _option.Option[T]:
    492        """Get the first element in this vec, returning `None` if there's none.
    493
    494        Example
    495        -------
    496        ```py
    497        vec = Vec((1,2,3))
    498        first = vec.first()
    499        assert ~first == 1
    500        ```
    501        """
    502        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]': View Source

    504    def last(self) -> _option.Option[T]:
    505        """Get the last element in this vec, returning `None` if there's none.
    506
    507        Example
    508        -------
    509        ```py
    510        vec = Vec([1, 2, 3, 4])
    511        first = vec.last()
    512        assert ~first == 4
    513        ```
    514        """
    515        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: View Source

    517    def truncate(self, size: int) -> None:
    518        """Shortens the vec, keeping the first `size` elements and dropping the rest.
    519
    520        Example
    521        -------
    522        ```py
    523        vec = Vec([1,2,3])
    524        vec.truncate(1)
    525        assert vec == [1]
    526        ```
    527        """
    528        if not self._ptr:
    529            return
    530
    531        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: View Source

    533    def retain(self, f: collections.Callable[[T], bool]) -> None:
    534        """Retains only the elements specified by the predicate.
    535
    536        This operation occurs in-place without copying the original list.
    537
    538        Example
    539        -------
    540        ```py
    541        vec = Vec([1, 2, 3])
    542        vec.retain(lambda elem: elem > 1)
    543
    544        assert vec == [2, 3]
    545        ```
    546
    547        The impl for this method is very simple
    548        ```py
    549        for idx, e in enumerate(vec):
    550            if not f(e):
    551                del vec[idx]
    552        ```
    553        """
    554        if not self._ptr:
    555            return
    556
    557        idx = 0
    558        while idx < len(self._ptr):
    559            if not f(self._ptr[idx]):
    560                del self._ptr[idx]
    561            else:
    562                idx += 1

Retains only the elements specified by the predicate.

This operation occurs in-place without copying the original list.

###### Example

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

    assert vec == [2, 3]

The impl for this method is very simple

    for idx, e in enumerate(vec):
        if not f(e):
            del vec[idx]

def swap_remove(self, item: ~T) -> ~T: View Source

    564    def swap_remove(self, item: T) -> T:
    565        """Remove the first appearance of `item` from this vector and return it.
    566
    567        Raises
    568        ------
    569        * `ValueError`: if `item` is not in this vector.
    570        * `MemoryError`: if this vector hasn't allocated, Aka nothing has been pushed to it.
    571
    572        Example
    573        -------
    574        ```py
    575        vec = Vec(('a', 'b', 'c'))
    576        element = vec.remove('a')
    577        assert vec == ['b', 'c'] and element == 'a'
    578        ```
    579        """
    580        if self._ptr is None:
    581            raise MemoryError("Vec is unallocated.") from None
    582
    583        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: View Source

    585    def fill(self, value: T) -> None:
    586        """Fill `self` with the given `value`.
    587
    588        Nothing happens if the vec is empty or unallocated.
    589
    590        Example
    591        ```py
    592        a = Vec([0, 1, 2, 3])
    593        a.fill(0)
    594        assert a == [0, 0, 0, 0]
    595        ```
    596        """
    597        if not self._ptr:
    598            return
    599
    600        for n, _ in enumerate(self):
    601            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: View Source

    603    def push(self, item: T) -> None:
    604        """Push an element at the end of the vector.
    605
    606        Example
    607        -------
    608        ```py
    609        vec = Vec()
    610        vec.push(1)
    611
    612        assert vec == [1]
    613        ```
    614        """
    615        if self._capacity is not None:
    616            self.push_within_capacity(item)
    617            return
    618
    619        if self._ptr is None:
    620            self._ptr = []
    621
    622        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]': View Source

    624    def push_within_capacity(self, x: T) -> Result[None, T]:
    625        """Appends an element if there is sufficient spare capacity, otherwise an error is returned with the element.
    626
    627        Example
    628        -------
    629        ```py
    630        vec: Vec[int] = Vec.with_capacity(3)
    631        for i in range(3):
    632            match vec.push_within_capacity(i):
    633                case Ok(_):
    634                    print("All good.")
    635                case Err(elem):
    636                    print("Reached max cap :< can't push", elem)
    637        ```
    638
    639        Or you can also just call `Vec.push` and it will push if there's is sufficient capacity.
    640        ```py
    641        vec: Vec[int] = Vec.with_capacity(3)
    642
    643        vec.extend((1, 2, 3))
    644        vec.push(4)
    645
    646        assert vec.len() == 3
    647        ```
    648        """
    649        if self._ptr is None:
    650            self._ptr = []
    651
    652        if self.len() == self._capacity:
    653            return _result.Err(x)
    654
    655        self._ptr.append(x)
    656        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 :< can't push", elem)

Or you can also just call `Vec.push` and it will push if there's 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: View Source

    658    def reserve(self, additional: int) -> None:
    659        """Reserves capacity for at least additional more elements to be inserted in the given Vec<T>.
    660
    661        Example
    662        -------
    663        ```py
    664        vec = Vec.with_capacity(3)
    665        is_vip = random.choice((True, False))
    666
    667        for i in range(4):
    668            match vec.push_within_capacity(i):
    669                case Ok(_):
    670                    print("All good")
    671                case Err(person):
    672                    # If the person is a VIP, then reserve for one more.
    673                    if is_vip:
    674                        vec.reserve(1)
    675                        continue
    676
    677                    # is_vip was false.
    678                    print("Can't reserve for non-VIP members...", person)
    679                    break
    680        ```
    681        """
    682        if self._capacity is not None:
    683            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: View Source

    685    def shrink_to_fit(self) -> None:
    686        """Shrink the capacity of this `Vec` to match its length.
    687
    688        If `self` is initialized with no capacity, This is a `NOP`.
    689
    690        Example
    691        -------
    692        ```py
    693        s = Vec([1, 2, 3, 4])
    694
    695        s.reserve(100)
    696        s.shrink_to_fit()
    697        assert s.capacity() == 4
    698        ```
    699        """
    700        if self._capacity is None:
    701            return
    702
    703        # The capacity is never less than the length.
    704        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: View Source

    706    def shrink_to(self, min_capacity: int) -> None:
    707        """Shrink the capacity of this `Vec` to a minimum specified capacity.
    708
    709        If `self` is initialized with no capacity or the current capacity is less than the lower limit,
    710        This is a `NOP`.
    711
    712        Example
    713        -------
    714        ```py
    715        vec = Vec.with_capacity(10)
    716        vec.extend([1, 2, 3])
    717        assert vec.capacity() >= 10
    718        vec.shrink_to(4)
    719        assert vec.capacity() >= 4
    720        vec.shrink_to(0)
    721        ```
    722        """
    723        if self._capacity is None or self._capacity <= min_capacity:
    724            return
    725
    726        # Ensure the capacity is not reduced below the current length of the vector.
    727        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, value: ~T) -> None: View Source

    733    def append(self, value: T) -> None:
    734        """An alias to `Vec.push`."""
    735        self.push(value)

An alias to `Vec.push`.

def get(self, index: int) -> '_option.Option[T]': View Source

    737    def get(self, index: int) -> _option.Option[T]:
    738        """Get the item at the given index, or `Some[None]` if its out of bounds.
    739
    740        Example
    741        -------
    742        ```py
    743        vec = Vec((1, 2, 3))
    744        vec.get(0) == Some(1)
    745        vec.get(3) == Some(None)
    746        ```
    747        """
    748        try:
    749            return _option.Some(self[index])
    750        except IndexError:
    751            return _option.NOTHING

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: View Source

    753    def insert(self, index: int, value: T) -> None:
    754        """Insert an element at the position `index`.
    755
    756        Example
    757        --------
    758        ```py
    759        vec = Vec((2, 3))
    760        vec.insert(0, 1)
    761        assert vec == [1, 2, 3]
    762        ```
    763        """
    764        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]': View Source

    766    def pop(self, index: int = -1) -> _option.Option[T]:
    767        """Removes the last element from a vector and returns it, or `None` if it is empty.
    768
    769        Example
    770        -------
    771        ```py
    772        vec = Vec((1, 2, 3))
    773        assert vec.pop() == Some(3)
    774        assert vec == [1, 2]
    775        ```
    776        """
    777        if not self._ptr:
    778            return _option.NOTHING
    779
    780        return _option.Some(self._ptr.pop(index))

Removes the last element from a vector and returns it, or `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]': View Source

    782    def pop_if(self, pred: collections.Callable[[T], bool]) -> _option.Option[T]:
    783        """Removes the last element from a vector and returns it if `f` returns `True`,
    784        or `None` if it is empty.
    785
    786        Example
    787        -------
    788        ```py
    789        vec = Vec((1, 2, 3))
    790        assert vec.pop_if(lambda num: num * 2 == 6) == Some(3)
    791        assert vec == [1, 2]
    792        ```
    793        """
    794        if not self._ptr:
    795            return _option.NOTHING
    796
    797        if pred(self[-1]):
    798            return self.pop()
    799
    800        return _option.NOTHING

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: View Source

    802    def dedup(self) -> None:
    803        """Removes consecutive repeated elements in the vector according to their `__eq__`
    804        implementation.
    805
    806        Example
    807        -------
    808        ```py
    809        vec = Vec([1, 2, 2, 3, 2])
    810        vec.dedup()
    811        assert vec == [1, 2, 3, 2]
    812        """
    813        self.dedup_by(lambda a, b: a == b)

Removes consecutive repeated elements in the vector according to their `__eq__` implementation.

###### Example

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

def dedup_by(self, same_bucket: Callable[[~T, ~T], bool]) -> None: View Source

    815    def dedup_by(self, same_bucket: collections.Callable[[T, T], bool]) -> None:
    816        """Removes all but the first of consecutive elements in the vector satisfying a given equality.
    817
    818        Example
    819        -------
    820        ```py
    821        vec = Vec(["foo", "bar", "Bar", "baz", "bar"])
    822        vec.dedup_by(lambda a, b: a.lower() == b.lower())
    823        assert vec == ["foo", "bar", "baz", "bar"]
    824        ```
    825
    826        Only remove consecutive duplicates.
    827        ```py
    828        vec = Vec([1, 2, 2, 3, 4, 1])
    829        vec.dedup_by(lambda a, b: a == b)
    830        # The final 1 is not adjacent to the first 1, so it is not removed.
    831        assert vec == [1, 2, 3, 4, 1]
    832        ```
    833        """
    834
    835        if not self._ptr or (len_ := len(self._ptr)) <= 1:
    836            return
    837
    838        idx = 1
    839        while idx < len_:
    840            if same_bucket(self._ptr[idx], self._ptr[idx - 1]):
    841                del self._ptr[idx]
    842                len_ -= 1
    843            else:
    844                idx += 1

Removes all but the first of consecutive elements in the vector satisfying a given equality.

###### Example

    vec = Vec(["foo", "bar", "Bar", "baz", "bar"])
    vec.dedup_by(lambda a, b: a.lower() == b.lower())
    assert vec == ["foo", "bar", "baz", "bar"]

Only remove consecutive duplicates.

    vec = Vec([1, 2, 2, 3, 4, 1])
    vec.dedup_by(lambda a, b: a == b)
    # The final 1 is not adjacent to the first 1, so it is not removed.
    assert vec == [1, 2, 3, 4, 1]

def remove(self, item: ~T) -> None: View Source

    846    def remove(self, item: T) -> None:
    847        """Remove the first appearance of `item` from this vector.
    848
    849        Example
    850        -------
    851        ```py
    852        vec = Vec(('a', 'b', 'c'))
    853        vec.remove('a')
    854        assert vec == ['b', 'c']
    855        ```
    856        """
    857        if not self._ptr:
    858            return
    859
    860        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: View Source

    862    def extend(self, iterable: collections.Iterable[T]) -> None:
    863        """Extend this vector from another iterable.
    864
    865        Example
    866        -------
    867        ```py
    868        vec = Vec((1, 2, 3))
    869        vec.extend((4, 5, 6))
    870
    871        assert vec == [1, 2, 3, 4, 5, 6]
    872        ```
    873        """
    874        if self._ptr is None:
    875            self._ptr = []
    876
    877        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]: View Source

    879    def copy(self) -> Vec[T]:
    880        """Copy all elements of `self` into a new vector.
    881
    882        Example
    883        -------
    884        ```py
    885        original = Vec((1,2,3))
    886        copy = original.copy()
    887        copy.push(4)
    888
    889        print(original) # [1, 2, 3]
    890        ```
    891        """
    892        return Vec(self._ptr[:]) if self._ptr else Vec()

Copy all elements of `self` into a new vector.

###### Example

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

    print(original) # [1, 2, 3]

def clear(self) -> None: View Source

    894    def clear(self) -> None:
    895        """Clear all elements of this vector.
    896
    897        Example
    898        -------
    899        ```py
    900        vec = Vec((1,2,3))
    901        vec.clear()
    902        assert vec.len() == 0
    903        ```
    904        """
    905        if not self._ptr:
    906            return
    907
    908        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: View Source

    910    def sort(
    911        self,
    912        *,
    913        key: collections.Callable[[T], SupportsRichComparison] | None = None,
    914        reverse: bool = False,
    915    ) -> None:
    916        """This method sorts the list in place, using only < comparisons between items.
    917
    918        Example
    919        -------
    920        ```py
    921        vec = Vec((2, 1, 3))
    922        vec.sort()
    923        assert vec == [1, 2, 3]
    924        ```
    925        """
    926        if not self._ptr:
    927            return
    928
    929        # key can be `None` here just fine, idk why pyright is complaining.
    930        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: View Source

    932    def index(
    933        self, item: T, start: typing.SupportsIndex = 0, end: int = _sys.maxsize
    934    ) -> int:
    935        # << Official documentation >>
    936        """Return zero-based index in the vec of the first item whose value is equal to `item`.
    937        Raises a ValueError if there is no such item.
    938
    939        Example
    940        -------
    941        ```py
    942        vec = Vec((1, 2, 3))
    943        assert vec.index(2) == 1
    944        ```
    945        """
    946        if self._ptr is None:
    947            raise ValueError from None
    948
    949        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: View Source

    951    def count(self, item: T) -> int:
    952        """Return the number of occurrences of `item` in the vec.
    953
    954        `0` is returned if the vector is empty or hasn't been initialized, as well if them item not found.
    955
    956        Example
    957        --------
    958        ```py
    959        vec = Vec((1, 2, 3, 3))
    960        assert vec.count(3) == 2
    961        ```
    962        """
    963        if self._ptr is None:
    964            return 0
    965
    966        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

##### Inherited Members

sain.collections.slice.SpecContains
  contains

@rustc_diagnostic_item('&[u8]')
@typing.final
class Bytes(sain.convert.ToString, collections.abc.Sequence[int], sain.collections.slice.SpecContains[int]): View Source

    109@rustc_diagnostic_item("&[u8]")
    110@typing.final
    111class Bytes(convert.ToString, collections.Sequence[int], _slice.SpecContains[int]):
    112    """Provides immutable abstractions for working with bytes.
    113
    114    It is an efficient container for storing and operating with bytes.
    115    It behaves very much like `array.array[int]` as well has the same layout.
    116
    117    A `Bytes` objects are usually used within networking applications, but can also be used
    118    elsewhere as well.
    119
    120    ## Construction
    121    `Bytes` object accept multiple rawish data types, See `Rawish` for all supported types.
    122
    123    * `Bytes()`: Initialize an empty `Bytes` object
    124    * `from_str`: Create `Bytes` from `str`
    125    * `from_bytes`: Create `Bytes` from a `Buffer` bytes-like type
    126    * `from_raw`: Create `Bytes` from a `Rawish` type
    127    * `from_ptr`: Create `Bytes` that points to an `array.array[int]` without copying it
    128    * `Bytes.zeroed(count)`: Create `Bytes` filled with `zeroes * count`.
    129
    130    Example
    131    -------
    132    ```py
    133    from sain import Bytes
    134
    135    buf = Bytes.from_str("Hello")
    136    print(buf) # [72, 101, 108, 108, 111]
    137    # buf is currently immutable, to make it mutable use `buf.to_mut()`
    138    # the conversion costs nothing, as it just points to the same underlying array.
    139    buf_mut = buf.to_mut()
    140    buf_mut.put(32)
    141    assert buf_mut == b"Hello "
    142    ```
    143    """
    144
    145    __slots__ = ("_buf",)
    146
    147    def __init__(self) -> None:
    148        """Creates a new empty `Bytes`.
    149
    150        This won't allocate the array and the returned `Bytes` will be empty.
    151        """
    152        self._buf: array.array[int] | None = None
    153
    154    # construction
    155
    156    @classmethod
    157    def from_str(cls, s: str) -> Bytes:
    158        """Create a new `Bytes` from a utf-8 string.
    159
    160        Example
    161        -------
    162        ```py
    163        buffer = Bytes.from_str("💀")
    164        ```
    165        """
    166        b = cls()
    167        b._buf = array.array("B", s.encode(ENCODING))
    168        return b
    169
    170    @classmethod
    171    def from_ptr(cls, arr: array.array[int]) -> Self:
    172        """Create a new `Bytes` from an array.
    173
    174        The returned `Bytes` will directly point to `arr` without copying.
    175
    176        Example
    177        -------
    178        ```py
    179        arr = array.array("B", b"Hello")
    180        buffer = Bytes.from_ptr(arr)
    181        ```
    182        """
    183        # this is technically an `assert` line
    184        # but Python isn't smart enough to inline and opt-out
    185        # this out of the generated bytecode.
    186        # so we'll just leave this under `if` statement.
    187        if __debug__:
    188            assert_precondition(
    189                arr.typecode == "B",
    190                f"array type must be `B`, not `{arr.typecode}`",
    191                TypeError,
    192            )
    193
    194        b = cls()
    195        b._buf = arr
    196        return b
    197
    198    @classmethod
    199    @unsafe
    200    def from_ptr_unchecked(cls, arr: array.array[int]) -> Self:
    201        """Create a new `Bytes` from an array, without checking the type code.
    202
    203        The returned `Bytes` will directly point to `arr` without copying.
    204
    205        ## Safety
    206
    207        The caller must ensure that `arr` is of type `array.array[int]` with type code `B`.
    208
    209        Example
    210        -------
    211        ```py
    212        arr = array.array("B", b"Hello")
    213        buffer = Bytes.from_ptr_unchecked(arr)
    214        ```
    215        """
    216        b = cls()
    217        b._buf = arr
    218        return b
    219
    220    @classmethod
    221    def from_bytes(cls, buf: Buffer) -> Self:
    222        """Create a new `Bytes` from an initial bytes.
    223
    224        Example
    225        -------
    226        ```py
    227        buffer = Bytes.from_bytes(b"SIGNATURE")
    228        ```
    229        """
    230        b = cls()
    231        b._buf = array.array("B", buf)
    232        return b
    233
    234    @classmethod
    235    def from_raw(cls, raw: Rawish) -> Self:
    236        """Initialize a new `Bytes` from a `Rawish` data type.
    237
    238        Example
    239        -------
    240        ```py
    241        with open('file.txt', 'rb') as file:
    242            buff = Bytes.from_raw(file)
    243
    244        # in memory bytes io
    245        bytes_io = io.BytesIO(b"data")
    246        buffer1 = Bytes.from_raw(bytes_io)
    247        # in memory string io
    248        string_io = io.StringIO("data")
    249        buffer2 = Bytes.from_raw(string_io)
    250        ```
    251        """
    252        c = cls()
    253        c._buf = array.array("B", unwrap_bytes(raw))
    254        return c
    255
    256    @classmethod
    257    def zeroed(cls, count: int) -> Self:
    258        """Initialize a new `Bytes` filled with `0 * count`.
    259
    260        Example
    261        -------
    262        ```py
    263        ALLOC_SIZE = 1024 * 2
    264        buffer = Bytes.zeros(ALLOC_SIZE)
    265        assert buffer.len() == ALLOC_SIZE
    266        ```
    267        """
    268        c = cls()
    269        c._buf = array.array("B", [0] * count)
    270        return c
    271
    272    # buffer evolution
    273
    274    # These are getting deprecated because they're trivial.
    275    # maybe we impl a `String` type and include them later.
    276    # anyways, they won't be leaving for sometime until 2.0.0.
    277
    278    @deprecated(
    279        since="1.3.0",
    280        removed_in="2.0.0",
    281        use_instead='Bytes.to_bytes().decode("utf8")',
    282        hint="Converting a bytes object to string is fairly trivial.",
    283    )
    284    def to_string(self) -> str:
    285        """Convert the bytes to a string.
    286
    287        Same as `Bytes.to_str`
    288        """
    289        return self.to_str()
    290
    291    @deprecated(
    292        since="1.3.0",
    293        removed_in="2.0.0",
    294        use_instead='Bytes.to_bytes().decode("utf8")',
    295        hint="Converting a bytes object to string is fairly trivial.",
    296    )
    297    def try_to_str(self) -> Result[str, bytes]:
    298        """A safe method to convert `self` into a string.
    299
    300        This may fail if the `self` contains invalid bytes. strings
    301        needs to be valid utf-8.
    302
    303        Example
    304        -------
    305        ```py
    306        buf = Bytes()
    307        sparkles_heart = [240, 159, 146, 150]
    308        buf.put_bytes(sparkles_heart)
    309
    310        assert buf.try_to_str().unwrap() == "💖"
    311        ```
    312
    313        Incorrect bytes
    314        ---------------
    315        ```py
    316        invalid_bytes = Bytes.from_bytes([0, 159, 146, 150])
    317        invalid_bytes.try_to_str().is_err()
    318        ```
    319
    320        Returns
    321        -------
    322        `Result[str, bytes]`
    323            If successful, returns the decoded string, otherwise the original bytes that failed
    324            to get decoded.
    325        """
    326        try:
    327            return _result.Ok(self.to_bytes().decode(ENCODING))
    328        except UnicodeDecodeError as e:
    329            return _result.Err(e.object)
    330
    331    @deprecated(
    332        since="1.3.0",
    333        removed_in="2.0.0",
    334        use_instead='str(Bytes, encoding="utf-8")',
    335        hint="Converting a bytes object to string is fairly trivial.",
    336    )
    337    def to_str(self) -> str:
    338        r"""Convert `self` to a utf-8 string.
    339
    340        During the conversion process, any invalid bytes will get converted to
    341        [REPLACEMENT_CHARACTER](https://en.wikipedia.org/wiki/Specials_(Unicode_block))
    342        which looks like this `�`, so be careful on what you're trying to convert.
    343
    344        Use `.try_to_str` try attempt the conversion in case of failure.
    345
    346        Example
    347        -------
    348        ```py
    349        buf = Bytes()
    350        sparkles_heart = [240, 159, 146, 150]
    351        buf.put_bytes(sparkles_heart)
    352
    353        assert buf.to_str() == "💖"
    354        ```
    355
    356        Incorrect bytes
    357        ---------------
    358        ```py
    359        invalid_bytes = Bytes.from_bytes(b"Hello \xf0\x90\x80World")
    360        assert invalid_bytes.to_str() == "Hello �World"
    361        ```
    362        """
    363        if not self._buf:
    364            return ""
    365
    366        return self._buf.tobytes().decode(ENCODING, errors="replace")
    367
    368    def to_bytes(self) -> bytes:
    369        """Convert `self` into `bytes`, copying the underlying array into a new buffer.
    370
    371        Example
    372        -------
    373        ```py
    374        buf = Bytes.from_str("Hello")
    375        assert buf.to_bytes() == b'Hello'
    376        ```
    377        """
    378        if not self._buf:
    379            return b""
    380
    381        return self._buf.tobytes()
    382
    383    def to_vec(self) -> _vec.Vec[int]:
    384        """Copies `self` into a new `Vec`.
    385
    386        Example
    387        -------
    388        ```py
    389        buffer = Bytes.from_str([1, 2, 3, 4])
    390        # buffer and x can be modified independently.
    391        x = buffer.to_vec()
    392        """
    393        return _vec.Vec(self.copy())
    394
    395    def leak(self) -> array.array[int]:
    396        """Consumes and leaks the `Bytes`, returning the contents as an `array[int]`,
    397
    398        A new empty array is returned if the underlying buffer is not initialized.
    399
    400        `self` will deallocate the underlying array, therefore it becomes unusable.
    401
    402        Safety
    403        ------
    404        It is unsafe to access the leaked array from `self` after calling this function.
    405
    406        Example
    407        -------
    408        ```py
    409        bytes = Bytes.from_str("chunks of data")
    410        consumed = bytes.leak()
    411        # `bytes` doesn't point to anything, this is undefined behavior.
    412        bytes.put(0)
    413        # access the array directly instead.
    414        consumed.tobytes() == b"chunks of data"
    415        ```
    416        """
    417        if self._buf is None:
    418            return array.array("B")
    419
    420        arr = self._buf
    421        # We don't need to reference this anymore since the caller will own the array.
    422        del self._buf
    423        return arr
    424
    425    def as_ptr(self) -> memoryview[int]:
    426        """Returns a read-only pointer to the buffer data.
    427
    428        `pointer` here refers to a `memoryview` object.
    429
    430        A `BufferError` is raised if the underlying sequence is not initialized.
    431
    432        Example
    433        -------
    434        ```py
    435        buffer = Bytes.from_bytes(b"data")
    436        ptr = buffer.as_ptr()
    437        ptr[0] = 1 # TypeError: cannot modify read-only memory
    438        ```
    439        """
    440        return self.__buffer__(256).toreadonly()
    441
    442    def as_ref(self) -> _slice.Slice[int]:
    443        """Get an immutable reference to the underlying sequence, without copying.
    444
    445        An empty slice is returned if the underlying sequence is not initialized.
    446
    447        Example
    448        -------
    449        ```py
    450        async def send_multipart(buf: Sequence[int]) -> None:
    451            ...
    452
    453        buffer = Bytes.from_bytes([0, 0, 0, 0])
    454        await send_multipart(buffer.as_ref()) # no copy.
    455        ```
    456        """
    457        if self._buf is not None:
    458            return _slice.Slice(self)
    459
    460        return _slice.Slice(())
    461
    462    @safe
    463    def to_mut(self) -> BytesMut:
    464        """Convert `self` into `BytesMut`.
    465
    466        This consumes `self` and returns a new `BytesMut` that points to the same underlying array,
    467        The conversion costs nothing.
    468
    469        Notes
    470        -----
    471        * If `self` is not initialized, a new empty `BytesMut` is returned.
    472        * `self` will no longer be usable, as it will not point to the underlying array.
    473
    474        The inverse method for this is `BytesMut.freeze()`
    475
    476        Example
    477        -------
    478        ```py
    479        def modify(buffer: Bytes) -> BytesMut:
    480            buf = buffer.to_mut() # doesn't cost anything.
    481            buf.swap(0, 1)
    482            return buf
    483
    484        buffer = Bytes.from_bytes([1, 2, 3, 4])
    485        new = modify(buffer)
    486        assert new == [2, 1, 3, 4]
    487        ```
    488        """
    489        # SAFETY: `Bytes.leak` returns an empty array
    490        # if `self` is uninitialized.
    491        return BytesMut.from_ptr_unchecked(self.leak())
    492
    493    def raw_parts(
    494        self,
    495    ) -> tuple[int, int]:
    496        """Return `self` as tuple containing the memory address to the buffer and how many bytes it currently contains.
    497
    498        An alias to `array.buffer_into`
    499        """
    500        if not self._buf:
    501            return (0x0, 0)
    502
    503        return self._buf.buffer_info()
    504
    505    def len(self) -> int:
    506        """Return the number of bytes in this buffer.
    507
    508        Example
    509        -------
    510        ```py
    511        buf = Bytes.from_bytes([240, 159, 146, 150])
    512        assert buf.len() == 4
    513        ```
    514        """
    515        return self.__len__()
    516
    517    def size(self) -> int:
    518        """The length in bytes of one array item in the internal representation.
    519
    520
    521        An alias to `array.itemsize`
    522
    523        Example
    524        -------
    525        ```py
    526        buf = Bytes.from_bytes([240, 159, 146, 150])
    527        assert buf.size() == 1
    528        ```
    529        """
    530        if not self._buf:
    531            return 0
    532        return self._buf.itemsize
    533
    534    def iter(self) -> _iter.TrustedIter[int]:
    535        """Returns an iterator over the contained bytes.
    536
    537        This iterator yields all `int`s from start to end.
    538
    539        Example
    540        -------
    541        ```py
    542        buf = Bytes.from_bytes((1, 2, 3))
    543        iterator = buf.iter()
    544
    545        # map each byte to a character
    546        for element in iterator.map(chr):
    547            print(element)
    548        # ☺
    549        # ☻
    550        # ♥
    551        ```
    552        """
    553        return _iter.TrustedIter(self.as_ptr())
    554
    555    def chars(self) -> Chars:
    556        """Returns an iterator over the characters of `Bytes`.
    557
    558        This iterator yields all `int`s from start to end mapped as a `ctypes.c_char`.
    559
    560        Example
    561        -------
    562        ```py
    563        b = Bytes.from_str("Hello")
    564        for char in b.chars():
    565            print(char)
    566
    567        # c_char(b'H')
    568        # c_char(b'e')
    569        # c_char(b'l')
    570        # c_char(b'l')
    571        # c_char(b'o')
    572        ```
    573        """
    574        # The built-in map is actually faster than our own pure python adapter impl.
    575        return _iter.Iter(map(_ctypes.c_char, self))
    576
    577    def is_empty(self) -> bool:
    578        """Check whether `self` contains any bytes or not.
    579
    580        Example
    581        -------
    582        ```py
    583        buffer = Bytes()
    584        assert buffer.is_empty()
    585        ```
    586        """
    587        return not self._buf
    588
    589    def split_off(self, at: int) -> Bytes:
    590        """Split the bytes off at the specified position, returning a new
    591        `Bytes` at the range of `[at : len]`, leaving `self` at `[at : bytes_len]`.
    592
    593        if this bytes is empty, `self` is returned unchanged.
    594
    595        Example
    596        -------
    597        ```py
    598        origin = Bytes.from_bytes((1, 2, 3, 4))
    599        split = origin.split_off(2)
    600
    601        print(origin, split)  # [1, 2], [3, 4]
    602        ```
    603
    604        Raises
    605        ------
    606        `RuntimeError`
    607            This method will raise if `at` > `len(self)`
    608        """
    609        len_ = self.len()
    610        if at > len_:
    611            raise RuntimeError(
    612                f"Index `at` ({at}) should be <= than len of `self` ({len_}) "
    613            ) from None
    614
    615        # Either the list is empty or uninit.
    616        if not self._buf:
    617            return self
    618
    619        split = self[at:len_]  # split the items into a new buffer.
    620        del self._buf[at:len_]  # remove the items from the original list.
    621        return split
    622
    623    def split_first(self) -> Option[tuple[int, Bytes]]:
    624        """Split the first and rest elements of the bytes, If empty, `None` is returned.
    625
    626        Example
    627        -------
    628        ```py
    629        buf = Bytes.from_bytes([1, 2, 3])
    630        split = buf.split_first()
    631        assert split == Some((1, [2, 3]))
    632        ```
    633        """
    634        if not self._buf:
    635            return _option.NOTHING
    636
    637        # optimized to only one element in the buffer.
    638        if self.len() == 1:
    639            return _option.Some((self[0], Bytes()))
    640
    641        first, rest = self[0], self[1:]
    642        return _option.Some((first, rest))
    643
    644    def split_last(self) -> Option[tuple[int, Bytes]]:
    645        """Returns the last and rest of the elements of the bytes, If `self` is empty, `None` is returned.
    646
    647        Example
    648        -------
    649        ```py
    650        buf = Bytes.from_bytes([0, 1, 2])
    651        last, elements = buf.split_last().unwrap()
    652        assert (last, elements) == (3, [1, 2])
    653        ```
    654        """
    655        if not self._buf:
    656            return _option.NOTHING
    657
    658        len_ = self.len()
    659        # optimized to only one element in the buffer.
    660        if len_ == 1:
    661            return _option.Some((self[0], Bytes()))
    662
    663        last, rest = self[-1], self[:-1]
    664        return _option.Some((last, rest))
    665
    666    def split_at(self, mid: int) -> tuple[Bytes, Bytes]:
    667        """Divide `self` into two at an index.
    668
    669        The first will contain all bytes from `[0:mid]` excluding `mid` it self.
    670        and the second will contain the remaining bytes.
    671
    672        if `mid` > `self.len()`, Then all bytes will be moved to the left,
    673        returning an empty bytes in right.
    674
    675        Example
    676        -------
    677        ```py
    678        buffer = Bytes.from_bytes((1, 2, 3, 4))
    679        left, right = buffer.split_at(0)
    680        assert left == [] and right == [1, 2, 3, 4]
    681
    682        left, right = buffer.split_at(2)
    683        assert left == [1, 2] and right == [2, 3]
    684        ```
    685
    686        The is roughly the implementation
    687        ```py
    688        self[0:mid], self[mid:]
    689        ```
    690        """
    691        return self[0:mid], self[mid:]
    692
    693    # layout methods.
    694
    695    @safe
    696    def copy(self) -> Bytes:
    697        """Create a copy of the bytes.
    698
    699        Example
    700        -------
    701        ```py
    702        original = Bytes.from_bytes([255, 255, 255, 0])
    703        copy = original.copy()
    704        ```
    705        """
    706        if not self._buf:
    707            return Bytes()
    708
    709        # SAFETY: `self._buf` is initialized.
    710        return self.from_ptr_unchecked(self._buf[:])
    711
    712    def index(self, v: int, start: int = 0, stop: int = _sys.maxsize) -> int:
    713        """Return the smallest `i` such that `i` is the index of the first occurrence of `v` in the buffer.
    714
    715        The optional arguments start and stop can be specified to search for x within a
    716        subsection of the array. Raise ValueError if x is not found
    717        """
    718        if not self._buf:
    719            raise ValueError from None
    720
    721        return self._buf.index(v, start, stop)
    722
    723    def count(self, x: int) -> int:
    724        """Return the number of occurrences of `x` in the buffer.
    725
    726        Example
    727        --------
    728        ```py
    729        buf = Bytes([32, 32, 31])
    730        assert buf.count(32) == 2
    731        ```
    732        """
    733        if self._buf is None:
    734            return 0
    735
    736        return self._buf.count(x)
    737
    738    # special methods
    739
    740    def __iter__(self) -> collections.Iterator[int]:
    741        if self._buf:
    742            return self._buf.__iter__()
    743
    744        return ().__iter__()
    745
    746    def __len__(self) -> int:
    747        return len(self._buf) if self._buf else 0
    748
    749    def __repr__(self) -> str:
    750        if not self._buf:
    751            return "[]"
    752
    753        return "[" + ", ".join(str(x) for x in self._buf) + "]"
    754
    755    __str__ = __repr__
    756
    757    def __bytes__(self) -> bytes:
    758        return self.to_bytes()
    759
    760    def __buffer__(self, flag: int | inspect.BufferFlags) -> memoryview[int]:
    761        if not self._buf:
    762            raise BufferError("Cannot work with uninitialized bytes.")
    763
    764        if _sys.version_info >= (3, 12):
    765            mem = self._buf.__buffer__(flag)
    766        else:
    767            # arrays in 3.11 and under don't implement the buffer protocol.
    768            mem = memoryview(self._buf)
    769
    770        return mem
    771
    772    def __contains__(self, byte: int) -> bool:
    773        return byte in self._buf if self._buf else False
    774
    775    def __eq__(self, other: object, /) -> bool:
    776        if not self._buf:
    777            return False
    778
    779        if isinstance(other, bytes):
    780            return self._buf.tobytes() == other
    781
    782        # bytes IS a `Sequence[int]`, but not all `Sequence[int]`
    783        # represented as bytes.
    784        elif isinstance(other, collections.Sequence):
    785            return self._buf.tolist() == other
    786
    787        return self._buf.__eq__(other)
    788
    789    def __ne__(self, other: object, /) -> bool:
    790        return not self.__eq__(other)
    791
    792    def __le__(self, other: object) -> bool:
    793        if not self._buf:
    794            return False
    795
    796        if not isinstance(other, Bytes):
    797            return NotImplemented
    798
    799        if not other._buf:
    800            return False
    801
    802        return self._buf <= other._buf
    803
    804    def __ge__(self, other: object) -> bool:
    805        if not self._buf:
    806            return False
    807
    808        if not isinstance(other, Bytes):
    809            return NotImplemented
    810
    811        if not other._buf:
    812            return False
    813
    814        return self._buf >= other._buf
    815
    816    def __lt__(self, other: object) -> bool:
    817        if not self._buf:
    818            return False
    819
    820        if not isinstance(other, Bytes):
    821            return NotImplemented
    822
    823        if not other._buf:
    824            return False
    825
    826        return self._buf < other._buf
    827
    828    def __gt__(self, other: object) -> bool:
    829        if not self._buf:
    830            return False
    831
    832        if not isinstance(other, Bytes):
    833            return NotImplemented
    834
    835        if not other._buf:
    836            return False
    837
    838        return self._buf > other._buf
    839
    840    @typing.overload
    841    def __getitem__(self, index: slice) -> Bytes: ...
    842
    843    @typing.overload
    844    def __getitem__(self, index: int) -> int: ...
    845
    846    @safe
    847    def __getitem__(self, index: int | slice) -> int | Bytes:
    848        if not self._buf:
    849            raise IndexError("Index out of range")
    850
    851        if isinstance(index, slice):
    852            # SAFETY: `self._buf` is initialized.
    853            return self.from_ptr_unchecked(self._buf[index])
    854
    855        return self._buf[index]
    856
    857    def __reversed__(self) -> collections.Iterator[int]:
    858        return reversed(self._buf or ())
    859
    860    # defined like `array`'s
    861    __hash__: typing.ClassVar[None] = None
    862
    863    @safe
    864    def __copy__(self) -> Bytes:
    865        if not self._buf:
    866            return Bytes()
    867
    868        return Bytes.from_ptr_unchecked(self._buf.__copy__())
    869
    870    @safe
    871    def __deepcopy__(self, unused: typing.Any, /) -> Bytes:
    872        if not self._buf:
    873            return Bytes()
    874
    875        return Bytes.from_ptr_unchecked(self._buf.__deepcopy__(unused))

Provides immutable abstractions for working with bytes.

It is an efficient container for storing and operating with bytes. It behaves very much like `array.array[int]` as well has the same layout.

A `Bytes` objects are usually used within networking applications, but can also be used elsewhere as well.

## Construction

`Bytes` object accept multiple rawish data types, See `Rawish` for all supported types.

- `Bytes()`: Initialize an empty `Bytes` object
- `from_str`: Create `Bytes` from `str`
- `from_bytes`: Create `Bytes` from a `Buffer` bytes-like type
- `from_raw`: Create `Bytes` from a `Rawish` type
- `from_ptr`: Create `Bytes` that points to an `array.array[int]` without copying it
- `Bytes.zeroed(count)`: Create `Bytes` filled with `zeroes * count`.

###### Example

    from sain import Bytes

    buf = Bytes.from_str("Hello")
    print(buf) # [72, 101, 108, 108, 111]
    # buf is currently immutable, to make it mutable use `buf.to_mut()`
    # the conversion costs nothing, as it just points to the same underlying array.
    buf_mut = buf.to_mut()
    buf_mut.put(32)
    assert buf_mut == b"Hello "

# Implementations

This class implements &[u8] in Rust.

@classmethod
def from_str(cls, s: str) -> Bytes: View Source

    156    @classmethod
    157    def from_str(cls, s: str) -> Bytes:
    158        """Create a new `Bytes` from a utf-8 string.
    159
    160        Example
    161        -------
    162        ```py
    163        buffer = Bytes.from_str("💀")
    164        ```
    165        """
    166        b = cls()
    167        b._buf = array.array("B", s.encode(ENCODING))
    168        return b

Create a new `Bytes` from a utf-8 string.

###### Example

    buffer = Bytes.from_str("💀")

@classmethod
def from_ptr(cls, arr: array.array[int]) -> Self: View Source

    170    @classmethod
    171    def from_ptr(cls, arr: array.array[int]) -> Self:
    172        """Create a new `Bytes` from an array.
    173
    174        The returned `Bytes` will directly point to `arr` without copying.
    175
    176        Example
    177        -------
    178        ```py
    179        arr = array.array("B", b"Hello")
    180        buffer = Bytes.from_ptr(arr)
    181        ```
    182        """
    183        # this is technically an `assert` line
    184        # but Python isn't smart enough to inline and opt-out
    185        # this out of the generated bytecode.
    186        # so we'll just leave this under `if` statement.
    187        if __debug__:
    188            assert_precondition(
    189                arr.typecode == "B",
    190                f"array type must be `B`, not `{arr.typecode}`",
    191                TypeError,
    192            )
    193
    194        b = cls()
    195        b._buf = arr
    196        return b

Create a new `Bytes` from an array.

The returned `Bytes` will directly point to `arr` without copying.

###### Example

    arr = array.array("B", b"Hello")
    buffer = Bytes.from_ptr(arr)

@classmethod
@unsafe
def from_ptr_unchecked(cls, arr: array.array[int]) -> Self: View Source

    198    @classmethod
    199    @unsafe
    200    def from_ptr_unchecked(cls, arr: array.array[int]) -> Self:
    201        """Create a new `Bytes` from an array, without checking the type code.
    202
    203        The returned `Bytes` will directly point to `arr` without copying.
    204
    205        ## Safety
    206
    207        The caller must ensure that `arr` is of type `array.array[int]` with type code `B`.
    208
    209        Example
    210        -------
    211        ```py
    212        arr = array.array("B", b"Hello")
    213        buffer = Bytes.from_ptr_unchecked(arr)
    214        ```
    215        """
    216        b = cls()
    217        b._buf = arr
    218        return b

Create a new `Bytes` from an array, without checking the type code.

The returned `Bytes` will directly point to `arr` without copying.

## Safety

The caller must ensure that `arr` is of type `array.array[int]` with type code `B`.

###### Example

    arr = array.array("B", b"Hello")
    buffer = Bytes.from_ptr_unchecked(arr)

# Safety ⚠️

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

@classmethod
def from_bytes(cls, buf: bytes | bytearray | Iterable[int]) -> Self: View Source

    220    @classmethod
    221    def from_bytes(cls, buf: Buffer) -> Self:
    222        """Create a new `Bytes` from an initial bytes.
    223
    224        Example
    225        -------
    226        ```py
    227        buffer = Bytes.from_bytes(b"SIGNATURE")
    228        ```
    229        """
    230        b = cls()
    231        b._buf = array.array("B", buf)
    232        return b

Create a new `Bytes` from an initial bytes.

###### Example

    buffer = Bytes.from_bytes(b"SIGNATURE")

@classmethod
def from_raw(cls, raw: _io.StringIO | _io.BytesIO | _io.BufferedReader) -> Self: View Source

    234    @classmethod
    235    def from_raw(cls, raw: Rawish) -> Self:
    236        """Initialize a new `Bytes` from a `Rawish` data type.
    237
    238        Example
    239        -------
    240        ```py
    241        with open('file.txt', 'rb') as file:
    242            buff = Bytes.from_raw(file)
    243
    244        # in memory bytes io
    245        bytes_io = io.BytesIO(b"data")
    246        buffer1 = Bytes.from_raw(bytes_io)
    247        # in memory string io
    248        string_io = io.StringIO("data")
    249        buffer2 = Bytes.from_raw(string_io)
    250        ```
    251        """
    252        c = cls()
    253        c._buf = array.array("B", unwrap_bytes(raw))
    254        return c

Initialize a new `Bytes` from a `Rawish` data type.

###### Example

    with open('file.txt', 'rb') as file:
        buff = Bytes.from_raw(file)

    # in memory bytes io
    bytes_io = io.BytesIO(b"data")
    buffer1 = Bytes.from_raw(bytes_io)
    # in memory string io
    string_io = io.StringIO("data")
    buffer2 = Bytes.from_raw(string_io)

@classmethod
def zeroed(cls, count: int) -> Self: View Source

    256    @classmethod
    257    def zeroed(cls, count: int) -> Self:
    258        """Initialize a new `Bytes` filled with `0 * count`.
    259
    260        Example
    261        -------
    262        ```py
    263        ALLOC_SIZE = 1024 * 2
    264        buffer = Bytes.zeros(ALLOC_SIZE)
    265        assert buffer.len() == ALLOC_SIZE
    266        ```
    267        """
    268        c = cls()
    269        c._buf = array.array("B", [0] * count)
    270        return c

Initialize a new `Bytes` filled with `0 * count`.

###### Example

    ALLOC_SIZE = 1024 * 2
    buffer = Bytes.zeros(ALLOC_SIZE)
    assert buffer.len() == ALLOC_SIZE

@deprecated(since='1.3.0', removed_in='2.0.0', use_instead='Bytes.to_bytes().decode("utf8")', hint='Converting a bytes object to string is fairly trivial.')
def try_to_str(self) -> 'Result[str, bytes]': View Source

    291    @deprecated(
    292        since="1.3.0",
    293        removed_in="2.0.0",
    294        use_instead='Bytes.to_bytes().decode("utf8")',
    295        hint="Converting a bytes object to string is fairly trivial.",
    296    )
    297    def try_to_str(self) -> Result[str, bytes]:
    298        """A safe method to convert `self` into a string.
    299
    300        This may fail if the `self` contains invalid bytes. strings
    301        needs to be valid utf-8.
    302
    303        Example
    304        -------
    305        ```py
    306        buf = Bytes()
    307        sparkles_heart = [240, 159, 146, 150]
    308        buf.put_bytes(sparkles_heart)
    309
    310        assert buf.try_to_str().unwrap() == "💖"
    311        ```
    312
    313        Incorrect bytes
    314        ---------------
    315        ```py
    316        invalid_bytes = Bytes.from_bytes([0, 159, 146, 150])
    317        invalid_bytes.try_to_str().is_err()
    318        ```
    319
    320        Returns
    321        -------
    322        `Result[str, bytes]`
    323            If successful, returns the decoded string, otherwise the original bytes that failed
    324            to get decoded.
    325        """
    326        try:
    327            return _result.Ok(self.to_bytes().decode(ENCODING))
    328        except UnicodeDecodeError as e:
    329            return _result.Err(e.object)

A safe method to convert `self` into a string.

This may fail if the `self` contains invalid bytes. strings needs to be valid utf-8.

###### Example

    buf = Bytes()
    sparkles_heart = [240, 159, 146, 150]
    buf.put_bytes(sparkles_heart)

    assert buf.try_to_str().unwrap() == "💖"

###### Incorrect bytes

    invalid_bytes = Bytes.from_bytes([0, 159, 146, 150])
    invalid_bytes.try_to_str().is_err()

###### Returns

- `Result[str, bytes]`: If successful, returns the decoded string, otherwise the original bytes that failed to get decoded.

@deprecated(since='1.3.0', removed_in='2.0.0', use_instead='str(Bytes, encoding="utf-8")', hint='Converting a bytes object to string is fairly trivial.')
def to_str(self) -> str: View Source

    331    @deprecated(
    332        since="1.3.0",
    333        removed_in="2.0.0",
    334        use_instead='str(Bytes, encoding="utf-8")',
    335        hint="Converting a bytes object to string is fairly trivial.",
    336    )
    337    def to_str(self) -> str:
    338        r"""Convert `self` to a utf-8 string.
    339
    340        During the conversion process, any invalid bytes will get converted to
    341        [REPLACEMENT_CHARACTER](https://en.wikipedia.org/wiki/Specials_(Unicode_block))
    342        which looks like this `�`, so be careful on what you're trying to convert.
    343
    344        Use `.try_to_str` try attempt the conversion in case of failure.
    345
    346        Example
    347        -------
    348        ```py
    349        buf = Bytes()
    350        sparkles_heart = [240, 159, 146, 150]
    351        buf.put_bytes(sparkles_heart)
    352
    353        assert buf.to_str() == "💖"
    354        ```
    355
    356        Incorrect bytes
    357        ---------------
    358        ```py
    359        invalid_bytes = Bytes.from_bytes(b"Hello \xf0\x90\x80World")
    360        assert invalid_bytes.to_str() == "Hello �World"
    361        ```
    362        """
    363        if not self._buf:
    364            return ""
    365
    366        return self._buf.tobytes().decode(ENCODING, errors="replace")

Convert `self` to a utf-8 string.

During the conversion process, any invalid bytes will get converted to REPLACEMENT_CHARACTER which looks like this `�`, so be careful on what you're trying to convert.

Use `.try_to_str` try attempt the conversion in case of failure.

###### Example

    buf = Bytes()
    sparkles_heart = [240, 159, 146, 150]
    buf.put_bytes(sparkles_heart)

    assert buf.to_str() == "💖"

###### Incorrect bytes

    invalid_bytes = Bytes.from_bytes(b"Hello \xf0\x90\x80World")
    assert invalid_bytes.to_str() == "Hello �World"

def to_bytes(self) -> bytes: View Source

    368    def to_bytes(self) -> bytes:
    369        """Convert `self` into `bytes`, copying the underlying array into a new buffer.
    370
    371        Example
    372        -------
    373        ```py
    374        buf = Bytes.from_str("Hello")
    375        assert buf.to_bytes() == b'Hello'
    376        ```
    377        """
    378        if not self._buf:
    379            return b""
    380
    381        return self._buf.tobytes()

Convert `self` into `bytes`, copying the underlying array into a new buffer.

###### Example

    buf = Bytes.from_str("Hello")
    assert buf.to_bytes() == b'Hello'

def to_vec(self) -> Vec[int]: View Source

    383    def to_vec(self) -> _vec.Vec[int]:
    384        """Copies `self` into a new `Vec`.
    385
    386        Example
    387        -------
    388        ```py
    389        buffer = Bytes.from_str([1, 2, 3, 4])
    390        # buffer and x can be modified independently.
    391        x = buffer.to_vec()
    392        """
    393        return _vec.Vec(self.copy())

Copies `self` into a new `Vec`.

###### Example

```py buffer = Bytes.from_str([1, 2, 3, 4])

# buffer and x can be modified independently.

x = buffer.to_vec()

def leak(self) -> array.array[int]: View Source

    395    def leak(self) -> array.array[int]:
    396        """Consumes and leaks the `Bytes`, returning the contents as an `array[int]`,
    397
    398        A new empty array is returned if the underlying buffer is not initialized.
    399
    400        `self` will deallocate the underlying array, therefore it becomes unusable.
    401
    402        Safety
    403        ------
    404        It is unsafe to access the leaked array from `self` after calling this function.
    405
    406        Example
    407        -------
    408        ```py
    409        bytes = Bytes.from_str("chunks of data")
    410        consumed = bytes.leak()
    411        # `bytes` doesn't point to anything, this is undefined behavior.
    412        bytes.put(0)
    413        # access the array directly instead.
    414        consumed.tobytes() == b"chunks of data"
    415        ```
    416        """
    417        if self._buf is None:
    418            return array.array("B")
    419
    420        arr = self._buf
    421        # We don't need to reference this anymore since the caller will own the array.
    422        del self._buf
    423        return arr

Consumes and leaks the `Bytes`, returning the contents as an `array[int]`,

A new empty array is returned if the underlying buffer is not initialized.

`self` will deallocate the underlying array, therefore it becomes unusable.

###### Safety

It is unsafe to access the leaked array from `self` after calling this function.

###### Example

    bytes = Bytes.from_str("chunks of data")
    consumed = bytes.leak()
    # `bytes` doesn't point to anything, this is undefined behavior.
    bytes.put(0)
    # access the array directly instead.
    consumed.tobytes() == b"chunks of data"

def as_ptr(self) -> 'memoryview[int]': View Source

    425    def as_ptr(self) -> memoryview[int]:
    426        """Returns a read-only pointer to the buffer data.
    427
    428        `pointer` here refers to a `memoryview` object.
    429
    430        A `BufferError` is raised if the underlying sequence is not initialized.
    431
    432        Example
    433        -------
    434        ```py
    435        buffer = Bytes.from_bytes(b"data")
    436        ptr = buffer.as_ptr()
    437        ptr[0] = 1 # TypeError: cannot modify read-only memory
    438        ```
    439        """
    440        return self.__buffer__(256).toreadonly()

Returns a read-only pointer to the buffer data.

`pointer` here refers to a `memoryview` object.

A `BufferError` is raised if the underlying sequence is not initialized.

###### Example

    buffer = Bytes.from_bytes(b"data")
    ptr = buffer.as_ptr()
    ptr[0] = 1 # TypeError: cannot modify read-only memory

def as_ref(self) -> sain.collections.slice.Slice[int]: View Source

    442    def as_ref(self) -> _slice.Slice[int]:
    443        """Get an immutable reference to the underlying sequence, without copying.
    444
    445        An empty slice is returned if the underlying sequence is not initialized.
    446
    447        Example
    448        -------
    449        ```py
    450        async def send_multipart(buf: Sequence[int]) -> None:
    451            ...
    452
    453        buffer = Bytes.from_bytes([0, 0, 0, 0])
    454        await send_multipart(buffer.as_ref()) # no copy.
    455        ```
    456        """
    457        if self._buf is not None:
    458            return _slice.Slice(self)
    459
    460        return _slice.Slice(())

Get an immutable reference to the underlying sequence, without copying.

An empty slice is returned if the underlying sequence is not initialized.

###### Example

    async def send_multipart(buf: Sequence[int]) -> None:
        ...

    buffer = Bytes.from_bytes([0, 0, 0, 0])
    await send_multipart(buffer.as_ref()) # no copy.

@safe
def to_mut(self) -> BytesMut: View Source

    462    @safe
    463    def to_mut(self) -> BytesMut:
    464        """Convert `self` into `BytesMut`.
    465
    466        This consumes `self` and returns a new `BytesMut` that points to the same underlying array,
    467        The conversion costs nothing.
    468
    469        Notes
    470        -----
    471        * If `self` is not initialized, a new empty `BytesMut` is returned.
    472        * `self` will no longer be usable, as it will not point to the underlying array.
    473
    474        The inverse method for this is `BytesMut.freeze()`
    475
    476        Example
    477        -------
    478        ```py
    479        def modify(buffer: Bytes) -> BytesMut:
    480            buf = buffer.to_mut() # doesn't cost anything.
    481            buf.swap(0, 1)
    482            return buf
    483
    484        buffer = Bytes.from_bytes([1, 2, 3, 4])
    485        new = modify(buffer)
    486        assert new == [2, 1, 3, 4]
    487        ```
    488        """
    489        # SAFETY: `Bytes.leak` returns an empty array
    490        # if `self` is uninitialized.
    491        return BytesMut.from_ptr_unchecked(self.leak())

Convert `self` into `BytesMut`.

This consumes `self` and returns a new `BytesMut` that points to the same underlying array, The conversion costs nothing.

###### Notes

- If `self` is not initialized, a new empty `BytesMut` is returned.
- `self` will no longer be usable, as it will not point to the underlying array.

The inverse method for this is `BytesMut.freeze()`

###### Example

    def modify(buffer: Bytes) -> BytesMut:
        buf = buffer.to_mut() # doesn't cost anything.
        buf.swap(0, 1)
        return buf

    buffer = Bytes.from_bytes([1, 2, 3, 4])
    new = modify(buffer)
    assert new == [2, 1, 3, 4]

def raw_parts(self) -> tuple[int, int]: View Source

    493    def raw_parts(
    494        self,
    495    ) -> tuple[int, int]:
    496        """Return `self` as tuple containing the memory address to the buffer and how many bytes it currently contains.
    497
    498        An alias to `array.buffer_into`
    499        """
    500        if not self._buf:
    501            return (0x0, 0)
    502
    503        return self._buf.buffer_info()

Return `self` as tuple containing the memory address to the buffer and how many bytes it currently contains.

An alias to `array.buffer_into`

def len(self) -> int: View Source

    505    def len(self) -> int:
    506        """Return the number of bytes in this buffer.
    507
    508        Example
    509        -------
    510        ```py
    511        buf = Bytes.from_bytes([240, 159, 146, 150])
    512        assert buf.len() == 4
    513        ```
    514        """
    515        return self.__len__()

Return the number of bytes in this buffer.

###### Example

    buf = Bytes.from_bytes([240, 159, 146, 150])
    assert buf.len() == 4

def size(self) -> int: View Source

    517    def size(self) -> int:
    518        """The length in bytes of one array item in the internal representation.
    519
    520
    521        An alias to `array.itemsize`
    522
    523        Example
    524        -------
    525        ```py
    526        buf = Bytes.from_bytes([240, 159, 146, 150])
    527        assert buf.size() == 1
    528        ```
    529        """
    530        if not self._buf:
    531            return 0
    532        return self._buf.itemsize

The length in bytes of one array item in the internal representation.

An alias to `array.itemsize`

###### Example

    buf = Bytes.from_bytes([240, 159, 146, 150])
    assert buf.size() == 1

def iter(self) -> sain.iter.TrustedIter[int]: View Source

    534    def iter(self) -> _iter.TrustedIter[int]:
    535        """Returns an iterator over the contained bytes.
    536
    537        This iterator yields all `int`s from start to end.
    538
    539        Example
    540        -------
    541        ```py
    542        buf = Bytes.from_bytes((1, 2, 3))
    543        iterator = buf.iter()
    544
    545        # map each byte to a character
    546        for element in iterator.map(chr):
    547            print(element)
    548        # ☺
    549        # ☻
    550        # ♥
    551        ```
    552        """
    553        return _iter.TrustedIter(self.as_ptr())

Returns an iterator over the contained bytes.

This iterator yields all `int`s from start to end.

###### Example

    buf = Bytes.from_bytes((1, 2, 3))
    iterator = buf.iter()

    # map each byte to a character
    for element in iterator.map(chr):
        print(element)
    # ☺
    # ☻
    # ♥

def chars(self) -> sain.Iterator[ctypes.c_char]: View Source

    555    def chars(self) -> Chars:
    556        """Returns an iterator over the characters of `Bytes`.
    557
    558        This iterator yields all `int`s from start to end mapped as a `ctypes.c_char`.
    559
    560        Example
    561        -------
    562        ```py
    563        b = Bytes.from_str("Hello")
    564        for char in b.chars():
    565            print(char)
    566
    567        # c_char(b'H')
    568        # c_char(b'e')
    569        # c_char(b'l')
    570        # c_char(b'l')
    571        # c_char(b'o')
    572        ```
    573        """
    574        # The built-in map is actually faster than our own pure python adapter impl.
    575        return _iter.Iter(map(_ctypes.c_char, self))

Returns an iterator over the characters of `Bytes`.

This iterator yields all `int`s from start to end mapped as a `ctypes.c_char`.

###### Example

    b = Bytes.from_str("Hello")
    for char in b.chars():
        print(char)

    # c_char(b'H')
    # c_char(b'e')
    # c_char(b'l')
    # c_char(b'l')
    # c_char(b'o')

def is_empty(self) -> bool: View Source

    577    def is_empty(self) -> bool:
    578        """Check whether `self` contains any bytes or not.
    579
    580        Example
    581        -------
    582        ```py
    583        buffer = Bytes()
    584        assert buffer.is_empty()
    585        ```
    586        """
    587        return not self._buf

Check whether `self` contains any bytes or not.

###### Example

    buffer = Bytes()
    assert buffer.is_empty()

def split_off(self, at: int) -> Bytes: View Source

    589    def split_off(self, at: int) -> Bytes:
    590        """Split the bytes off at the specified position, returning a new
    591        `Bytes` at the range of `[at : len]`, leaving `self` at `[at : bytes_len]`.
    592
    593        if this bytes is empty, `self` is returned unchanged.
    594
    595        Example
    596        -------
    597        ```py
    598        origin = Bytes.from_bytes((1, 2, 3, 4))
    599        split = origin.split_off(2)
    600
    601        print(origin, split)  # [1, 2], [3, 4]
    602        ```
    603
    604        Raises
    605        ------
    606        `RuntimeError`
    607            This method will raise if `at` > `len(self)`
    608        """
    609        len_ = self.len()
    610        if at > len_:
    611            raise RuntimeError(
    612                f"Index `at` ({at}) should be <= than len of `self` ({len_}) "
    613            ) from None
    614
    615        # Either the list is empty or uninit.
    616        if not self._buf:
    617            return self
    618
    619        split = self[at:len_]  # split the items into a new buffer.
    620        del self._buf[at:len_]  # remove the items from the original list.
    621        return split

Split the bytes off at the specified position, returning a new `Bytes` at the range of `[at : len]`, leaving `self` at `[at : bytes_len]`.

if this bytes is empty, `self` is returned unchanged.

###### Example

    origin = Bytes.from_bytes((1, 2, 3, 4))
    split = origin.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[tuple[int, Bytes]]': View Source

    623    def split_first(self) -> Option[tuple[int, Bytes]]:
    624        """Split the first and rest elements of the bytes, If empty, `None` is returned.
    625
    626        Example
    627        -------
    628        ```py
    629        buf = Bytes.from_bytes([1, 2, 3])
    630        split = buf.split_first()
    631        assert split == Some((1, [2, 3]))
    632        ```
    633        """
    634        if not self._buf:
    635            return _option.NOTHING
    636
    637        # optimized to only one element in the buffer.
    638        if self.len() == 1:
    639            return _option.Some((self[0], Bytes()))
    640
    641        first, rest = self[0], self[1:]
    642        return _option.Some((first, rest))

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

###### Example

    buf = Bytes.from_bytes([1, 2, 3])
    split = buf.split_first()
    assert split == Some((1, [2, 3]))

def split_last(self) -> 'Option[tuple[int, Bytes]]': View Source

    644    def split_last(self) -> Option[tuple[int, Bytes]]:
    645        """Returns the last and rest of the elements of the bytes, If `self` is empty, `None` is returned.
    646
    647        Example
    648        -------
    649        ```py
    650        buf = Bytes.from_bytes([0, 1, 2])
    651        last, elements = buf.split_last().unwrap()
    652        assert (last, elements) == (3, [1, 2])
    653        ```
    654        """
    655        if not self._buf:
    656            return _option.NOTHING
    657
    658        len_ = self.len()
    659        # optimized to only one element in the buffer.
    660        if len_ == 1:
    661            return _option.Some((self[0], Bytes()))
    662
    663        last, rest = self[-1], self[:-1]
    664        return _option.Some((last, rest))

Returns the last and rest of the elements of the bytes, If `self` is empty, `None` is returned.

###### Example

    buf = Bytes.from_bytes([0, 1, 2])
    last, elements = buf.split_last().unwrap()
    assert (last, elements) == (3, [1, 2])

def split_at( self, mid: int) -> tuple[Bytes, Bytes]: View Source

    666    def split_at(self, mid: int) -> tuple[Bytes, Bytes]:
    667        """Divide `self` into two at an index.
    668
    669        The first will contain all bytes from `[0:mid]` excluding `mid` it self.
    670        and the second will contain the remaining bytes.
    671
    672        if `mid` > `self.len()`, Then all bytes will be moved to the left,
    673        returning an empty bytes in right.
    674
    675        Example
    676        -------
    677        ```py
    678        buffer = Bytes.from_bytes((1, 2, 3, 4))
    679        left, right = buffer.split_at(0)
    680        assert left == [] and right == [1, 2, 3, 4]
    681
    682        left, right = buffer.split_at(2)
    683        assert left == [1, 2] and right == [2, 3]
    684        ```
    685
    686        The is roughly the implementation
    687        ```py
    688        self[0:mid], self[mid:]
    689        ```
    690        """
    691        return self[0:mid], self[mid:]

Divide `self` into two at an index.

The first will contain all bytes from `[0:mid]` excluding `mid` it self. and the second will contain the remaining bytes.

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

###### Example

    buffer = Bytes.from_bytes((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:]

@safe
def copy(self) -> Bytes: View Source

    695    @safe
    696    def copy(self) -> Bytes:
    697        """Create a copy of the bytes.
    698
    699        Example
    700        -------
    701        ```py
    702        original = Bytes.from_bytes([255, 255, 255, 0])
    703        copy = original.copy()
    704        ```
    705        """
    706        if not self._buf:
    707            return Bytes()
    708
    709        # SAFETY: `self._buf` is initialized.
    710        return self.from_ptr_unchecked(self._buf[:])

Create a copy of the bytes.

###### Example

    original = Bytes.from_bytes([255, 255, 255, 0])
    copy = original.copy()

def index(self, v: int, start: int = 0, stop: int = 9223372036854775807) -> int: View Source

    712    def index(self, v: int, start: int = 0, stop: int = _sys.maxsize) -> int:
    713        """Return the smallest `i` such that `i` is the index of the first occurrence of `v` in the buffer.
    714
    715        The optional arguments start and stop can be specified to search for x within a
    716        subsection of the array. Raise ValueError if x is not found
    717        """
    718        if not self._buf:
    719            raise ValueError from None
    720
    721        return self._buf.index(v, start, stop)

Return the smallest `i` such that `i` is the index of the first occurrence of `v` in the buffer.

The optional arguments start and stop can be specified to search for x within a subsection of the array. Raise ValueError if x is not found

def count(self, x: int) -> int: View Source

    723    def count(self, x: int) -> int:
    724        """Return the number of occurrences of `x` in the buffer.
    725
    726        Example
    727        --------
    728        ```py
    729        buf = Bytes([32, 32, 31])
    730        assert buf.count(32) == 2
    731        ```
    732        """
    733        if self._buf is None:
    734            return 0
    735
    736        return self._buf.count(x)

Return the number of occurrences of `x` in the buffer.

###### Example

    buf = Bytes([32, 32, 31])
    assert buf.count(32) == 2

##### Inherited Members

sain.convert.ToString
  ToString
  to_string
sain.collections.slice.SpecContains
  contains

@rustc_diagnostic_item('&mut [u8]')
@typing.final
class BytesMut(sain.collections.Bytes, collections.abc.MutableSequence[int]): View Source

     878@rustc_diagnostic_item("&mut [u8]")
     879@typing.final
     880class BytesMut(
     881    Bytes,  # pyright: ignore - we want to inherit from `Bytes`.
     882    collections.MutableSequence[int],
     883):
     884    """Provides mutable abstractions for working with bytes.
     885
     886    It is an efficient container for storing and operating with bytes,
     887    It is built on-top of `array.array[int]`, which means you get all of `array[int]`'s operations.
     888
     889    A `bytes` object is usually used within networking applications, but can also be used
     890    elsewhere as well.
     891
     892    ## Construction
     893    You can create a `BytesMut` object in multiple ways.
     894
     895    * `BytesMut()`: Initialize an empty `BytesMut` object
     896    * `from_str`: Create `BytesMut` from `str`
     897    * `from_bytes`: Create `BytesMut` from a `Buffer` bytes-like type
     898    * `from_raw`: Create `BytesMut` from a `Rawish` type
     899    * `from_ptr`: Create `BytesMut` that points to an `array.array[int]` without copying it
     900    * `BytesMut.zeroed(count)`: Create `BytesMut` filled with `zeroes * count`.
     901
     902    Example
     903    -------
     904    ```py
     905    from sain import BytesNut
     906
     907    buf = BytesMut()
     908    buffer.put_bytes(b"Hello")
     909    print(buffer) # [72, 101, 108, 108, 111]
     910
     911    buf.put(32) # space
     912    assert buffer.to_bytes() == b"Hello "
     913    ```
     914    """
     915
     916    __slots__ = ("_buf",)
     917
     918    def __init__(self) -> None:
     919        """Creates a new empty `BytesMut`.
     920
     921        This won't allocate the array and the returned `BytesMut` will be empty.
     922        """
     923        super().__init__()
     924
     925    # default methods.
     926
     927    def extend(self, src: Buffer) -> None:
     928        """Extend `self` from a `src`.
     929
     930        Example
     931        -------
     932        ```py
     933        buf = Bytes()
     934        buf.extend([1, 2, 3])
     935        assert buf == [1, 2, 3]
     936        ```
     937
     938        Parameters
     939        ----------
     940        src : `Buffer`
     941            Can be one of `Bytes`, `bytes`, `bytearray` or `Sequence[int]`
     942
     943        Raises
     944        ------
     945        `OverflowError`
     946            If `src` not in range of `0..255`
     947        """
     948        if self._buf is None:
     949            # If it was `None`, we initialize it with a source instead of extending.
     950            self._buf = array.array("B", src)
     951        else:
     952            self._buf.extend(src)
     953
     954    def put(self, src: int) -> None:
     955        """Append a byte at the end of the array.
     956
     957        unlike `.put_bytes`, this method appends instead of extending the array
     958        which is faster if you're putting a single byte in a single call.
     959
     960        Example
     961        -------
     962        ```py
     963        buf = Bytes()
     964        buf.put(32) # append a space to the end of the buffer
     965        assert buf.to_bytes() == b' '
     966        ```
     967
     968        Parameters
     969        ----------
     970        src : `int`
     971            An unsigned integer, also known as `u8` to put.
     972
     973        Raises
     974        ------
     975        `OverflowError`
     976            If `src` not in range of `0..255`
     977        """
     978        if self._buf is None:
     979            # If it was `None`, we initialize it with a source instead of appending.
     980            self._buf = array.array("B", [src])
     981        else:
     982            self._buf.append(src)
     983
     984    def put_float(self, src: float) -> None:
     985        r"""Writes a single-precision (4 bytes) floating point number to `self` in big-endian byte order.
     986
     987        The valid range for the float value is `-3.402823466e38` to `3.402823466e38`.
     988
     989        Example
     990        -------
     991        ```py
     992        buf = BytesMut()
     993        buf.put_float(1.2)
     994        assert buf.to_bytes() == b'\x3f\x99\x99\x9a'
     995        ```
     996
     997        Raises
     998        ------
     999        `OverflowError`
    1000            If `src` is out of range.
    1001        """
    1002        assert_precondition(
    1003            -3.402823466e38 <= src <= 3.402823466e38,
    1004            f"Float {src} is out of range for a single-precision float",
    1005            OverflowError,
    1006        )
    1007        bits = struct.pack(">f", src)
    1008
    1009        if self._buf is None:
    1010            self._buf = array.array("B", bits)
    1011        else:
    1012            self._buf.extend(bits)
    1013
    1014    def put_char(self, char: str) -> None:
    1015        """Append a single character to the buffer.
    1016
    1017        This is the same as `self.put(ord(char))`.
    1018
    1019        Example
    1020        -------
    1021        ```py
    1022        buf = BytesMut()
    1023        buf.put_char('a')
    1024        assert buf == b"a"
    1025        ```
    1026
    1027        Parameters
    1028        ----------
    1029        char : `str`
    1030            The character to put.
    1031        """
    1032        assert (ln := len(char)) == 1, f"Expected a single character, got {ln}"
    1033        self.put(ord(char))
    1034
    1035    def put_raw(self, src: Rawish) -> None:
    1036        """Extend `self` from a raw data type source.
    1037
    1038        Example
    1039        -------
    1040        ```py
    1041        buffer = BytesMut()
    1042        # A file descriptor's contents
    1043        with open('file.txt', 'rb') as file:
    1044            buffer.put_raw(file)
    1045
    1046        # bytes io
    1047        buffer.put(io.BytesIO(b"data"))
    1048        # string io
    1049        buffer.put(io.StringIO("data"))
    1050        ```
    1051
    1052        Parameters
    1053        ----------
    1054        src : `Rawish`
    1055            A valid raw data type. See `Rawish` for more details.
    1056
    1057        Raises
    1058        ------
    1059        `OverflowError`
    1060            If `src` not in range of `0..255`
    1061        """
    1062        if self._buf is None:
    1063            # If it was `None`, we initialize it with a source instead of extending.
    1064            self._buf = array.array("B", unwrap_bytes(src))
    1065        else:
    1066            self._buf.extend(unwrap_bytes(src))
    1067
    1068    def put_bytes(self, src: Buffer) -> None:
    1069        """Put `bytes` into `self`.
    1070
    1071        Example
    1072        -------
    1073        ```py
    1074        buf = BytesMut.from_bytes(b"hello")
    1075        buf.put_bytes([32, 119, 111, 114, 108, 100])
    1076        assert buf == b"hello world"
    1077        ```
    1078
    1079        Parameters
    1080        ----------
    1081        src : `Buffer`
    1082            Can be one of `Bytes`, `bytes`, `bytearray` or `Sequence[int]`
    1083
    1084        Raises
    1085        ------
    1086        `OverflowError`
    1087            If `src` not in range of `0..255`
    1088        """
    1089        if self._buf is None:
    1090            # If it was `None`, we initialize it with a source instead of extending.
    1091            self._buf = array.array("B", src)
    1092        else:
    1093            self._buf.extend(src)
    1094
    1095    def put_str(self, s: str) -> None:
    1096        """Put a `utf-8` encoded bytes from a string.
    1097
    1098        Example
    1099        -------
    1100        ```py
    1101        buffer = BytesMut()
    1102        buffer.put_str("hello")
    1103
    1104        assert buffer == b"hello"
    1105        ```
    1106
    1107        Parameters
    1108        ----------
    1109        src: `str`
    1110            The string
    1111        """
    1112        self.put_bytes(s.encode(ENCODING))
    1113
    1114    def replace(self, index: int, byte: int) -> None:
    1115        """Replace the byte at `index` with `byte`.
    1116
    1117        This method is `NOOP` if:
    1118        -------------------------
    1119        * `self` is empty or unallocated.
    1120        * `index` is out of range.
    1121
    1122        Example
    1123        -------
    1124        ```py
    1125        buf = BytesMut.from_bytes([1, 2, 3])
    1126        buf.replace(1, 4)
    1127        assert buf == [1, 4, 3]
    1128        ```
    1129        """
    1130        if not self._buf or index < 0 or index >= self.len():
    1131            return
    1132
    1133        self._buf[index] = byte
    1134
    1135    def replace_with(self, index: int, f: collections.Callable[[int], int]) -> None:
    1136        """Replace the byte at `index` with a byte returned from `f`.
    1137
    1138        The signature of `f` is `Fn(int) -> int`, where the argument is the old byte.
    1139
    1140        ## This method is `NOOP` if:
    1141        * `self` is empty or unallocated.
    1142        * `index` is out of range.
    1143
    1144        Example
    1145        -------
    1146        ```py
    1147        buf = BytesMut.from_bytes([1, 2, 3])
    1148        buf.replace_with(1, lambda prev: prev * 2)
    1149        assert buf == [1, 4, 3]
    1150        ```
    1151        """
    1152        if not self._buf or index < 0 or index >= self.len():
    1153            return
    1154
    1155        old = self._buf[index]
    1156        self._buf[index] = f(old)
    1157
    1158    def offset(self, f: collections.Callable[[int], int]) -> None:
    1159        """Modify each byte in the buffer with a new byte returned from `f`.
    1160
    1161        The signature of `f` is `Fn(int) -> int`, where the argument is the previous byte.
    1162
    1163        Example
    1164        -------
    1165        ```py
    1166        buf = BytesMut.from_bytes([1, 2, 3])
    1167        buf.offset(lambda prev: prev * 2)
    1168        assert buf == [2, 4, 6]
    1169        ```
    1170
    1171        This method is `NOOP` if `self` is empty or unallocated.
    1172        """
    1173
    1174        if not self._buf:
    1175            return
    1176
    1177        for index in range(len(self._buf)):
    1178            self._buf[index] = f(self._buf[index])
    1179
    1180    def fill(self, value: int) -> None:
    1181        """Fills `self` with the given byte.
    1182
    1183        Nothing happens if the buffer is empty or unallocated.
    1184
    1185        Example
    1186        -------
    1187        ```py
    1188        a = Bytes.from_bytes([0, 1, 2, 3])
    1189        a.fill(0)
    1190        assert a == [0, 0, 0, 0]
    1191        ```
    1192        """
    1193        if not self._buf:
    1194            return
    1195
    1196        self.as_mut_ptr()[:] = bytearray([value] * self.len())
    1197
    1198    def fill_with(self, f: collections.Callable[[], int]) -> None:
    1199        """Fills `self` with the given byte returned from `f`.
    1200
    1201        Nothing happens if the buffer is empty or unallocated.
    1202
    1203        Example
    1204        -------
    1205        ```py
    1206        def default() -> int:
    1207            return 0
    1208
    1209        a = Bytes.from_bytes([0, 1, 2, 3])
    1210        a.fill_with(default)
    1211        assert a == [0, 0, 0, 0]
    1212        ```
    1213        """
    1214        if not self._buf:
    1215            return
    1216
    1217        self.as_mut_ptr()[:] = bytearray([f()] * self.len())
    1218
    1219    def swap(self, a: int, b: int):
    1220        """Swap two bytes in the buffer.
    1221
    1222        if `a` equals to `b` then it's guaranteed that elements won't change value.
    1223
    1224        Example
    1225        -------
    1226        ```py
    1227        buf = Bytes.from_bytes([1, 2, 3, 4])
    1228        buf.swap(0, 3)
    1229        assert buf == [4, 2, 3, 1]
    1230        ```
    1231
    1232        Raises
    1233        ------
    1234        IndexError
    1235            If the positions of `a` or `b` are out of index.
    1236        """
    1237        if self[a] == self[b]:
    1238            return
    1239
    1240        self[a], self[b] = self[b], self[a]
    1241
    1242    def swap_unchecked(self, a: int, b: int):
    1243        """Swap two bytes in the buffer. without checking if `a` == `b`.
    1244
    1245        If you care about `a` and `b` equality, see `Bytes.swap`.
    1246
    1247        Example
    1248        -------
    1249        ```py
    1250        buf = Bytes.from_bytes([1, 2, 3, 1])
    1251        buf.swap_unchecked(0, 3)
    1252        assert buf == [1, 2, 3, 1]
    1253        ```
    1254
    1255        Raises
    1256        ------
    1257        IndexError
    1258            If the positions of `a` or `b` are out of index.
    1259        """
    1260        self[a], self[b] = self[b], self[a]
    1261
    1262    def as_mut_ptr(self) -> memoryview[int]:
    1263        """Returns a mutable pointer to the buffer data.
    1264
    1265        `pointer` here refers to a `memoryview` object.
    1266
    1267        A `BufferError` is raised if the underlying sequence is not initialized.
    1268
    1269        Example
    1270        -------
    1271        ```py
    1272        buffer = BytesMut.from_str("ouv")
    1273        ptr = buffer.as_mut_ptr()
    1274        ptr[0] = ord(b'L')
    1275        assert buffer.to_bytes() == b"Luv"
    1276        ```
    1277        """
    1278        return self.__buffer__(512)
    1279
    1280    def as_mut(self) -> _slice.SliceMut[int]:
    1281        """Get a mutable reference to the underlying sequence, without copying.
    1282
    1283        An empty slice is returned if the underlying sequence is not initialized.
    1284
    1285        Example
    1286        -------
    1287        ```py
    1288        buff = BytesMut.from_str("Hello")
    1289        ref = buff.as_mut()
    1290        ref.append(32)
    1291        del ref
    1292        assert buff == b"Hello "
    1293        ```
    1294        """
    1295        if self._buf is not None:
    1296            return _slice.SliceMut(self)
    1297
    1298        return _slice.SliceMut([])
    1299
    1300    @safe
    1301    def freeze(self) -> Bytes:
    1302        """Convert `self` into an immutable `Bytes`.
    1303
    1304        This conversion is zero-cost, meaning it doesn't any _hidden-copy_ operations behind the scenes.
    1305        This consumes `self` and returns a new `Bytes` that points to the same underlying array,
    1306
    1307        Notes
    1308        -----
    1309        * If `self` is not initialized, a new empty `Bytes` is returned.
    1310        * `self` will no longer be usable, as it will not point to the underlying array.
    1311
    1312        The inverse method of this is `Bytes.to_mut()`
    1313
    1314        Example
    1315        -------
    1316        ```py
    1317        def shrink_to(cap: int, buffer: BytesMut) -> Bytes:
    1318            buf.truncate(cap)
    1319            return buf.freeze()
    1320
    1321        buffer = BytesMut.from_bytes([32, 23, 34, 65])
    1322        # accessing `buffer` after this is undefined behavior.
    1323        modified = shrink_to(2, buffer)
    1324        assert modified == [32, 23]
    1325        ```
    1326        """
    1327        # SAFETY: `Bytes.leak` returns an empty array
    1328        # if `self` is uninitialized.
    1329        return Bytes.from_ptr_unchecked(self.leak())
    1330
    1331    def swap_remove(self, byte: int) -> int:
    1332        """Remove the first appearance of `item` from this buffer and return it.
    1333
    1334        Raises
    1335        ------
    1336        * `ValueError`: if `item` is not in this buffer.
    1337        * `MemoryError`: if this buffer hasn't allocated, Aka nothing has been pushed to it.
    1338
    1339        Example
    1340        -------
    1341        ```py
    1342        buf = BytesMut.from_bytes([1, 2, 3, 4])
    1343        assert 1 == buf.swap_remove(1)
    1344        assert buf == [2, 3, 4]
    1345        ```
    1346        """
    1347        if self._buf is None:
    1348            raise MemoryError("`self` is unallocated.") from None
    1349
    1350        return self._buf.pop(self.index(byte))
    1351
    1352    def truncate(self, size: int) -> None:
    1353        """Shortens the bytes, keeping the first `size` elements and dropping the rest.
    1354
    1355        Example
    1356        -------
    1357        ```py
    1358        buf = BytesMut.from_bytes([0, 0, 0, 0])
    1359        buf.truncate(1)
    1360        assert buf.len() == 1
    1361        ```
    1362        """
    1363        if not self._buf:
    1364            return
    1365
    1366        del self._buf[size:]
    1367
    1368    def split_off_mut(self, at: int) -> BytesMut:
    1369        """Split the bytes off at the specified position, returning a new
    1370        `BytesMut` at the range of `[at : len]`, leaving `self` at `[at : bytes_len]`.
    1371
    1372        if this bytes is empty, `self` is returned unchanged.
    1373
    1374        Example
    1375        -------
    1376        ```py
    1377        origin = BytesMut.from_bytes((1, 2, 3, 4))
    1378        split = origin.split_off_mut(2)
    1379
    1380        print(origin, split)  # [1, 2], [3, 4]
    1381        ```
    1382
    1383        Raises
    1384        ------
    1385        `IndexError`
    1386            This method will raise if `at` > `len(self)`
    1387        """
    1388        len_ = self.len()
    1389        if at > len_:
    1390            raise IndexError(
    1391                f"the index of `at` ({at}) should be <= than len of `self` ({len_}) "
    1392            ) from None
    1393
    1394        if not self._buf:
    1395            return self
    1396
    1397        split = BytesMut.from_ptr(self._buf[at:len_])
    1398        del self._buf[at:len_]
    1399        return split
    1400
    1401    def split_first_mut(self) -> Option[tuple[int, BytesMut]]:
    1402        """Split the first and rest elements of the bytes, If empty, `None` is returned.
    1403
    1404        Returns a tuple of (first, rest) where rest is a mutable sequence.
    1405
    1406        Example
    1407        -------
    1408        ```py
    1409        buf = BytesMut.from_bytes([1, 2, 3])
    1410        split = buf.split_first_mut()
    1411        assert split == Some((1, [2, 3]))
    1412        ```
    1413        """
    1414        if not self._buf:
    1415            return _option.NOTHING
    1416
    1417        if self.len() == 1:
    1418            return _option.Some((self[0], BytesMut()))
    1419
    1420        first = self[0]
    1421        rest = self[1:]
    1422        return _option.Some((first, rest))
    1423
    1424    def split_last_mut(self) -> Option[tuple[int, Bytes]]:
    1425        """Returns the last and rest of the elements of the bytes, If `self` is empty, `None` is returned.
    1426
    1427        Returns a tuple of (last, rest) where rest is a mutable sequence.
    1428
    1429        Example
    1430        -------
    1431        ```py
    1432        buf = BytesMut.from_bytes([0, 1, 2])
    1433        last, elements = buf.split_last_mut().unwrap()
    1434        assert (last, elements) == (2, [0, 1])
    1435        ```
    1436        """
    1437        if not self._buf:
    1438            return _option.NOTHING
    1439
    1440        len_ = self.len()
    1441        if len_ == 1:
    1442            return _option.Some((self[0], BytesMut()))
    1443
    1444        last = self[-1]
    1445        rest = self[:-1]
    1446        return _option.Some((last, rest))
    1447
    1448    def split_at_mut(self, mid: int) -> tuple[BytesMut, BytesMut]:
    1449        """Divide `self` into two at an index.
    1450
    1451        The first will contain all bytes from `[0:mid]` excluding `mid` itself.
    1452        and the second will contain the remaining bytes.
    1453
    1454        if `mid` > `self.len()`, Then all bytes will be moved to the left,
    1455        returning an empty bytes in right.
    1456
    1457        Example
    1458        -------
    1459        ```py
    1460        buffer = BytesMut.from_bytes((1, 2, 3, 4))
    1461        left, right = buffer.split_at_mut(0)
    1462        assert left == [] and right == [1, 2, 3, 4]
    1463
    1464        left, right = buffer.split_at_mut(2)
    1465        assert left == [1, 2] and right == [3, 4]
    1466        ```
    1467
    1468        The is roughly the implementation
    1469        ```py
    1470        self[0:mid], self[mid:]
    1471        ```
    1472        """
    1473        return self[0:mid], self[mid:]
    1474
    1475    # * Layout * #
    1476
    1477    def insert(self, index: int, value: int) -> None:
    1478        """Insert a new item with `value` in the buffer before position `index`.
    1479
    1480        Negative values are treated as being relative to the end of the buffer.
    1481        """
    1482        if self._buf is None:
    1483            return
    1484
    1485        self._buf.insert(index, value)
    1486
    1487    def pop(self, i: int = -1) -> Option[int]:
    1488        """Removes the last element from the buffer and returns it, `Some(None)` if it is empty.
    1489
    1490        Example
    1491        -------
    1492        ```py
    1493        buf = BytesMut((21, 32, 44))
    1494        assert buf.pop() == Some(44)
    1495        ```
    1496        """
    1497        if not self._buf:
    1498            return _option.NOTHING
    1499
    1500        return _option.Some(self._buf.pop(i))
    1501
    1502    def remove(self, i: int) -> None:
    1503        """Remove the first appearance of `i` from `self`.
    1504
    1505        Example
    1506        ------
    1507        ```py
    1508        buf = BytesMut.from_bytes([1, 1, 2, 3, 4])
    1509        buf.remove(1)
    1510        print(buf) # [1, 2, 3, 4]
    1511        ```
    1512        """
    1513        if not self._buf:
    1514            return
    1515
    1516        self._buf.remove(i)
    1517
    1518    def clear(self) -> None:
    1519        """Clear the buffer.
    1520
    1521        Example
    1522        -------
    1523        ```py
    1524        buf = BytesMut.from_bytes([255])
    1525        buf.clear()
    1526
    1527        assert buf.is_empty()
    1528        ```
    1529        """
    1530        if not self._buf:
    1531            return
    1532
    1533        del self._buf[:]
    1534
    1535    def byteswap(self) -> None:
    1536        """Swap the byte order of the bytes in `self`."""
    1537        if not self._buf:
    1538            return
    1539
    1540        self._buf.byteswap()
    1541
    1542    def copy(self) -> BytesMut:
    1543        """Create a copy of the bytes.
    1544
    1545        Example
    1546        -------
    1547        ```py
    1548        original = BytesMut.from_bytes([255, 255, 255, 0])
    1549        copy = original.copy()
    1550        ```
    1551        """
    1552        if not self._buf:
    1553            return BytesMut()
    1554
    1555        return self.from_ptr(self._buf[:])
    1556
    1557    def __setitem__(self, index: int, value: int):
    1558        if not self._buf:
    1559            raise IndexError("index out of range")
    1560
    1561        self._buf[index] = value
    1562
    1563    def __delitem__(self, key: typing.SupportsIndex | slice, /) -> None:
    1564        if not self._buf:
    1565            raise IndexError("index out of range")
    1566
    1567        del self._buf[key]
    1568
    1569    @typing.overload
    1570    def __getitem__(self, index: slice) -> BytesMut: ...
    1571
    1572    @typing.overload
    1573    def __getitem__(self, index: int) -> int: ...
    1574
    1575    @safe
    1576    def __getitem__(self, index: int | slice) -> int | BytesMut:
    1577        if not self._buf:
    1578            raise IndexError("index out of range")
    1579
    1580        if isinstance(index, slice):
    1581            # SAFETY: `self._buf` is initialized.
    1582            return self.from_ptr_unchecked(self._buf[index])
    1583
    1584        return self._buf[index]
    1585
    1586    @safe
    1587    def __copy__(self) -> BytesMut:
    1588        if not self._buf:
    1589            return BytesMut()
    1590
    1591        return BytesMut.from_ptr_unchecked(self._buf.__copy__())
    1592
    1593    @safe
    1594    def __deepcopy__(self, unused: typing.Any, /) -> BytesMut:
    1595        if not self._buf:
    1596            return BytesMut()
    1597
    1598        return BytesMut.from_ptr_unchecked(self._buf.__deepcopy__(unused))

Provides mutable abstractions for working with bytes.

It is an efficient container for storing and operating with bytes, It is built on-top of `array.array[int]`, which means you get all of `array[int]`'s operations.

A `bytes` object is usually used within networking applications, but can also be used elsewhere as well.

## Construction

You can create a `BytesMut` object in multiple ways.

- `BytesMut()`: Initialize an empty `BytesMut` object
- `from_str`: Create `BytesMut` from `str`
- `from_bytes`: Create `BytesMut` from a `Buffer` bytes-like type
- `from_raw`: Create `BytesMut` from a `Rawish` type
- `from_ptr`: Create `BytesMut` that points to an `array.array[int]` without copying it
- `BytesMut.zeroed(count)`: Create `BytesMut` filled with `zeroes * count`.

###### Example

    from sain import BytesNut

    buf = BytesMut()
    buffer.put_bytes(b"Hello")
    print(buffer) # [72, 101, 108, 108, 111]

    buf.put(32) # space
    assert buffer.to_bytes() == b"Hello "

# Implementations

This class implements &mut [u8] in Rust.

def extend(self, src: bytes | bytearray | Iterable[int]) -> None: View Source

    927    def extend(self, src: Buffer) -> None:
    928        """Extend `self` from a `src`.
    929
    930        Example
    931        -------
    932        ```py
    933        buf = Bytes()
    934        buf.extend([1, 2, 3])
    935        assert buf == [1, 2, 3]
    936        ```
    937
    938        Parameters
    939        ----------
    940        src : `Buffer`
    941            Can be one of `Bytes`, `bytes`, `bytearray` or `Sequence[int]`
    942
    943        Raises
    944        ------
    945        `OverflowError`
    946            If `src` not in range of `0..255`
    947        """
    948        if self._buf is None:
    949            # If it was `None`, we initialize it with a source instead of extending.
    950            self._buf = array.array("B", src)
    951        else:
    952            self._buf.extend(src)

Extend `self` from a `src`.

###### Example

    buf = Bytes()
    buf.extend([1, 2, 3])
    assert buf == [1, 2, 3]

###### Parameters

- src (`Buffer`): Can be one of `Bytes`, `bytes`, `bytearray` or `Sequence[int]`

###### Raises

- `OverflowError`: If `src` not in range of `0..255`

def put(self, src: int) -> None: View Source

    954    def put(self, src: int) -> None:
    955        """Append a byte at the end of the array.
    956
    957        unlike `.put_bytes`, this method appends instead of extending the array
    958        which is faster if you're putting a single byte in a single call.
    959
    960        Example
    961        -------
    962        ```py
    963        buf = Bytes()
    964        buf.put(32) # append a space to the end of the buffer
    965        assert buf.to_bytes() == b' '
    966        ```
    967
    968        Parameters
    969        ----------
    970        src : `int`
    971            An unsigned integer, also known as `u8` to put.
    972
    973        Raises
    974        ------
    975        `OverflowError`
    976            If `src` not in range of `0..255`
    977        """
    978        if self._buf is None:
    979            # If it was `None`, we initialize it with a source instead of appending.
    980            self._buf = array.array("B", [src])
    981        else:
    982            self._buf.append(src)

Append a byte at the end of the array.

unlike `.put_bytes`, this method appends instead of extending the array which is faster if you're putting a single byte in a single call.

###### Example

    buf = Bytes()
    buf.put(32) # append a space to the end of the buffer
    assert buf.to_bytes() == b' '

###### Parameters

- src (`int`): An unsigned integer, also known as `u8` to put.

###### Raises

- `OverflowError`: If `src` not in range of `0..255`

def put_float(self, src: float) -> None: View Source

     984    def put_float(self, src: float) -> None:
     985        r"""Writes a single-precision (4 bytes) floating point number to `self` in big-endian byte order.
     986
     987        The valid range for the float value is `-3.402823466e38` to `3.402823466e38`.
     988
     989        Example
     990        -------
     991        ```py
     992        buf = BytesMut()
     993        buf.put_float(1.2)
     994        assert buf.to_bytes() == b'\x3f\x99\x99\x9a'
     995        ```
     996
     997        Raises
     998        ------
     999        `OverflowError`
    1000            If `src` is out of range.
    1001        """
    1002        assert_precondition(
    1003            -3.402823466e38 <= src <= 3.402823466e38,
    1004            f"Float {src} is out of range for a single-precision float",
    1005            OverflowError,
    1006        )
    1007        bits = struct.pack(">f", src)
    1008
    1009        if self._buf is None:
    1010            self._buf = array.array("B", bits)
    1011        else:
    1012            self._buf.extend(bits)

Writes a single-precision (4 bytes) floating point number to `self` in big-endian byte order.

The valid range for the float value is `-3.402823466e38` to `3.402823466e38`.

###### Example

    buf = BytesMut()
    buf.put_float(1.2)
    assert buf.to_bytes() == b'\x3f\x99\x99\x9a'

###### Raises

- `OverflowError`: If `src` is out of range.

def put_char(self, char: str) -> None: View Source

    1014    def put_char(self, char: str) -> None:
    1015        """Append a single character to the buffer.
    1016
    1017        This is the same as `self.put(ord(char))`.
    1018
    1019        Example
    1020        -------
    1021        ```py
    1022        buf = BytesMut()
    1023        buf.put_char('a')
    1024        assert buf == b"a"
    1025        ```
    1026
    1027        Parameters
    1028        ----------
    1029        char : `str`
    1030            The character to put.
    1031        """
    1032        assert (ln := len(char)) == 1, f"Expected a single character, got {ln}"
    1033        self.put(ord(char))

Append a single character to the buffer.

This is the same as `self.put(ord(char))`.

###### Example

    buf = BytesMut()
    buf.put_char('a')
    assert buf == b"a"

###### Parameters

- char (`str`): The character to put.

def put_raw(self, src: _io.StringIO | _io.BytesIO | _io.BufferedReader) -> None: View Source

    1035    def put_raw(self, src: Rawish) -> None:
    1036        """Extend `self` from a raw data type source.
    1037
    1038        Example
    1039        -------
    1040        ```py
    1041        buffer = BytesMut()
    1042        # A file descriptor's contents
    1043        with open('file.txt', 'rb') as file:
    1044            buffer.put_raw(file)
    1045
    1046        # bytes io
    1047        buffer.put(io.BytesIO(b"data"))
    1048        # string io
    1049        buffer.put(io.StringIO("data"))
    1050        ```
    1051
    1052        Parameters
    1053        ----------
    1054        src : `Rawish`
    1055            A valid raw data type. See `Rawish` for more details.
    1056
    1057        Raises
    1058        ------
    1059        `OverflowError`
    1060            If `src` not in range of `0..255`
    1061        """
    1062        if self._buf is None:
    1063            # If it was `None`, we initialize it with a source instead of extending.
    1064            self._buf = array.array("B", unwrap_bytes(src))
    1065        else:
    1066            self._buf.extend(unwrap_bytes(src))

Extend `self` from a raw data type source.

###### Example

    buffer = BytesMut()
    # A file descriptor's contents
    with open('file.txt', 'rb') as file:
        buffer.put_raw(file)

    # bytes io
    buffer.put(io.BytesIO(b"data"))
    # string io
    buffer.put(io.StringIO("data"))

###### Parameters

- src (`Rawish`): A valid raw data type. See `Rawish` for more details.

###### Raises

- `OverflowError`: If `src` not in range of `0..255`

def put_bytes(self, src: bytes | bytearray | Iterable[int]) -> None: View Source

    1068    def put_bytes(self, src: Buffer) -> None:
    1069        """Put `bytes` into `self`.
    1070
    1071        Example
    1072        -------
    1073        ```py
    1074        buf = BytesMut.from_bytes(b"hello")
    1075        buf.put_bytes([32, 119, 111, 114, 108, 100])
    1076        assert buf == b"hello world"
    1077        ```
    1078
    1079        Parameters
    1080        ----------
    1081        src : `Buffer`
    1082            Can be one of `Bytes`, `bytes`, `bytearray` or `Sequence[int]`
    1083
    1084        Raises
    1085        ------
    1086        `OverflowError`
    1087            If `src` not in range of `0..255`
    1088        """
    1089        if self._buf is None:
    1090            # If it was `None`, we initialize it with a source instead of extending.
    1091            self._buf = array.array("B", src)
    1092        else:
    1093            self._buf.extend(src)

Put `bytes` into `self`.

###### Example

    buf = BytesMut.from_bytes(b"hello")
    buf.put_bytes([32, 119, 111, 114, 108, 100])
    assert buf == b"hello world"

###### Parameters

- src (`Buffer`): Can be one of `Bytes`, `bytes`, `bytearray` or `Sequence[int]`

###### Raises

- `OverflowError`: If `src` not in range of `0..255`

def put_str(self, s: str) -> None: View Source

    1095    def put_str(self, s: str) -> None:
    1096        """Put a `utf-8` encoded bytes from a string.
    1097
    1098        Example
    1099        -------
    1100        ```py
    1101        buffer = BytesMut()
    1102        buffer.put_str("hello")
    1103
    1104        assert buffer == b"hello"
    1105        ```
    1106
    1107        Parameters
    1108        ----------
    1109        src: `str`
    1110            The string
    1111        """
    1112        self.put_bytes(s.encode(ENCODING))

Put a `utf-8` encoded bytes from a string.

###### Example

    buffer = BytesMut()
    buffer.put_str("hello")

    assert buffer == b"hello"

###### Parameters

- src (`str`): The string

def replace(self, index: int, byte: int) -> None: View Source

    1114    def replace(self, index: int, byte: int) -> None:
    1115        """Replace the byte at `index` with `byte`.
    1116
    1117        This method is `NOOP` if:
    1118        -------------------------
    1119        * `self` is empty or unallocated.
    1120        * `index` is out of range.
    1121
    1122        Example
    1123        -------
    1124        ```py
    1125        buf = BytesMut.from_bytes([1, 2, 3])
    1126        buf.replace(1, 4)
    1127        assert buf == [1, 4, 3]
    1128        ```
    1129        """
    1130        if not self._buf or index < 0 or index >= self.len():
    1131            return
    1132
    1133        self._buf[index] = byte

Replace the byte at `index` with `byte`.

## This method is `NOOP` if:

- `self` is empty or unallocated.
- `index` is out of range.

###### Example

    buf = BytesMut.from_bytes([1, 2, 3])
    buf.replace(1, 4)
    assert buf == [1, 4, 3]

def replace_with(self, index: int, f: Callable[[int], int]) -> None: View Source

    1135    def replace_with(self, index: int, f: collections.Callable[[int], int]) -> None:
    1136        """Replace the byte at `index` with a byte returned from `f`.
    1137
    1138        The signature of `f` is `Fn(int) -> int`, where the argument is the old byte.
    1139
    1140        ## This method is `NOOP` if:
    1141        * `self` is empty or unallocated.
    1142        * `index` is out of range.
    1143
    1144        Example
    1145        -------
    1146        ```py
    1147        buf = BytesMut.from_bytes([1, 2, 3])
    1148        buf.replace_with(1, lambda prev: prev * 2)
    1149        assert buf == [1, 4, 3]
    1150        ```
    1151        """
    1152        if not self._buf or index < 0 or index >= self.len():
    1153            return
    1154
    1155        old = self._buf[index]
    1156        self._buf[index] = f(old)

Replace the byte at `index` with a byte returned from `f`.

The signature of `f` is `Fn(int) -> int`, where the argument is the old byte.

## This method is `NOOP` if:

- `self` is empty or unallocated.
- `index` is out of range.

###### Example

    buf = BytesMut.from_bytes([1, 2, 3])
    buf.replace_with(1, lambda prev: prev * 2)
    assert buf == [1, 4, 3]

def offset(self, f: Callable[[int], int]) -> None: View Source

    1158    def offset(self, f: collections.Callable[[int], int]) -> None:
    1159        """Modify each byte in the buffer with a new byte returned from `f`.
    1160
    1161        The signature of `f` is `Fn(int) -> int`, where the argument is the previous byte.
    1162
    1163        Example
    1164        -------
    1165        ```py
    1166        buf = BytesMut.from_bytes([1, 2, 3])
    1167        buf.offset(lambda prev: prev * 2)
    1168        assert buf == [2, 4, 6]
    1169        ```
    1170
    1171        This method is `NOOP` if `self` is empty or unallocated.
    1172        """
    1173
    1174        if not self._buf:
    1175            return
    1176
    1177        for index in range(len(self._buf)):
    1178            self._buf[index] = f(self._buf[index])

Modify each byte in the buffer with a new byte returned from `f`.

The signature of `f` is `Fn(int) -> int`, where the argument is the previous byte.

###### Example

    buf = BytesMut.from_bytes([1, 2, 3])
    buf.offset(lambda prev: prev * 2)
    assert buf == [2, 4, 6]

This method is `NOOP` if `self` is empty or unallocated.

def fill(self, value: int) -> None: View Source

    1180    def fill(self, value: int) -> None:
    1181        """Fills `self` with the given byte.
    1182
    1183        Nothing happens if the buffer is empty or unallocated.
    1184
    1185        Example
    1186        -------
    1187        ```py
    1188        a = Bytes.from_bytes([0, 1, 2, 3])
    1189        a.fill(0)
    1190        assert a == [0, 0, 0, 0]
    1191        ```
    1192        """
    1193        if not self._buf:
    1194            return
    1195
    1196        self.as_mut_ptr()[:] = bytearray([value] * self.len())

Fills `self` with the given byte.

Nothing happens if the buffer is empty or unallocated.

###### Example

    a = Bytes.from_bytes([0, 1, 2, 3])
    a.fill(0)
    assert a == [0, 0, 0, 0]

def fill_with(self, f: Callable[[], int]) -> None: View Source

    1198    def fill_with(self, f: collections.Callable[[], int]) -> None:
    1199        """Fills `self` with the given byte returned from `f`.
    1200
    1201        Nothing happens if the buffer is empty or unallocated.
    1202
    1203        Example
    1204        -------
    1205        ```py
    1206        def default() -> int:
    1207            return 0
    1208
    1209        a = Bytes.from_bytes([0, 1, 2, 3])
    1210        a.fill_with(default)
    1211        assert a == [0, 0, 0, 0]
    1212        ```
    1213        """
    1214        if not self._buf:
    1215            return
    1216
    1217        self.as_mut_ptr()[:] = bytearray([f()] * self.len())

Fills `self` with the given byte returned from `f`.

Nothing happens if the buffer is empty or unallocated.

###### Example

    def default() -> int:
        return 0

    a = Bytes.from_bytes([0, 1, 2, 3])
    a.fill_with(default)
    assert a == [0, 0, 0, 0]

def swap(self, a: int, b: int): View Source

    1219    def swap(self, a: int, b: int):
    1220        """Swap two bytes in the buffer.
    1221
    1222        if `a` equals to `b` then it's guaranteed that elements won't change value.
    1223
    1224        Example
    1225        -------
    1226        ```py
    1227        buf = Bytes.from_bytes([1, 2, 3, 4])
    1228        buf.swap(0, 3)
    1229        assert buf == [4, 2, 3, 1]
    1230        ```
    1231
    1232        Raises
    1233        ------
    1234        IndexError
    1235            If the positions of `a` or `b` are out of index.
    1236        """
    1237        if self[a] == self[b]:
    1238            return
    1239
    1240        self[a], self[b] = self[b], self[a]

Swap two bytes in the buffer.

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

###### Example

    buf = Bytes.from_bytes([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): View Source

    1242    def swap_unchecked(self, a: int, b: int):
    1243        """Swap two bytes in the buffer. without checking if `a` == `b`.
    1244
    1245        If you care about `a` and `b` equality, see `Bytes.swap`.
    1246
    1247        Example
    1248        -------
    1249        ```py
    1250        buf = Bytes.from_bytes([1, 2, 3, 1])
    1251        buf.swap_unchecked(0, 3)
    1252        assert buf == [1, 2, 3, 1]
    1253        ```
    1254
    1255        Raises
    1256        ------
    1257        IndexError
    1258            If the positions of `a` or `b` are out of index.
    1259        """
    1260        self[a], self[b] = self[b], self[a]

Swap two bytes in the buffer. without checking if `a` == `b`.

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

###### Example

    buf = Bytes.from_bytes([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 as_mut_ptr(self) -> 'memoryview[int]': View Source

    1262    def as_mut_ptr(self) -> memoryview[int]:
    1263        """Returns a mutable pointer to the buffer data.
    1264
    1265        `pointer` here refers to a `memoryview` object.
    1266
    1267        A `BufferError` is raised if the underlying sequence is not initialized.
    1268
    1269        Example
    1270        -------
    1271        ```py
    1272        buffer = BytesMut.from_str("ouv")
    1273        ptr = buffer.as_mut_ptr()
    1274        ptr[0] = ord(b'L')
    1275        assert buffer.to_bytes() == b"Luv"
    1276        ```
    1277        """
    1278        return self.__buffer__(512)

Returns a mutable pointer to the buffer data.

`pointer` here refers to a `memoryview` object.

A `BufferError` is raised if the underlying sequence is not initialized.

###### Example

    buffer = BytesMut.from_str("ouv")
    ptr = buffer.as_mut_ptr()
    ptr[0] = ord(b'L')
    assert buffer.to_bytes() == b"Luv"

def as_mut(self) -> sain.collections.slice.SliceMut[int]: View Source

    1280    def as_mut(self) -> _slice.SliceMut[int]:
    1281        """Get a mutable reference to the underlying sequence, without copying.
    1282
    1283        An empty slice is returned if the underlying sequence is not initialized.
    1284
    1285        Example
    1286        -------
    1287        ```py
    1288        buff = BytesMut.from_str("Hello")
    1289        ref = buff.as_mut()
    1290        ref.append(32)
    1291        del ref
    1292        assert buff == b"Hello "
    1293        ```
    1294        """
    1295        if self._buf is not None:
    1296            return _slice.SliceMut(self)
    1297
    1298        return _slice.SliceMut([])

Get a mutable reference to the underlying sequence, without copying.

An empty slice is returned if the underlying sequence is not initialized.

###### Example

    buff = BytesMut.from_str("Hello")
    ref = buff.as_mut()
    ref.append(32)
    del ref
    assert buff == b"Hello "

@safe
def freeze(self) -> Bytes: View Source

    1300    @safe
    1301    def freeze(self) -> Bytes:
    1302        """Convert `self` into an immutable `Bytes`.
    1303
    1304        This conversion is zero-cost, meaning it doesn't any _hidden-copy_ operations behind the scenes.
    1305        This consumes `self` and returns a new `Bytes` that points to the same underlying array,
    1306
    1307        Notes
    1308        -----
    1309        * If `self` is not initialized, a new empty `Bytes` is returned.
    1310        * `self` will no longer be usable, as it will not point to the underlying array.
    1311
    1312        The inverse method of this is `Bytes.to_mut()`
    1313
    1314        Example
    1315        -------
    1316        ```py
    1317        def shrink_to(cap: int, buffer: BytesMut) -> Bytes:
    1318            buf.truncate(cap)
    1319            return buf.freeze()
    1320
    1321        buffer = BytesMut.from_bytes([32, 23, 34, 65])
    1322        # accessing `buffer` after this is undefined behavior.
    1323        modified = shrink_to(2, buffer)
    1324        assert modified == [32, 23]
    1325        ```
    1326        """
    1327        # SAFETY: `Bytes.leak` returns an empty array
    1328        # if `self` is uninitialized.
    1329        return Bytes.from_ptr_unchecked(self.leak())

Convert `self` into an immutable `Bytes`.

This conversion is zero-cost, meaning it doesn't any _hidden-copy_ operations behind the scenes. This consumes `self` and returns a new `Bytes` that points to the same underlying array,

###### Notes

- If `self` is not initialized, a new empty `Bytes` is returned.
- `self` will no longer be usable, as it will not point to the underlying array.

The inverse method of this is `Bytes.to_mut()`

###### Example

    def shrink_to(cap: int, buffer: BytesMut) -> Bytes:
        buf.truncate(cap)
        return buf.freeze()

    buffer = BytesMut.from_bytes([32, 23, 34, 65])
    # accessing `buffer` after this is undefined behavior.
    modified = shrink_to(2, buffer)
    assert modified == [32, 23]

def swap_remove(self, byte: int) -> int: View Source

    1331    def swap_remove(self, byte: int) -> int:
    1332        """Remove the first appearance of `item` from this buffer and return it.
    1333
    1334        Raises
    1335        ------
    1336        * `ValueError`: if `item` is not in this buffer.
    1337        * `MemoryError`: if this buffer hasn't allocated, Aka nothing has been pushed to it.
    1338
    1339        Example
    1340        -------
    1341        ```py
    1342        buf = BytesMut.from_bytes([1, 2, 3, 4])
    1343        assert 1 == buf.swap_remove(1)
    1344        assert buf == [2, 3, 4]
    1345        ```
    1346        """
    1347        if self._buf is None:
    1348            raise MemoryError("`self` is unallocated.") from None
    1349
    1350        return self._buf.pop(self.index(byte))

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

###### Raises

- * `ValueError` (if `item` is not in this buffer.):

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

###### Example

    buf = BytesMut.from_bytes([1, 2, 3, 4])
    assert 1 == buf.swap_remove(1)
    assert buf == [2, 3, 4]

def truncate(self, size: int) -> None: View Source

    1352    def truncate(self, size: int) -> None:
    1353        """Shortens the bytes, keeping the first `size` elements and dropping the rest.
    1354
    1355        Example
    1356        -------
    1357        ```py
    1358        buf = BytesMut.from_bytes([0, 0, 0, 0])
    1359        buf.truncate(1)
    1360        assert buf.len() == 1
    1361        ```
    1362        """
    1363        if not self._buf:
    1364            return
    1365
    1366        del self._buf[size:]

Shortens the bytes, keeping the first `size` elements and dropping the rest.

###### Example

    buf = BytesMut.from_bytes([0, 0, 0, 0])
    buf.truncate(1)
    assert buf.len() == 1

def split_off_mut(self, at: int) -> BytesMut: View Source

    1368    def split_off_mut(self, at: int) -> BytesMut:
    1369        """Split the bytes off at the specified position, returning a new
    1370        `BytesMut` at the range of `[at : len]`, leaving `self` at `[at : bytes_len]`.
    1371
    1372        if this bytes is empty, `self` is returned unchanged.
    1373
    1374        Example
    1375        -------
    1376        ```py
    1377        origin = BytesMut.from_bytes((1, 2, 3, 4))
    1378        split = origin.split_off_mut(2)
    1379
    1380        print(origin, split)  # [1, 2], [3, 4]
    1381        ```
    1382
    1383        Raises
    1384        ------
    1385        `IndexError`
    1386            This method will raise if `at` > `len(self)`
    1387        """
    1388        len_ = self.len()
    1389        if at > len_:
    1390            raise IndexError(
    1391                f"the index of `at` ({at}) should be <= than len of `self` ({len_}) "
    1392            ) from None
    1393
    1394        if not self._buf:
    1395            return self
    1396
    1397        split = BytesMut.from_ptr(self._buf[at:len_])
    1398        del self._buf[at:len_]
    1399        return split

Split the bytes off at the specified position, returning a new `BytesMut` at the range of `[at : len]`, leaving `self` at `[at : bytes_len]`.

if this bytes is empty, `self` is returned unchanged.

###### Example

    origin = BytesMut.from_bytes((1, 2, 3, 4))
    split = origin.split_off_mut(2)

    print(origin, split)  # [1, 2], [3, 4]

###### Raises

- `IndexError`: This method will raise if `at` > `len(self)`

def split_first_mut(self) -> 'Option[tuple[int, BytesMut]]': View Source

    1401    def split_first_mut(self) -> Option[tuple[int, BytesMut]]:
    1402        """Split the first and rest elements of the bytes, If empty, `None` is returned.
    1403
    1404        Returns a tuple of (first, rest) where rest is a mutable sequence.
    1405
    1406        Example
    1407        -------
    1408        ```py
    1409        buf = BytesMut.from_bytes([1, 2, 3])
    1410        split = buf.split_first_mut()
    1411        assert split == Some((1, [2, 3]))
    1412        ```
    1413        """
    1414        if not self._buf:
    1415            return _option.NOTHING
    1416
    1417        if self.len() == 1:
    1418            return _option.Some((self[0], BytesMut()))
    1419
    1420        first = self[0]
    1421        rest = self[1:]
    1422        return _option.Some((first, rest))

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

Returns a tuple of (first, rest) where rest is a mutable sequence.

###### Example

    buf = BytesMut.from_bytes([1, 2, 3])
    split = buf.split_first_mut()
    assert split == Some((1, [2, 3]))

def split_last_mut(self) -> 'Option[tuple[int, Bytes]]': View Source

    1424    def split_last_mut(self) -> Option[tuple[int, Bytes]]:
    1425        """Returns the last and rest of the elements of the bytes, If `self` is empty, `None` is returned.
    1426
    1427        Returns a tuple of (last, rest) where rest is a mutable sequence.
    1428
    1429        Example
    1430        -------
    1431        ```py
    1432        buf = BytesMut.from_bytes([0, 1, 2])
    1433        last, elements = buf.split_last_mut().unwrap()
    1434        assert (last, elements) == (2, [0, 1])
    1435        ```
    1436        """
    1437        if not self._buf:
    1438            return _option.NOTHING
    1439
    1440        len_ = self.len()
    1441        if len_ == 1:
    1442            return _option.Some((self[0], BytesMut()))
    1443
    1444        last = self[-1]
    1445        rest = self[:-1]
    1446        return _option.Some((last, rest))

Returns the last and rest of the elements of the bytes, If `self` is empty, `None` is returned.

Returns a tuple of (last, rest) where rest is a mutable sequence.

###### Example

    buf = BytesMut.from_bytes([0, 1, 2])
    last, elements = buf.split_last_mut().unwrap()
    assert (last, elements) == (2, [0, 1])

def split_at_mut( self, mid: int) -> tuple[BytesMut, BytesMut]: View Source

    1448    def split_at_mut(self, mid: int) -> tuple[BytesMut, BytesMut]:
    1449        """Divide `self` into two at an index.
    1450
    1451        The first will contain all bytes from `[0:mid]` excluding `mid` itself.
    1452        and the second will contain the remaining bytes.
    1453
    1454        if `mid` > `self.len()`, Then all bytes will be moved to the left,
    1455        returning an empty bytes in right.
    1456
    1457        Example
    1458        -------
    1459        ```py
    1460        buffer = BytesMut.from_bytes((1, 2, 3, 4))
    1461        left, right = buffer.split_at_mut(0)
    1462        assert left == [] and right == [1, 2, 3, 4]
    1463
    1464        left, right = buffer.split_at_mut(2)
    1465        assert left == [1, 2] and right == [3, 4]
    1466        ```
    1467
    1468        The is roughly the implementation
    1469        ```py
    1470        self[0:mid], self[mid:]
    1471        ```
    1472        """
    1473        return self[0:mid], self[mid:]

Divide `self` into two at an index.

The first will contain all bytes from `[0:mid]` excluding `mid` itself. and the second will contain the remaining bytes.

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

###### Example

    buffer = BytesMut.from_bytes((1, 2, 3, 4))
    left, right = buffer.split_at_mut(0)
    assert left == [] and right == [1, 2, 3, 4]

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

The is roughly the implementation

    self[0:mid], self[mid:]

def insert(self, index: int, value: int) -> None: View Source

    1477    def insert(self, index: int, value: int) -> None:
    1478        """Insert a new item with `value` in the buffer before position `index`.
    1479
    1480        Negative values are treated as being relative to the end of the buffer.
    1481        """
    1482        if self._buf is None:
    1483            return
    1484
    1485        self._buf.insert(index, value)

Insert a new item with `value` in the buffer before position `index`.

Negative values are treated as being relative to the end of the buffer.

def pop(self, i: int = -1) -> 'Option[int]': View Source

    1487    def pop(self, i: int = -1) -> Option[int]:
    1488        """Removes the last element from the buffer and returns it, `Some(None)` if it is empty.
    1489
    1490        Example
    1491        -------
    1492        ```py
    1493        buf = BytesMut((21, 32, 44))
    1494        assert buf.pop() == Some(44)
    1495        ```
    1496        """
    1497        if not self._buf:
    1498            return _option.NOTHING
    1499
    1500        return _option.Some(self._buf.pop(i))

Removes the last element from the buffer and returns it, `Some(None)` if it is empty.

###### Example

    buf = BytesMut((21, 32, 44))
    assert buf.pop() == Some(44)

def remove(self, i: int) -> None: View Source

    1502    def remove(self, i: int) -> None:
    1503        """Remove the first appearance of `i` from `self`.
    1504
    1505        Example
    1506        ------
    1507        ```py
    1508        buf = BytesMut.from_bytes([1, 1, 2, 3, 4])
    1509        buf.remove(1)
    1510        print(buf) # [1, 2, 3, 4]
    1511        ```
    1512        """
    1513        if not self._buf:
    1514            return
    1515
    1516        self._buf.remove(i)

Remove the first appearance of `i` from `self`.

###### Example

    buf = BytesMut.from_bytes([1, 1, 2, 3, 4])
    buf.remove(1)
    print(buf) # [1, 2, 3, 4]

def clear(self) -> None: View Source

    1518    def clear(self) -> None:
    1519        """Clear the buffer.
    1520
    1521        Example
    1522        -------
    1523        ```py
    1524        buf = BytesMut.from_bytes([255])
    1525        buf.clear()
    1526
    1527        assert buf.is_empty()
    1528        ```
    1529        """
    1530        if not self._buf:
    1531            return
    1532
    1533        del self._buf[:]

Clear the buffer.

###### Example

    buf = BytesMut.from_bytes([255])
    buf.clear()

    assert buf.is_empty()

def byteswap(self) -> None: View Source

    1535    def byteswap(self) -> None:
    1536        """Swap the byte order of the bytes in `self`."""
    1537        if not self._buf:
    1538            return
    1539
    1540        self._buf.byteswap()

Swap the byte order of the bytes in `self`.

##### Inherited Members

Bytes
  Bytes
  from_str
  from_ptr
  from_ptr_unchecked
  from_bytes
  from_raw
  zeroed
  to_string
  try_to_str
  to_str
  to_bytes
  to_vec
  leak
  as_ptr
  as_ref
  to_mut
  raw_parts
  len
  size
  iter
  chars
  is_empty
  split_off
  split_first
  split_last
  split_at
  copy
  index
  count
sain.collections.slice.SpecContains
  contains

@rustc_diagnostic_item('HashMap')
class HashMap(sain.collections.hash_map._RawMap[~K, ~V], sain.default.Default[ForwardRef('HashMap[K, V]')]): View Source

    398@rustc_diagnostic_item("HashMap")
    399class HashMap(_RawMap[K, V], Default["HashMap[K, V]"]):
    400    """An immutable key-value dictionary.
    401
    402    But default, `HashMap` is immutable, it cannot change its values after initializing it. however,
    403    you can return a mutable reference to this hashmap via `HashMap.as_mut` method, it returns a reference to the underlying map.
    404
    405    Example
    406    -------
    407    ```py
    408    # initialize it with a source. after that, item insertion is not allowed.
    409    books: HashMap[str, str] = HashMap({
    410        "Adventures of Huckleberry Finn": "My favorite book."
    411    })
    412    # get a mutable reference to it to be able to.
    413    books_mut = books.as_mut()
    414    # You can either call `.insert`, which is similar to Rust's.
    415    books_mut.insert(
    416        "Grimms Fairy Tales",
    417        "Masterpiece.",
    418    )
    419    # Or via item assignments
    420    books_mut["Pride and Prejudice"] = "Very enjoyable."
    421    print(books)
    422
    423    for book, review in books.items():
    424        print(book, review)
    425    ```
    426
    427    Parameters
    428    ----------
    429    source: `dict[K, V]`
    430        A dictionary to point to. this will be used as the underlying source.
    431    """
    432
    433    __slots__ = ("_source",)
    434
    435    def __init__(self, source: dict[K, V] | None = None, /) -> None:
    436        super().__init__(source)
    437
    438    @staticmethod
    439    def default() -> HashMap[K, V]:
    440        """Creates an empty `HashMap<K, V>`."""
    441        return HashMap()
    442
    443    @classmethod
    444    def from_mut(cls, source: dict[K, V] | None = None, /) -> RefMut[K, V]:
    445        """Create a new mutable `HashMap`, with the given source if available.
    446
    447        Example
    448        -------
    449        ```py
    450        books = HashMap.from_mut()
    451        books[0] = "Twilight"
    452        ```
    453        """
    454        return RefMut(source or {})
    455
    456    @staticmethod
    457    def from_keys_mut(*iterable: tuple[K, V]) -> RefMut[K, V]:
    458        """Create a new mutable `HashMap` from a sequence of key-value pairs.
    459
    460        Example
    461        -------
    462        ```py
    463        tier_list = [
    464            ("S", "Top tier"),
    465            ("A", "Very Good"),
    466            ("B", "Good"),
    467            ("C", "Average"),
    468            ("D", "dodo")
    469        ]
    470        mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list)
    471        ```
    472        """
    473        return RefMut({k: v for k, v in iterable})
    474
    475    def as_mut(self) -> RefMut[K, V]:
    476        """Get a mutable reference to this hash map.
    477
    478        Example
    479        -------
    480        ```py
    481        map: HashMap[str, float] = HashMap()
    482
    483        # Get a reference to map
    484        mut = map.as_mut()
    485        mut.insert("sqrt", 1.0)
    486        del mut # not needed anymore
    487
    488        assert map == {"sqrt": 1.0}
    489        ```
    490        """
    491        return RefMut(self._source)

An immutable key-value dictionary.

But default, `HashMap` is immutable, it cannot change its values after initializing it. however, you can return a mutable reference to this hashmap via `HashMap.as_mut` method, it returns a reference to the underlying map.

###### Example

    # initialize it with a source. after that, item insertion is not allowed.
    books: HashMap[str, str] = HashMap({
        "Adventures of Huckleberry Finn": "My favorite book."
    })
    # get a mutable reference to it to be able to.
    books_mut = books.as_mut()
    # You can either call `.insert`, which is similar to Rust's.
    books_mut.insert(
        "Grimms Fairy Tales",
        "Masterpiece.",
    )
    # Or via item assignments
    books_mut["Pride and Prejudice"] = "Very enjoyable."
    print(books)

    for book, review in books.items():
        print(book, review)

###### Parameters

- source (`dict[K, V]`): A dictionary to point to. this will be used as the underlying source.
- # Implementations
- **This class implements HashMap:

HashMap(source: dict[~K, ~V] | None = None, /) View Source

    435    def __init__(self, source: dict[K, V] | None = None, /) -> None:
    436        super().__init__(source)

@staticmethod
def default() -> HashMap[~K, ~V]: View Source

    438    @staticmethod
    439    def default() -> HashMap[K, V]:
    440        """Creates an empty `HashMap<K, V>`."""
    441        return HashMap()

Creates an empty `HashMap<K, V>`.

@classmethod
def from_mut( cls, source: dict[~K, ~V] | None = None, /) -> sain.collections.hash_map.RefMut[~K, ~V]: View Source

    443    @classmethod
    444    def from_mut(cls, source: dict[K, V] | None = None, /) -> RefMut[K, V]:
    445        """Create a new mutable `HashMap`, with the given source if available.
    446
    447        Example
    448        -------
    449        ```py
    450        books = HashMap.from_mut()
    451        books[0] = "Twilight"
    452        ```
    453        """
    454        return RefMut(source or {})

Create a new mutable `HashMap`, with the given source if available.

###### Example

    books = HashMap.from_mut()
    books[0] = "Twilight"

@staticmethod
def from_keys_mut(*iterable: tuple[~K, ~V]) -> sain.collections.hash_map.RefMut[~K, ~V]: View Source

    456    @staticmethod
    457    def from_keys_mut(*iterable: tuple[K, V]) -> RefMut[K, V]:
    458        """Create a new mutable `HashMap` from a sequence of key-value pairs.
    459
    460        Example
    461        -------
    462        ```py
    463        tier_list = [
    464            ("S", "Top tier"),
    465            ("A", "Very Good"),
    466            ("B", "Good"),
    467            ("C", "Average"),
    468            ("D", "dodo")
    469        ]
    470        mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list)
    471        ```
    472        """
    473        return RefMut({k: v for k, v in iterable})

Create a new mutable `HashMap` from a sequence of key-value pairs.

###### Example

    tier_list = [
        ("S", "Top tier"),
        ("A", "Very Good"),
        ("B", "Good"),
        ("C", "Average"),
        ("D", "dodo")
    ]
    mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list)

def as_mut(self) -> sain.collections.hash_map.RefMut[~K, ~V]: View Source

    475    def as_mut(self) -> RefMut[K, V]:
    476        """Get a mutable reference to this hash map.
    477
    478        Example
    479        -------
    480        ```py
    481        map: HashMap[str, float] = HashMap()
    482
    483        # Get a reference to map
    484        mut = map.as_mut()
    485        mut.insert("sqrt", 1.0)
    486        del mut # not needed anymore
    487
    488        assert map == {"sqrt": 1.0}
    489        ```
    490        """
    491        return RefMut(self._source)

Get a mutable reference to this hash map.

###### Example

    map: HashMap[str, float] = HashMap()

    # Get a reference to map
    mut = map.as_mut()
    mut.insert("sqrt", 1.0)
    del mut # not needed anymore

    assert map == {"sqrt": 1.0}

##### Inherited Members

sain.collections.hash_map._RawMap
  from_keys
  from_value
  into
  into_keys
  into_values
  contains_key
  is_empty
  get
  get_with
  get_pairs
  get_many
  iter
  into_iter
  len
  leak
  copy