DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Java for AI
  • Running TypeSafe AI's Jev Inside Neo4j for Confidence-Aware Sentiment Decisions
  • Embabel vs LangGraph4j: Two Agentic Philosophies for Investment and Risk Analysis in BFSI
  • Java Enterprise Is Already Ready for the AI Era

Trending

  • Using the Anthropic Evaluation Tool to Check the Claude Code Plugin Efficiency
  • Building a Feature Store With Neo4j and Feast
  • Designing a Polling Pipeline for Rate-Limited APIs Without Losing Data
  • Idempotency Under Concurrency: Why Your Application Check Isn't the Last Line of Defense

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Best of Three Worlds: AI Agents Writing In Rust and Java Beat the C Library

Best of Three Worlds: AI Agents Writing In Rust and Java Beat the C Library

How two pure-language image decoders: one in Rust and one in Java, ended up beating libheif, and what I learned about getting AI agents to improve each other's work.

By 
Yannick Majoros
·
Nov. 12, 26 · Analysis
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
8 Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

Every app that accepts photo uploads meets HEIC sooner or later. iPhones save in it by default. Neither Java nor Rust can read it out of the box, and the usual answer, libheif, is a C library: native packages in every container image, a C toolchain in the build, and a parser written in C reading files that strangers upload.

I had the problem twice, in a Java product and in a Rust one. So I went the other way: decoders written in the language itself, built and improved by AI coding agents, with me steering. Here is how it went.

1. Make It Work, In Each Project

One agent per codebase, each starting from an existing open-source decoder in its own language: Openize.HEIC for Java, HEIC decoder for Rust. The first versions lived inside each app. They read the photos, and that was enough to ship. They were ready in no time, given there were upstream libraries to start from, even if some features had to be added to match libheif.

It was tempting to stop there. Nobody complains about an upload that works.

2. Extract and Iterate

Next, I had each decoder pulled out as a standalone library, open source, with its own tests and releases, aligned with the best practices for each language (and mine). Then I asked each agent to iterate on its own: measure, improve, measure again.

That alone went a long way. The Java decoder went from 19 seconds to 3.2 for our ten test photos.

Decoding photos on one CPU core

3. Compare Everything With Everything

Working alone, each agent eventually ran out of obvious ideas. What changed the game was putting both decoders next to libheif on the same machine with the same photos, and then comparing them stage by stage.

Every gap became a lead. If another implementation did a step fast, there was a way to do it even faster, and the size of the gap told me whether it was worth chasing. A gap is a hint with a number attached.

Decoding comparisons: Rust vs libheif

The comparison also kept us honest. It showed where we were ahead, and it showed that part of libheif's lead came from doing less work: it copied color samples where our decoder interpolated them.

4. Make the Agents Talk

Here is the part that led to further improvements. Each agent, working in its own session, was told to talk with the other agent. I had the Rust agent brief the Java agent on what it had found, and the other way around. A gap one side had already closed became a recipe for the other. The Java decoder took the Rust decoder's entropy decoding approach; the Rust decoder took the Java decoder's parallel tiles and transform tricks. Later, the two agents, who were then aware of each other, even coordinated on their own, communicating which CPU cores each could benchmark on.

Decoding photos on eight CPU cores

Connecting them was the most useful step in the project.

5. Repeat On the Gaps That Remain

Then we ran the same loop again: compare, find the largest remaining gap, close it, then measure. One more round on the Rust side closed the last single-core gap with libheif. The Java side tried the JVM's vector instructions and gained another 9 to 14%.

Not every idea survived. The trick the C library is famous for, wide vector instructions, gained almost nothing in Rust: its slow parts were elsewhere. We measured it, wrote it down, and dropped it.

Be Strict About Evidence

A computer is never idle. Browsers, chat apps, other agents: everything competes for the CPU, and the numbers move with it. When we measured the very same code twice, back to back, the second run came out about 0.4% slower. Noise with a direction looks exactly like progress, or like a regression.

So I asked for proof, not impressions: count CPU work instead of wall-clock time, run old and new in alternating order, split results by type of photo, and drop any "gain" smaller than the noise. Several changes didn't make it. One that looked good overall turned out to slow down rotated photos, which are most of what phones upload, until the agent found why.

Where They Stand Today

Measured together on the same machine, the same ten photos, all three doing the same work:

  • 8 cores: Rust 0.46 s, Java 0.55 s, libheif 0.81 s
  • 1 core: Rust 1.38 s, libheif 1.45 s, Java 1.96 s
  • Rust can also interpolate color for sharper edges and still matches libheif: 1.45 s

Memory is on par with libheif or below, and a long way from where the two decoders started.

Memory use for decoding

What I Take Away

  • Iterating alone gets you far. Comparing gets you further. The gap between two implementations is the best to-do list.
  • Cross-pollinating agents helps a lot. The ideas were there, in two separate sessions. Making them talk to each other triggered more optimizations.
  • Be strict about evidence. Ask for measurements that hold up against noise, and be ready to throw away a change that doesn't.
  • Two implementations in two languages beat one. Each made the other faster. Getting a third as reference (libheif) helped even more.
  • Java is fast, too. “Java is slow” is a meme, not a measurement. Optimized the right way, it comes close to the C library on one core and beats it on eight.

Both decoders are open source:

  • Rust: github.com/Valuya/heic-decoder-rust
  • Java: github.com/Valuya/openize-heic-java
AI Library Java (programming language) Rust (programming language)

Published at DZone with permission of Yannick Majoros. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Java for AI
  • Running TypeSafe AI's Jev Inside Neo4j for Confidence-Aware Sentiment Decisions
  • Embabel vs LangGraph4j: Two Agentic Philosophies for Investment and Risk Analysis in BFSI
  • Java Enterprise Is Already Ready for the AI Era

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook