Mojo-toml v0.4.0 - TOML Writer Release 🔥

TL;DR: mojo-toml now supports writing TOML files! Build configs programmatically and serialize to TOML format with full round-trip fidelity.

What’s New

v0.4.0 adds complete TOML serialization:

from toml import to_toml, TomlValue

fn main() raises:
    // Build configuration
    var config = Dict[String, TomlValue]()
    
    var app = Dict[String, TomlValue]()
    app["name"] = TomlValue("MyApp")
    app["version"] = TomlValue("1.0.0")
    app["debug"] = TomlValue(True)
    config["app"] = TomlValue(app^)
    
    var db = Dict[String, TomlValue]()
    db["host"] = TomlValue("localhost")
    db["port"] = TomlValue(5432)
    config["database"] = TomlValue(db^)
    
    // Write to file
    var toml_str = to_toml(config)
    with open("config.toml", "w") as f:
        f.write(toml_str)

Output:

[app]
name = "MyApp"
version = "1.0.0"
debug = true
[database]
host = "localhost"
port = 5432

Features

  • :white_check_mark: to_toml() function for Dict → TOML string conversion
  • :white_check_mark: All types: strings, integers, floats, booleans, arrays, tables
  • :white_check_mark: String escaping, nested structures, table headers
  • :white_check_mark: Round-trip verified: parse → modify → write → parse preserves semantics
  • :white_check_mark: 41 new tests (137 total: 96 parser + 41 writer)

Installation

pixi add mojo-toml

from modular-community coming soon :wink:

Git submodule:

git submodule add https://github.com/databooth/mojo-toml vendor/mojo-toml
mojo -I vendor/mojo-toml/src your_app.mojo

Direct copy:

git clone https://github.com/databooth/mojo-toml
cp -r mojo-toml/src/toml your-project/lib/toml
mojo -I your-project/lib your_app.mojo

Links

Roadmap

v0.5.0: Array of tables [[section]], hex/octal/binary integers, INI support
v0.6.0: Comparative Python benchmarks, memory profiling


Zero Python dependencies. Pure Mojo. MIT licensed.

Feedback and contributions welcome! :rocket:

2 Likes

One thing that might be interesting to explore here would be the use of the just-landing reflection capabilities to automatically serialize and deserialize Mojo structs to and from .toml files. It’d be really cool if strongly-typed structs could be used as configurations and avoid the need for explicit .as_string(), .as_int(), etc.

@bgreni has been trying for JSON and has hit a number of roadblocks. I’m not sure reflection is in a state where it can be used for serialization or deserialization yet due to the density of compiler issues.

Once that issue is fixed, I agree this would be a cool feature to have.

This is an excellent idea @BradLarson and thanks for for comment @owenhilyard. Automatic struct serialisation would be a huge ergonomics win, eliminating all the .as_string(), .as_int() boilerplate.

After reviewing Mojo’s current reflection capabilities, while the reflection module is progressing well, it’s probably not quite ready for production serialisation yet. I believe that the critical blocker is that we can get field names at compile-time, but can’t read/write field values at runtime.

I’ve added this to the roadmap in two phases:

v0.7.0 (Interim): Could explore a trait-based approach where users implement Deserializable/Serializable manually. This reduces boilerplate while staying on stable features:

struct Config(Deserializable):
    fn from_toml(data: Dict[String, TomlValue]) -> Config:
        return Config(name=data["name"].as_string(), ...)

v0.8.0+ (Future): Automatic reflection-based serialisation once Mojo’s reflection matures:

var config = from_toml[Config]("config.toml")  // The end game!

I’ve documented the full analysis in docs/planning/REFLECTION_SERIALIZATION.md and updated the roadmap. Tracking this as Mojo’s stdlib evolves!

Thanks again for the suggestion / comments - this would be a fantastic feature when the time is right. :rocket: