This library provides Rust's core crates, implemented purely, in Python.
Offering core Rust items such as Vec<T>
, Result<T, E>
, Option<T>
, Iterator
semantics and more.
You can either look up the source code, or the built-in types section below.
Python 3.10 or higher is required.
Using uv:
uv pip install sain
Using pip:
pip install sain
Equivalent Rust code
let mut books: Vec<&str> = vec!["Dune", "1984"];
books.push("Foundation");
for book in books.iter().map(|book| book.to_uppercase()) {}
let s = &mut books[..];
let (first, elements) = s.split_first_mut()?;
fn first_element<'a>(slice: &'a [&str]) -> Option<&'a str> {
slice.first().copied()
}
let fav_book = first_element(&books);
println!("{:?}", fav_book); // Some("Dune")
assert_eq!(fav_book, Some("Dune"));
fn last_or<'a>(err: &'static str, vec: &'a Vec<&str>) -> Result<&'a str, &'static str> {
vec.last().copied().ok_or(err)
}
// use pattern matching to handle a result.
match last_or("not found", &books) {
Ok(book) => {
println!("Last is {book}");
}
Err(why) => {
println!("{why}",);
}
}
from __future__ import annotations
# Import some of the most primitive types.
from sain import Result, Ok, Err # used for safe error handling.
from sain import Option, Some # used for absence of a value, similar to `T | None`.
from sain import Vec # An extension for builtin `list` type.
from sain.collections import Slice # a view into some immutable sequence.
# A vec is an extension of a list.
books: Vec[str] = Vec(["Dune", "1984"])
# Vec is by default mutable.
books.push("Foundation")
# inline lazy iteration, thanks to `Iterator`.
for book in books.iter().map(lambda book: book.upper()):
...
# There's also a slicing API.
s = books[...] # returns a unique SliceMut<str> off of vec.
# The ~ operator here acts as `?`.
first, elements = ~s.split_first_mut() # Option<(str, SliceMut<str>)>
# Out: "Dune", SliceMut(["1984", "Foundation"])
def first_element(vec: Slice[str]) -> Option[str]:
# a `Vec` coerces to `SliceMut<T>`, so you can call its methods on it directly.
return vec.first()
# both `s` and `books` are valid parameters.
fav_book = first_element(books)
print(fav_book) # Some("Dune")
assert fav_book == Some("Dune")
def last_or(err: str, vec: Vec[str]) -> Result[str, str]:
return vec.split_last().ok_or(err)
# use pattern matching to handle a result.
match last_or("not found", books):
case Ok(book):
print("Last is", book)
case Err(why):
print(why)
name in Rust | name in Python | note | restrictions |
---|---|---|---|
Option<T>, Some(T), None | Option[T], Some(T), Some(None) | Some(None) has the same layout as Option::None |
|
Result<T, E>, Ok(T), Err(E) | Result[T, E], Ok(T), Err(E) | ||
Vec<T> | Vec[T] | Same layout as list[T] |
|
&[T] | Slice[T] | Same layout as its backing buffer | |
&mut [T] | SliceMut[T] | ||
HashMap<K, V> | HashMap[K, V] | Same layout as dict[K, V] |
|
bytes::Bytes | Bytes | ||
bytes::BytesMut | BytesMut | ||
LazyLock<T> | Lazy[T] | ||
OnceLock<T> | Once[T] | ||
Box<T> | Box[T] | this isn't a heap box | |
mem::MaybeUninit<T> | MaybeUninit[T] | they serve the same purpose, but slightly different | |
default::Default | Default[T] | ||
error::Error | Error | ||
Iterator<T> | Iterator[T] | ||
Iter<'a, T> | Iter[T] | some collections called by .iter() Β are built from this type |
|
iter::once::<T>() | iter.once[T] | ||
iter::empty::<T>() | iter.empty[T] | ||
iter::repeat::<T>() | iter.repeat[T] | ||
cfg!() | cfg() | runtime cfg, not all predictions are supported | |
#[cfg_attr] | @cfg_attr() | runtime cfg, not all predictions are supported | |
#[doc] | @doc() | the docs get generated at runtime | |
todo!() | todo() | ||
unimplemented!() | unimplemented() | ||
#[deprecated] | @deprecated() | same as warnings.deprecated |
See CONTRIBUTING.md.
don't use Python if you're worried about performance. no, seriously. This project was started to explore Rust design patterns and semantics.
This is still early days for sain
, it is not stable enough to be used in production level code.
each release might brick your code. eventually, by 2.0.0 release, most implementations will be stable enough.