Skip to content

nxtlo/sain

sain β€” Write safe Python code like Rust

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.

Install

Python 3.10 or higher is required.

Using uv:

uv pip install sain

Using pip:

pip install sain

Example

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)

built-in types

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

Contributing

See CONTRIBUTING.md.

Performance

don't use Python if you're worried about performance. no, seriously. This project was started to explore Rust design patterns and semantics.

Remaining work

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.

About

Write safe Python code like Rust πŸ¦€

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •