Olivia 🦀 @iolivia.me · 04/12/2025In addition to this, I have another rust project that I'm very excited about working on, and doing both at the same time plus other personal and work commitments is pretty hard. So, to wrap it up, thank you everyone who read and enjoyed the threads, you are the best! 2110
Olivia 🦀 @iolivia.me · 04/12/2025While reddit has a very large engaged audience, they are also very particular about content, so every other comment I get (for the free content I spend ages to write) is "arghh this format sucks". Which makes the newsletter very difficult to grow, since my goal is to share this with as many people 140
Olivia 🦀 @iolivia.me · 04/12/2025They take ages to write, even for topics that I am already familiar with, and if I'm not I have to spend extra time learning the topic before I can write about it. Growing the newsletter is a whole different game, the bluesky community and traffic is pretty small, so it requires posting to reddit. 130
Olivia 🦀 @iolivia.me · 04/12/2025One year in, time to reflect on the #rustlang threads! I wrote 44 total threads, many of you read them, and liked them and almost 100 people subscribed to the newsletter! I couldn't be more thankful for this. But unfortunately, I will stop writing these for now. Why? 👇 3150
Olivia 🦀 @iolivia.me · 13/11/2025That's it, we learned the basics of how async programming works in Rust! Hope it helped you learn 1% more Rust today, follow me for more threads like this and subscribe to receive these threads over email forms.gle/vY6zXE21Dkwa... 🦋 🦀forms.gleRust Threads NewsletterGet bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:… 020
Olivia 🦀 @iolivia.me · 13/11/20256️⃣ Conclusion - Futures are lazy state machines - Async provides concurrency, not necessarily parallelism - Cooperative multitasking: tasks yield at .await points only - Send = safe to move between threads - Sync = safe to share references btwn threads - Use async for I/O-bound, threads for CPU-bound 140
Olivia 🦀 @iolivia.me · 13/11/20255️⃣ When to Use Async vs Threads Async is perfect for I/O-bound operations where you're waiting for external resources, use async for concurrency with I/O. Use threads for CPU parallelism! 110
Olivia 🦀 @iolivia.me · 13/11/2025The runtime uses cooperative multitasking - it only switches between tasks at .await points. If a task never yields, it can block everything! 110
Olivia 🦀 @iolivia.me · 13/11/20254️⃣ The Runtime Async code needs a runtime to execute. The runtime manages the state machines, decides when to poll futures, and handles task scheduling. A main function in itself can be sync, with a runtime inside, or you could use #[tokio::main] to achieve the same with less boilerplate. 110
Olivia 🦀 @iolivia.me · 13/11/2025implementations for Send and Sync, and if they don't it's because most of the time they are not safe to send across threads. In practice I think you'll find most of the time in basic cases it will just work out of the box. 110
Olivia 🦀 @iolivia.me · 13/11/20253️⃣ Sync Trait Sync trait is automatically implemented for types for which it is safe to share references between threads. A type cannot be Sync unless it is Send, which of course makes sense as you wouldn't be able to share a reference to an "unsafe" object. Most types get automatic ... 110
Olivia 🦀 @iolivia.me · 13/11/2025This is why Send trait is important because it prevents at compile time thread safety issues! 110
Olivia 🦀 @iolivia.me · 13/11/2025But what if we used `Rc<String>` instead of String like this? This won't work because Rc doesn't implement Send, which means BadTranscript doesn't implement Send, which means we actually can't move this value between threads and use it as an output of the async task. 100
Olivia 🦀 @iolivia.me · 13/11/20252️⃣ Send Trait What if we wanted to return a transcript object like this? This works! 110
Olivia 🦀 @iolivia.me · 13/11/2025You can check out the Future trait, or more importantly the Poll enum which shows you exactly how this works under the hood. Basically each Poll is either Ready which means the future has finished running and we have the output T, or it's Pending which means it's still executing. 110
Olivia 🦀 @iolivia.me · 13/11/20251️⃣ Futures When you write async fn, Rust creates a Future - a value that may not be ready now but will be later. Futures are lazy and do nothing until you await them. Behind the scenes, Rust compiles your async function into a state machine that can be paused at each await and resumed later. 120
Olivia 🦀 @iolivia.me · 13/11/20253 seconds are real work, some of it is waiting for a network or IO call to come back. This is a perfect example to use async to handle all transcript requests concurrently and optimise resources. While we wait for that, we can do other work from another task. 120
Olivia 🦀 @iolivia.me · 13/11/2025We can expect the transcript generation under the hood does multiple steps like: * call an API over the network to get the student's data * do some CPU intensive work to calculate averages and totals based on that data * generate a PDF in memory * save PDF file This means not all those .. 110
Olivia 🦀 @iolivia.me · 13/11/20250️⃣ Blocking vs Async Code Let's see what happens when 3 students request transcripts using traditional blocking code. Not only is everything sequential, so each student needs to wait for all transcripts to finish before getting theirs, but also if we are on the main thread we'd be freezing the UI 110
Olivia 🦀 @iolivia.me · 13/11/2025🕰️ Async Basics in #rustlang Send, Sync, Future, tokio, Pin, I'm sure you've heard a lot of intimidating terminology when it comes to async Rust, so this thread is about explaining the basics in a simple way. We'll build a transcript generator to understand async/await, Futures 🧵👇 1150
Olivia 🦀 @iolivia.me · 06/11/2025No #rustlang threads today but I’ll be back next week! If you have a topic you'd like me to cover please suggest it in the replies 😀 280
Olivia 🦀 @iolivia.me · 30/10/2025That's it, we looked at how to do basic error handling in rust and then improved it using anyhow for context and thiserror w error types. Hope it helped you learn 1% more Rust today, follow me for more threads like this and subscribe to receive these threads over email forms.gle/vY6zXE21Dkwa... 🦋 🦀forms.gleRust Threads NewsletterGet bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:… 010
Olivia 🦀 @iolivia.me · 30/10/2025💡 This is the key difference: anyhow is great for applications where you just need good error messages, while thiserror is perfect for libraries where consumers need to handle errors programmatically. 140
Olivia 🦀 @iolivia.me · 30/10/2025The error messages are now cleaner and more structured. With custom error types, library clients can: - Match on specific error variants to handle different cases - Access error fields programmatically (like student_id, course_id) - Make informed decisions based on the error type 110
Olivia 🦀 @iolivia.me · 30/10/2025Then, we change all instances of anyhow! to return the appropriate EnrollmentError variant, and change the function signatures to return Result<T, EnrollmentError>. Note that we can no longer use `.context()` since that's an anyhow feature, but the errors themselves need to be descriptive enough 110
Olivia 🦀 @iolivia.me · 30/10/2025and we wanted to expose more specific error types that clients can match on and handle differently, we need custom error types. We can use the thiserror::Error derive macro to easily create a custom error enum with different variants for each error case. 110
Olivia 🦀 @iolivia.me · 30/10/20253️⃣ Custom error types The course enrollment is a pretty representative complex example, and the solution with anyhow context is normally good enough for internal application code where you don't need to worry about exposing error types to external clients However, if this was a library ... 110
Olivia 🦀 @iolivia.me · 30/10/2025We could extend this to a more complex example like course enrollment with a deeper chain. Here's how the process_enrollment function uses context at multiple levels. Notice how each layer of context provides additional info about where in the call stack the error occurred. 110
Olivia 🦀 @iolivia.me · 30/10/2025You can see in the last error the top level error message is "Failed to add student with id 2" and the cause is "Name cannot be empty". This additional context is super helpful for complex chains of function calls. 110
Olivia 🦀 @iolivia.me · 30/10/20252️⃣ Anyhow context Let's add new functionality that also validates the student name before adding them to the db. First, we need to import the Context trait and then use .context() to add context to the error returned from validate_name. 110
Olivia 🦀 @iolivia.me · 30/10/2025This is already better than the plain result because: - anyhow::Result can hold any error type, not just String - We get better error trait implementations (Display, Debug, etc.) - We can return different error types from the same function - It sets us up to use anyhow's powerful context feature 110
Olivia 🦀 @iolivia.me · 30/10/20251️⃣ Using Anyhow Building on top of this, let's explore how anyhow can help improve our error handling from here. We first switch Result<Student, String> to anyhow::Result<Student> and use the anyhow::anyhow! macro to create errors with messages. 100
Olivia 🦀 @iolivia.me · 30/10/2025Version 1 - Naive approach with panic-crashes the whole program on a simple error Version 2 - Returning bool to indicate success/failure but no error details, we know what failed but not why Version 3 - Using Result to return success values and error details, a good compromise and the rust default 120
Olivia 🦀 @iolivia.me · 30/10/20250️⃣ The evolution from panic to Result Let's explore error handling approaches using a university database with Student and Course structs, and a Database holding students, courses and an enrollments HashMap. Now let's explore 3 implementations for error handling: V1 - Panic V2 - Bool V3 - Result 120
Olivia 🦀 @iolivia.me · 30/10/2025⛔ Error handling in #rustlang with anyhow and thiserror Error handling in Rust can be a complex topic, especially since a lot of the patterns are different from other languages. Let's explore some basic options and then go deeper into using anyhow and thiserror crates 🧵👇 1182
Olivia 🦀 @iolivia.me · 27/10/2025Thank you so much! 🙏 Been struggling a bit with schedule last few weeks so every bit of feedback helps to keep the motivation up 😀 020
Olivia 🦀 @iolivia.me · 27/10/2025Thursday Thread Preview ⛔ Error handling in #rustlang with anyhow and thiserror 👉 In this thread, I’ll break down how to handle errors cleanly and how/when to use Result vs anyhow vs thiserror Stay tuned, coming out Thursday on 🦋 and 📤 1120
Olivia 🦀 @iolivia.me · 26/10/2025Ah yes, here you go! bsky.app/profile/ioli... I am planning to bundle them into blog posts and/or a PDF eventually! 100
Olivia 🦀 @iolivia.me · 26/10/2025#rustlang Thursday Threads recap Organising larger projects w workspaces bsky.app/profile/ioli... Memory layout bsky.app/profile/ioli... Panics bsky.app/profile/ioli... 👉 Subscribe to receive these threads over email 🦋 🦀 forms.gle/vY6zXE21Dkwa...bsky.app 070
Olivia 🦀 @iolivia.me · 10/10/2025That's it, we learned how to use the std::fs module for basic file IO operations in Rust. Hope it helped you learn 1% more Rust today, follow me for more threads like this and subscribe to receive these threads over email forms.gle/vY6zXE21Dkwa... 🦋 🦀forms.gleRust Threads NewsletterGet bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:… 000
Olivia 🦀 @iolivia.me · 10/10/2025🚀 Quick recap: - Use fs::write or writeln! for writing files - Use create_dir_all before writing to nested paths - Use fs::read_to_string for reading small files and BufReader for larger files - Use remove_file/remove_dir to delete files and directories 100
Olivia 🦀 @iolivia.me · 10/10/2025The reader acts as an iterator over the lines in the file, which means it never loads the full file into memory at once, but rather reads it line by line or chunks 100
Olivia 🦀 @iolivia.me · 10/10/20257️⃣ Reading larger files For larger files, it's better to use a buffered reader to avoid loading the entire file into memory. Here's how you can do that. Notice we use the BufReader and BufRead trait. 100
Olivia 🦀 @iolivia.me · 10/10/20256️⃣ Deleting a file After we saw how to create, write, and read files, let's see how to delete a file, pretty simple! We could also use the equivalent for directories with fs::remove_dir or fs::remove_dir_all. 100
Olivia 🦀 @iolivia.me · 10/10/20255️⃣ Parsing contents into structured data Technically not part of the std::fs API but another common pattern is to read a file and then parse its contents into a structured format. Here's how we can read back the grades file. We could also use JSON/CSV+real parser, this is just a simple example. 100
Olivia 🦀 @iolivia.me · 10/10/20254️⃣ Creating directories Another common task is creating directories. You can use fs::create_dir_all to create a directory and all its parent components if they are missing. 100
Olivia 🦀 @iolivia.me · 10/10/20253️⃣ Reading to string We can use fs::read_to_string to read the entire contents of a file into a string. This is super handy for small files. Again, we handle the Result to manage errors gracefully. 100
Olivia 🦀 @iolivia.me · 10/10/20252️⃣ Writing to the file with fs::write We can also use fs::write to write to the file, which is a bit more concise for small files. the write call will both open the file, write to it, and then close the file. Pretty neat! 100
Olivia 🦀 @iolivia.me · 10/10/20251️⃣ Writing to the file with writeln! Let's improve the error handling and handle the Result and write some data to the file. Notice the use of `ref mut` to get a mutable reference to the file inside the match arm and that the writeln! macro also returns a Result which we handle with expect. 100