Python to Rust: A JSON Parser in 6 Weeks
Learning Rust? I co-run a 6-week Python to Rust cohort where you build a performant JSON parser with PyO3 bindings.
Vikas Zingade is a lead ML engineer who builds complex systems in Python every day. He'd read about Rust, understanding it in theory, but he’d never actually had the borrow checker accept his code.
Six weeks and six PRs later, he has a fully compliant JSON parser with 210 passing tests that runs 12x faster than simplejson. His confidence in starting a new Rust project from scratch is a solid 7 out of 10.
Background
Vikas came into our cohort with serious Python experience and a performance-first mindset, the kind of background that makes learning Rust an appealing next step. He'd done background reading on Rust's ownership and knew, at a high level, why Rust is fast and safe. But there's a gap between knowing the rules and writing code the compiler will accept. He hadn't crossed it yet.
A few months before the cohort, he'd started building a dummy database to mimic Postgres, indexing and internals in Python. Not for performance, but to understand how databases actually work underneath the abstractions. He knew Rust would be a great candidate for this, but he didn't know enough Rust yet.
Understanding Rust concepts deeply
Weeks 3 and 4 of the cohort cover ownership, borrowing, and recursion. Ownership is Rust's rule that every value has exactly one owner, which determines when memory gets freed, not relying on a garbage collector (like Python). So borrowing something in Rust means temporarily using a value without taking ownership of it.
The compiler doesn't tell you whether cloning a value (making a full copy rather than passing a reference) is the right approach or a wasteful one. Vikas spent significant time pondering that question in week 3, reading beyond the curriculum, and asking Claude.
What finally grounded his understanding?
"What I did with respect to ownership and borrowing, was explaining it to one of my friends writing out the rules."
The analogy he created:
"A Rust variable is like owning a book. You can lend it out for reading to as many people as you want — those are immutable borrows. But if someone needs to write in it — a mutable borrow — they get exclusive access. No one else can even read the book until the writer is done. And if someone makes their own copy to scribble in, those notes stay separate — they don't show up in anyone else's copy."
When Vikas was handling errors with match statements, his coach Jim, asked what would happen if he used let result = parse_json(input)?; instead. The ? operator is Rust's shorthand for "if this fails, return the error immediately", similar to an unhandled exception bubbling up in Python. He swapped his original match statement with ? and ran it:
--- Parsing Primitive Values ---
"hello world" => String("hello world")
42 => Number(42.0)
Error: UnexpectedToken { expected: "valid JSON token", found: "i", position: 0 }
In Vikas' words:
"The program exited immediately after hitting the invalid input, it never processed the rest of the program. With
match, I can handle each error gracefully. With?, the error propagates up and terminates main."
Reading that ? propagates errors is one thing; watching it exit in your own code is another.
Writing idiomatic Rust
The cohort curriculum gives you a set of tests to pass. Tests tell you whether your code works. They don't tell you whether your code is idiomatic Rust though.
Vikas had a deliberate strategy from the start: write the brute-force version first, submit a PR, then let the review surface what a more idiomatic solution would look like. This rhythm of "try, submit, feedback, refactor" is where the deeper learning happened:
"Every PR review from Jim taught me something beyond the task. Not only did he point out what I did well, but the real value was when he'd say 'here's another way to do this.' Those idiomatic alternatives became my North Star for writing better Rust."
Code review is a powerful learning tool because it meets you at the specific decision you made and shows you what else was possible. Another example: Vikas' initial number parsing wasn't handling the failure case. Vikas applied the fix; then Clippy (Rust's linter) flagged this:
warning: matching on `Some` with `ok()` is redundant
help: consider matching on `Ok(n)` and removing the call to `ok` instead
- if let Some(n) = num_str.parse::<f64>().ok() {
+ if let Ok(n) = num_str.parse::<f64>() {
Curriculum for the initial implementation -> strong Rust tooling for initial feedback -> expert coach for the subtle idiomatic improvements.
PyO3 and the benchmarks
Weeks 5 and 6 of the curriculum cover PyO3 and benchmarking. PyO3 is the library that lets you write a Rust module and call it directly from Python. Pydantic and Polars use this to create a high-performance core, exposed to Python.
One specific trap Vikas hit: in Python, bool is a subclass of int. When you map values from Rust back to Python, you have to check for booleans before checking for numbers, otherwise True silently becomes 1.0. It's a good example of a detail that only comes up when you're writing real code.
Week 6 moved fastest for Vikas. After the harder conceptual weeks, the benchmarking and optimization was a matter of a few hours of work. Result: an RFC 8259 compliant parser, covering all JSON types, escape sequences, unicode, and error positions. Proper coverage: 177 Rust unit tests, 15 Python integration tests, and 18 doc tests. You can see his repo here - benchmarking results:
| Input | Size | vs CPython C | vs simplejson |
|---|---|---|---|
| small.json | 110 B | 2.0x faster | 14.3x faster |
| medium.json | 10 KB | 0.83x | 13.3x faster |
| large.json | 104 KB | 0.88x | 13.5x faster |
| xlarge.json | 501 KB | 0.81x | 12.3x faster |
| nested.json | 10 KB | 0.78x | 12.9x faster |
macOS 15.7.2 arm64 · Python 3.14.3 · 100-iteration warmup
Consistently 12-14x faster than simplejson. Within 80% of CPython's C extension, a mature codebase with years of hand-tuned optimization. And zero unsafe code.
What changed
Before the cohort, Vikas knew Rust only through books. After the 6-week cohort, he writes performant, increasingly idiomatic Rust code. When we asked about his confidence starting a new Rust project, he rated himself a 7 out of 10.
Since completing the cohort, he's set his next goal on migrating his Python Postgres internals simulator to be fully implemented in Rust.
Vikas also came away with a model for structuring future projects:
"I will take a lot of inspiration from how this particular curriculum was structured. For all my future side projects."
Want Rust to click beyond syntax? Build a JSON parser from scratch, wire it into Python with PyO3, and benchmark it against CPython and other JSON libraries. Six weeks of practical Python to Rust engineering with weekly PR reviews and support by experienced Rust and Python engineers, not lectures. Join the next Python to Rust cohort →