Convert Figma logo to code with AI

smol-rs logosmol

A small and fast async runtime for Rust

3,613
153
3,613
16

Top Related Projects

26,366

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

Async version of the Rust standard library

Zero-cost asynchronous programming in Rust

8,565

Actor framework for Rust.

Tools for concurrent programming in Rust

Quick Overview

Smol is a small and fast runtime for asynchronous Rust programming. It provides a lightweight alternative to tokio, focusing on simplicity and ease of use while still offering powerful async capabilities.

Pros

  • Lightweight and minimal overhead
  • Easy to use and understand
  • Flexible and composable with other async ecosystems
  • Fast performance for many use cases

Cons

  • Less feature-rich compared to larger runtimes like tokio
  • Smaller ecosystem and community support
  • May not be suitable for all large-scale production environments
  • Limited documentation compared to more established runtimes

Code Examples

  1. Basic TCP echo server:
use smol::Async;
use std::net::TcpListener;

fn main() -> std::io::Result<()> {
    smol::block_on(async {
        let listener = Async::<TcpListener>::bind(([127, 0, 0, 1], 7000))?;
        println!("Listening on {}", listener.get_ref().local_addr()?);

        loop {
            let (stream, peer_addr) = listener.accept().await?;
            println!("Connection from {}", peer_addr);
            smol::spawn(async move {
                let _ = smol::io::copy(&stream, &stream).await;
            }).detach();
        }
    })
}
  1. Concurrent HTTP GET requests:
use smol::Timer;
use std::time::Duration;

async fn fetch(url: &str) -> Result<String, surf::Error> {
    let mut res = surf::get(url).await?;
    Ok(res.body_string().await?)
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    smol::block_on(async {
        let urls = vec![
            "https://example.com",
            "https://www.rust-lang.org",
            "https://github.com",
        ];

        let fetches = urls.iter().map(|url| fetch(url));
        let results = futures::future::join_all(fetches).await;

        for (url, result) in urls.iter().zip(results) {
            println!("{}: {} bytes", url, result?.len());
        }

        Ok(())
    })
}
  1. Simple timer example:
use smol::Timer;
use std::time::Duration;

fn main() -> std::io::Result<()> {
    smol::block_on(async {
        println!("Waiting for 2 seconds...");
        Timer::after(Duration::from_secs(2)).await;
        println!("Done!");
        Ok(())
    })
}

Getting Started

To use smol in your Rust project, add it to your Cargo.toml:

[dependencies]
smol = "1.2"

Then, in your Rust code, you can import and use smol like this:

use smol;

fn main() -> std::io::Result<()> {
    smol::block_on(async {
        println!("Hello from smol!");
        Ok(())
    })
}

This sets up a basic async runtime and runs a simple async block. From here, you can start building more complex async applications using smol's features.

Competitor Comparisons

26,366

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

Pros of Tokio

  • More mature and widely adopted in the Rust ecosystem
  • Extensive documentation and community support
  • Offers a broader range of features and utilities

Cons of Tokio

  • Larger codebase and more complex API
  • Steeper learning curve for beginners
  • Higher compile times due to its size and feature set

Code Comparison

Tokio example:

#[tokio::main]
async fn main() {
    println!("Hello, world!");
    tokio::time::sleep(Duration::from_secs(1)).await;
}

Smol example:

fn main() {
    smol::block_on(async {
        println!("Hello, world!");
        smol::Timer::after(Duration::from_secs(1)).await;
    });
}

Summary

Tokio is a more comprehensive and widely-used asynchronous runtime for Rust, offering a rich set of features and extensive community support. However, it comes with a larger codebase and a steeper learning curve. Smol, on the other hand, provides a simpler and more lightweight alternative, focusing on ease of use and minimal dependencies. While Smol may be easier to get started with, it may lack some of the advanced features and optimizations found in Tokio. The choice between the two depends on the specific requirements of your project and your familiarity with asynchronous programming in Rust.

Async version of the Rust standard library

Pros of async-std

  • More comprehensive and feature-rich standard library replacement
  • Better documentation and examples
  • Larger ecosystem and community support

Cons of async-std

  • Larger codebase and longer compilation times
  • Higher memory usage due to more features
  • Steeper learning curve for beginners

Code Comparison

async-std example:

use async_std::task;
use async_std::fs::File;
use async_std::prelude::*;

async fn read_file(path: &str) -> std::io::Result<String> {
    let mut file = File::open(path).await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    Ok(contents)
}

smol example:

use smol::fs::File;
use smol::prelude::*;

async fn read_file(path: &str) -> std::io::Result<String> {
    let mut file = File::open(path).await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    Ok(contents)
}

Both libraries provide similar functionality for asynchronous file operations, but async-std offers a more comprehensive set of features and utilities beyond basic I/O operations. smol, on the other hand, focuses on providing a minimal and lightweight alternative for async programming in Rust.

Zero-cost asynchronous programming in Rust

Pros of futures-rs

  • More comprehensive and feature-rich, offering a wider range of utilities and abstractions for async programming
  • Officially maintained by the Rust team, ensuring long-term support and compatibility
  • Extensively documented with detailed examples and explanations

Cons of futures-rs

  • Larger and more complex API, which can be overwhelming for beginners
  • Higher learning curve due to its extensive feature set
  • May introduce more dependencies and increase compilation times

Code Comparison

futures-rs:

use futures::executor::block_on;
use futures::future::join_all;

async fn task(i: u32) -> u32 { i * 2 }

let tasks = (0..5).map(|i| task(i));
let results = block_on(join_all(tasks));

smol:

use smol::Timer;
use std::time::Duration;

smol::block_on(async {
    Timer::after(Duration::from_secs(1)).await;
    println!("One second has passed");
});

Summary

futures-rs is a more comprehensive and officially supported library, offering a wide range of async programming tools. It's ideal for complex projects requiring advanced features. smol, on the other hand, provides a simpler and more lightweight approach to async programming, making it easier to get started with and potentially faster for simpler use cases. The choice between the two depends on the specific needs of your project and your familiarity with async Rust programming.

8,565

Actor framework for Rust.

Pros of Actix

  • Higher performance and scalability for web applications
  • More comprehensive ecosystem with additional tools and integrations
  • Better suited for large-scale, production-ready applications

Cons of Actix

  • Steeper learning curve and more complex API
  • Heavier runtime overhead compared to Smol
  • Less flexibility for non-web async workloads

Code Comparison

Actix example:

use actix_web::{web, App, HttpServer, Responder};

async fn hello() -> impl Responder {
    "Hello, World!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().route("/", web::get().to(hello))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Smol example:

use async_std::net::TcpListener;
use async_std::prelude::*;
use smol::Task;

fn main() -> std::io::Result<()> {
    smol::block_on(async {
        let listener = TcpListener::bind("127.0.0.1:8080").await?;
        let mut incoming = listener.incoming();
        while let Some(stream) = incoming.next().await {
            let stream = stream?;
            Task::spawn(async move {
                // Handle connection
            }).detach();
        }
        Ok(())
    })
}

Tools for concurrent programming in Rust

Pros of Crossbeam

  • More mature and widely adopted in the Rust ecosystem
  • Provides a broader range of concurrent programming primitives
  • Highly optimized for performance in multi-threaded scenarios

Cons of Crossbeam

  • Steeper learning curve due to its extensive feature set
  • May be overkill for simpler concurrent programming tasks
  • Requires more careful consideration of memory safety

Code Comparison

Crossbeam (using channels):

use crossbeam_channel::unbounded;

let (s, r) = unbounded();
s.send(1).unwrap();
assert_eq!(r.recv(), Ok(1));

Smol (using async channels):

use smol::channel;

let (s, r) = channel::unbounded();
s.send(1).await.unwrap();
assert_eq!(r.recv().await, Ok(1));

Summary

Crossbeam is a comprehensive concurrency library with a focus on low-level primitives and high performance. It's well-suited for complex multi-threaded applications. Smol, on the other hand, is an async runtime that emphasizes simplicity and ease of use, making it a good choice for async-focused projects or those new to concurrent programming in Rust.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

smol

Build License Cargo Documentation Chat

kitty

A small and fast async runtime.

This crate simply re-exports other smaller async crates (see the source).

To use tokio-based libraries with smol, apply the async-compat adapter to futures and I/O types.

See the smol-macros crate if you want a no proc-macro, fast compiling, easy-to-use async main and/or multi-threaded Executor setup out of the box.

Examples

Connect to an HTTP website, make a GET request, and pipe the response to the standard output:

use smol::{io, net, prelude::*, Unblock};

fn main() -> io::Result<()> {
    smol::block_on(async {
        let mut stream = net::TcpStream::connect("example.com:80").await?;
        let req = b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n";
        stream.write_all(req).await?;

        let mut stdout = Unblock::new(std::io::stdout());
        io::copy(stream, &mut stdout).await?;
        Ok(())
    })
}

There's a lot more in the examples directory.

Subcrates

TLS certificate

Some code examples are using TLS for authentication. The repository contains a self-signed certificate usable for testing, but it should not be used for real-world scenarios. Browsers and tools like curl will show this certificate as insecure.

In browsers, accept the security prompt or use curl -k on the command line to bypass security warnings.

The certificate file was generated using minica and openssl:

minica --domains localhost -ip-addresses 127.0.0.1 -ca-cert certificate.pem
openssl pkcs12 -export -out identity.pfx -inkey localhost/key.pem -in localhost/cert.pem

Another useful tool for making certificates is mkcert.

MSRV Policy

The Minimum Supported Rust Version (MSRV) of this crate is 1.63. As a tentative policy, the MSRV will not advance past the current Rust version provided by Debian Stable. At the time of writing, this version of Rust is 1.63. However, the MSRV may be advanced further in the event of a major ecosystem shift or a security vulnerability.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.