Olivia 🦀
@iolivia.me
680 followers 76 following 960 posts
👩‍💻 staff eng 🦀 post a lot about rust and rust gamedev ✍️ wrote https://sokoban.iolivia.me 🔥 blog at https://iolivia.me 🧵 weekly #rustlang threads every Thursday - subscribe here https://forms.gle/Tcm7cAkLt4NF9ZCZ9
Posts Media Videos Starter Packs
Pinned
iolivia.me
Hey all 👋

This year I'll try to stick to Thread Thursdays, which is every Thursday I'll post a thread about #rustlang fundamentals 🦀

My goal is to help you learn 1% more Rust each Thursday, so follow me if you'd like to read them 🦋

Here are some of the best threads so far 🧵👇
iolivia.me
That'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... 🦋 🦀
Rust Threads Newsletter
Get bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:…
forms.gle
iolivia.me
🚀 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
iolivia.me
The 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
iolivia.me
7️⃣ 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.
iolivia.me
6️⃣ 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.
iolivia.me
5️⃣ 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.
iolivia.me
4️⃣ 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.
iolivia.me
3️⃣ 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.
iolivia.me
2️⃣ 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!
iolivia.me
1️⃣ 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.
iolivia.me
0️⃣ Creating files

Let's start by creating a file. You can see that File::create is used to create a file, if the file already exists it will be truncated. The file is opened in write-only mode and the API returns a result which makes error handling explicit.
iolivia.me
📁 File IO in #rustlang

File system handling is a core building block of using a language effectively, and Rust makes it pretty ergonomic with the std::fs module.

Let's take a look at how to use File IO APIs in Rust with a real-world example: a grade manager for students and courses 🧵👇
iolivia.me
That's it, we looked at how to use a VecDeque 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... 🦋 🦀
Rust Threads Newsletter
Get bite-size Rust Threads about fundamental concepts and practical usage right in your inbox every Thursday. Checkout this for a sample of previous threads:…
forms.gle
iolivia.me
You can also pop from the back or push to the front if needed, there's also methods to rotate the elements in the deque which can be useful for certain algorithms, or make_contiguous which rearranges the internal buffer to be contiguous in memory.
iolivia.me
5️⃣ Extras

VecDeque also has a few other cool methods, like being able to preview the first or last element without removing it using front() and back() - this actuallt returns immutable borrows to the elemens, whereas pop returns ownership of the element.
iolivia.me
If you need fast random access to an element in the middle, Deque is not a good fit, as it does not provide O(1) indexing like Vec so we'd need to search linearly to find this element.
iolivia.me
optimized for fast random access and appending to the end.

4️⃣ When to use VecDeque

In general, when you need efficient operations on both ends. In the case of the waitlist manager, we want to insert from the end and remove from the front at O(1), which only the dequeue can provide.
iolivia.me
Also, if we had a need to add high priority students to the front of the list, we could use push_front to add to the front of the deque in O(1) - not possible with Vec. This is because VecDeque is designed to allow efficient operations at both ends as a double ended queue, whereas Vec is ...
iolivia.me
However, it's important to note that VecDequeue provides a speed improvement at the cost of using more memory. Internally it uses a growable ring buffer which means it may allocate more memory than strictly necessary to store the elements, to allow for efficient insertion and removal from both ends
iolivia.me
3️⃣ Rough performance benchmark

We can prove the performance difference by creating a large waitlist and measuring the time taken to remove all students. We can see the VecDeque is about 10x faster in this example, although this will vary in general by the size of the waitlist and the number of ops
iolivia.me
If we run demonstrate again with this implementation, we get the same output as before, so we can guarantee correctness, but let's double check our assumptions on performance.
iolivia.me
The Rust standard library provides a data structure called VecDeque which is a double-ended queue that allows for efficient O(1) insertion and removal of elements from both ends.

So let's see how the waitlist implementation looks using VecDeque.
iolivia.me
1️⃣ Using VecDeque

The biggest problem with our implementation is that removing from the front of a Vec is O(n) as all elements need to be shifted. This can be very costly if we have a large waitlist and are frequently removing students from the front.
iolivia.me
This means all existing students will get shifted in memory as index 0 is removed.

You can see this implementation in action and it works.
iolivia.me
Now let's implement this trait using a Vec as storage.

The implementation is pretty simple, it uses a Vec as the backing data structure, for adding a student it simply calls push, and for removing a student it calls remove(0) to remove the first student in the list.