Open Source Reflections
Preface
It's been a while since I put up another article on here. I know I started this site with the intent that I would write up or record topics that interested me, whether it be something I read up on or one of my open source contributions, but being honest I got lazy with taking care of this site. I do want to build the habit of writing more posts like the first article I made, so I'll try to be more productive with this site moving forward.
That said, this article will be a little different from the type of articles I want to make usually. I want to take a moment to reflect on my open source journey and some of the things I've worked on this past year. I won't, however, go into any deep technical details of PRs I've put up and/or merged (that's something I want to save for future articles ;) )
Why I Started Contributing to Open Source
There were two reasons why I dove into open source: to learn something new and to do something impactful. The latter reason is something I mentioned in my last article.
To provide further context though, I graduated from university in May 2025. At the time leading up to graduating and after graduating, I wasn't able to find a job and was (and unfortunately still am) unemployed. Outside of applying to jobs, going to tech conferences and networking events, I had a lot of spare time to myself that I needed to use to do something.
Being out of university meant there were no assignments and classes to overload me with information, so I only had myself to push me further into learning new topics. And as much as I think constantly working on personal projects could be really helpful to learn new topics, I both miss and value the knowledge transfer I received from interacting with other people about algorithms, good coding practices and patterns, and even niche edge cases or optimizations that I didn't know about. Couple that with seeing my college friends work for companies and outputting stuff that people will use, I wanted to do something that would make an impact.
So yeah... I took a leap of faith to making open source contributions. Rust happened to be a language that I became fond of since I self-taught myself the language in June 2024, and I wanted to start from there.
My First Actual Contribution + Branching Out
This month, October 2026, would mark a year since I started making open source contributions. I remember the first silly little contribution I made to uutils' coreutils (otherwise known as the Rust rewrite of GNU coreutils). I had gotten so used to reading through ringbuffer-related code and optimizing my own asynchronous ringbuffer data structure, so when I saw a ringbuffer.rs in their codebase, I was really curious to see how they implemented their ring buffer data structure. Lo and behold, I found something I could optimize here when I noticed that they didn't need a size field and when it could be embedded through the VecDeque's capacity via pre-allocating with VecDeque::with_capacity.
It was indeed a small PR, but it didn't make submitting that change an insignificant contribution at all. Looking at uutils' coreutils, I've sifted through many other people's PRs just as small as mine, and saw how it collectively improved the experience people had with using these command line utilities. It's amazing to see the many different names that committed changes to a file in my IDE. Some of these committed changes are from familiar faces that I go "It's that guy again lol".
My time with uutils' coreutils kinda became the catalyst for me to branch out to other repositories and find a way to make a contribution there. If you've seen my previous article, after a bit of time with uutils' coreutils, I branched out a bit and made a PR to the Rust Lang repository, having seen from someone else's PR in uutils' coreutils that the standard library create_dir_all function can potentially cause a stack overflow.
It was an exciting moment for me to see that PR get merged in, but it also opened my mind that the process of getting things across the merge line for open source projects could take a very long time. That PR started in the same month as I started doing open source contributions and it landed only this past January (3 months!). By that time, I had made a few more contributions to uutils' coreutils and worked on a PR for nextest, which I also found out about through uutils as they use it for running their CI tests.
Takeaways from Open Source
There were a few takeaways that I can talk about from my time working on open source this past year, a lot of it dealing with the Rust Language standard library.
First Takeaway: There's a lot that I don't know
This should come as pretty obvious; there's only so much that each one of us knows about a tech domain or how something is implemented.
However, even in my first attempt on re-implementing create_dir_all and submitting that, there were ways that I realized during the review process that I could've written the code better, like pre-allocating the Vec and using some of the Vec/Iterator methods like Vec::extend and Iterator::take. At the time, it made me realize that I didn't know enough of the Rust standard library at the time to easily spot ways to optimize the code or think "Hey we have this method in <insert type> to do <insert what you want to do> better".
A part of this takeaway actually inspired me to go deeper into the Rust standard library and learn what it contained. And from poking around the standard library side of Rust (I have not touched compiler side much), there's actually a lot of interesting techniques and stuff that goes on there (e.g. guards for unwind safety, specialization, and ways they reduce bloat in their code, etc.).
Second Takeaway: Be patient with yourself
The issue I had early into my journey is that a part of why I wanted to make an impact somewhere stemmed from my desire to feel like I was doing something instead of lazing around while I'm unemployed. However, making open source contributions takes a lot of time, especially for a guy like me who had just dipped his toes into a large codebase.
It takes time for me to understand the contribution guidelines of a repository (and any accompanying dev guide). It takes time to figure out the codebase and understand the implementation details of a function, struct, macro, etc.. It takes time to write tests. It takes time to write a well-written and concise PR description. It takes time to build rapport with FOSS maintainers, so they can figure out what you are doing and trust your changes. And it takes time to merge that change.
I had to learn to be patient with myself and my situation, and be fine with taking more time to grasp a portion of code, terminology that I haven't used before, and/or technical concepts. It did get better with time for me; I've gotten better at grasping Rust codebase seeing patterns in the way people write their code or organize their files/directories.
Third Takeaway: Be okay with asking for help
I know, I know, this is a cliche lesson. I do want to emphasize the difference in nature in asking for help in person and asking for help online with asynchronous communication though.
When it came to college, it was easier for me to discuss the issue I had with a teaching assistant, Professor, or with a friend; they can see/hear what's confusing me in my face/voice, and I generally don't have a problem speaking my mind. It tends to be a kinder and easier-to-be-seen experience for me to ask for help in person.
On the internet though, speaking in public servers or channels, I tend to be wary of what I say. If you've coded in Rust and read through the book, there's a lot terminologies used in the language (lifetimes, aliasing, provenance, etc.); it takes me some time to construct my thoughts around those terminologies. What made me nervous for a while is conveying my ideas or thoughts in an inelegant/easily misunderstood way in a public area and being ridiculed. And outside of one friend who introduced me to Rust, I never really built the confidence to speak to others about Rust.
Of course, at a certain point, there's only so much that I know and can figure out myself. In order to get over a thought roadblock, I had to get over the roadblock of my fear of being in the momentary spotlight of the internet. And from that leap, I've gotten to learn how chill some people are from certain Discord servers or Zulip servers associated with a GitHub repository. I remember learning about how the compiler builds itself with PGO/BOLT optimization, which was pretty cool when I looked into it.
A Look Into What I've Contributed So Far
Looking back from October 2025 - October 2026, these are all of my contributions/write-ups I've made across multiple repositories (a few are still open/WIP)
uutils' coreutils
Merged:
- uucore: ringbuffer pre-allocates memory based on size given
- factor: use num_prime crate's u64 and u128 factorization methods to speed up the performance of calculating prime numbers for u64 and u128
- Factor: base benchmarking for single/multiple u64, u128, and >u128
- tests/mkfifo: added a test to check mkfifo permission denied error for code coverage
- cat: do not connect to unix domain socket and instead return an error
Closed:
- uu: updated error message for mv on overwriting non-empty directory inside destination directory
- chmod: output permission denied error messages for inaccesible directories/files as regular user
nextest
Merged:
Rust-Lang/rust
ACPs:
- ACP: Introduce something akin to reverse ancestor method/iterator for std::pathomething akin to reverse ancestor method/iterator for
std::path - Introduce something akin to Zip iterator but one that doesn't truncate the longer iterator (my sillest ACP, and quite rightfully got closed lol)
- Introduce an accessor method for
std::fs::ReadDirthat lets us get the path associated with theReadDiriterator - Separate
Componentsiterator implementation into non-prefixed & prefixed versions - Add an equivalent
DirBuilderExttrait on Windows + introducing creating subdirectories fromDirwith certain permissions upfront - Introduce
UnixSeqListener/UnixSeqPacket
Merged:
- Implement create_dir_all() to operate iteratively instead of recursively
- fixed VecDeque::splice() not filling the buffer correctly when resizing the buffer on start = end range
BTreeMap::mergeoptimized- Fixed ByteStr not padding within its Display trait when no specific alignment is mentioned
- ACP Implementation of PermissionsExt for Windows
- Optimize BTreeMap::append() using CursorMut
- Clarified doc comments + added tests confirming current behavior for intersperse/intersperse_with
- Clarified docs in std::sync::RwLock + added test to ensure that max reader count is respected
- Lifted intersperse and intersperse_with Fused transformation and updated documentation + tests
- Prevent no_threads RwLock's write() impl from setting mode to -1 when it is locked for reading
- Panic/return false on overflow in no_threads read/try_read impl
- Implemented
PathBuf::into_string - Implement
DoubleEndedIterator::next_chunk_back - Stabilize
PathBuf::into_string - Add
or_try_*variants forHashMapandBTreeMapEntry APIs - Added
PhantomPinneddiagnostic item and prevented dead field warning onPhantomPinned - Fix perf regression in
Read::read_to_endon short reads due to not checking if the cursor has initialized bytes - Added implementation on
set_permissions_nofollowfor all primary platforms - Optimize
ArrayChunks::try_rfoldwithDoubleEndedIterator::next_chunk_back - Updated expect messages in library/alloc/src/ffi/c_str.rs to follow the style guide
- Fix an edge case with
StepBy::nthon non-fused iterators - Refactored docs for
std::fs::set_permissions_nofollow+ fix BSD-based systems to use fchmodat with AT_SYMLINK_NOFOLLOW flag - Adding diagnostic item markers for multiple fs functions and structs
- Provide better doc code example for
UnixDatagram::bind_addrandUnixListener::bind_addr
Closed:
- remove unnecessary unsafe block code in Buffer's read_more method (might be most silliest PR submission in general)
- implement BTreeMap::merge
- Fixed doc links for [T]::concat and [T]::join
- Improve implementation of remove_dir_all_recursive for unix
- rustc_marker_type built in attribute created to have certain marker types not trigger dead code warnings from clippy
- Introduce a specialization trait for
ReadDirfor most platforms - Implement FusedIterator trait on StepBy if the underlying iterator is fused
- Implement
ManuallyDrop<T>::pinned_*methods
Currently open:
- Implemented DoubledEndedIterator for Ancestors<'_> + added tests and updated doc comments
- Implement
Metadata:from_statxfor LinuxMetadataExttrait - Split
Componentsiterator to prefixed and non-prefixed versions and optimizeComponentsfor non-prefix path based platforms (very proud of this PR I made :) ) - Prevent mutating the global environment pointer in
CommandExt::execand opt to use execve and resolve path manually - Implemented different with_native_path conversion methods, refactoring fs functions to utilize with_native_path, and move exists to use with_native_path
- Fix the maximum path length allowable on MacOS, NetBSD, and DragonFlyBSD for Unix Domain Sockets
- Fix an edge within
std::fs::create_dir_allfor certain platforms that views trailing cur dir components as a separate missing directory components - Implement
Vec::retain_unstableACP
Draft PR:
- Add 1 type parameter to RangeBounds<Start, End = Start> and all existing range types (have plans to revisit this one and see if I can get the inference stuff working for compiler side)
tokio
Merged:
Rust-Lang/libc
Merged:
Rust-Lang/rust-clippy
Closed
Open:
End Note
There's probably a lot more I could say when looking in retrospect of my first year doing open source, but this post is getting pretty long and I kinda just want to finish this here. What I can say to end off is that I've been having a lot of fun digging into different projects and learning new topics or concepts
We'll see what 2027 has gotten me into with open source; I hope I get to make more contributions and branch out further.
That said, thanks for reading this. And oh yea, happy halloween! 👻️
Comments
Join the discussionIn the ring-buffer follow-up, could you show the invariant that makes the capacity-based replacement valid? In particular, it would help to separate allocated capacity from the intended logical bound and show the boundary tests. That would make the reasoning behind removing the size field reusable, alongside the patch itself.