Skip to content

Conversation

@puremourning
Copy link

@puremourning puremourning commented Dec 3, 2025

As discussed in #68, I'm sharing this very rough cut of JSON codec support for input.

Some assumptions I made, which influenced the implementation, but could be changed depending on your view:

  • avoid third party crates: json parser/encoder rolled from scratch, base64/hex encoders rolled from scratch
  • should be its own crate in the workspace (per comment in Consider merging with Serde #68)
  • std is ok for this crate
  • perfect is the enemy of good (just kidding, or rather trying to soften the blow, as this implementation is not art)

What's supported:

  • Compatible with the default encoding provided by the upstream c++ implementation I believe
  • Encode and Decode to/from String
  • Annotations provided by upstream: flatten, discriminator, name
  • base64, hex and array of numbers encodings for Data fields.
  • a smattering of tests. coverage is probably not yet sufficient.

The best doc on the actual encoding is the json.capnp which is taken directly from upstream. We don't use all of it, but I kept it unmodified anyway.

What's not supported, and what deviates from the upstream implementation:

  • Any way to customise the encoding/decoding. The c++ implementation has a sort of codec plugin which allows users to supply arbitrary codecs for fields.. This is probably most useful for Data fields.
  • Speed. This is not an optimised parser, serialiser or anything. It's the simplest way to just do something that works.
  • Arbitrary "JsonValue" types in messages. This is due to a difference in the way the codecs work. The c++ implementation uses a JsonValue (capnp) as an intermediary format for any value type whether encoding or decoding. This relies on Orphans (which we don't support) and seems to me to be an unnecessary overhead. In this implementation we go direct from Reader -> JSON string. For decoding, we still need an intermediary format, so we use a JsonValue of our own (a Rust enum) and thus JSON string -> JsonValue enum -> Builder.
  • There's a lack of comments and general polish; to be done if we agree on the bigger picture items.
  • Security safety rail; there is no protection over blowing out the stack, due to a maliciously crafted JSON document

@codecov
Copy link

codecov bot commented Dec 3, 2025

Codecov Report

❌ Patch coverage is 56.23926% with 1273 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.51%. Comparing base (ab342b3) to head (6618ff9).
⚠️ Report is 249 commits behind head on master.

Files with missing lines Patch % Lines
capnp-json/src/json_capnp.rs 4.79% 1013 Missing ⚠️
capnp-json/src/decode.rs 70.14% 163 Missing ⚠️
capnp-json/test/cppcompat.rs 88.71% 43 Missing ⚠️
capnp-json/src/data.rs 82.41% 16 Missing ⚠️
capnp-json/src/lib.rs 77.27% 15 Missing ⚠️
capnp-json/test/json.rs 97.56% 13 Missing ⚠️
capnp-json/src/encode.rs 95.59% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #600      +/-   ##
==========================================
- Coverage   51.64%   51.51%   -0.13%     
==========================================
  Files          69       77       +8     
  Lines       33735    35258    +1523     
==========================================
+ Hits        17422    18163     +741     
- Misses      16313    17095     +782     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

field_meta.name
)));
};
Ok((*field_value as i8).into())
Copy link
Author

@puremourning puremourning Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle encoded values > 127 correctly.
ditto for the other types, we should fail, rather than panic.

JsonValue::String(field_value) => {
let enum_schema = capnp::schema::EnumSchema::new(enum_schema);
let Some(enum_value) = enum_schema.get_enumerants()?.iter().find(|e| {
// FIXME: this is naive, enum values can be renamed using
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comment, it's handled

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant