Skip to content

Conversation

@TadeasKriz
Copy link

@TadeasKriz TadeasKriz commented Aug 15, 2025

Resolves SDKS-1053
Co-authored by: @phatblat

This PR adds a Metadata "language" which is a JSON file containing Rust type metadata for external tools. This metadata is used to enhance the types with information lost in the export to a C header.

Type Metadata

Metadata attributes included in the JSON file:

  • name type name
  • enum case names
    • rustName (e.g. Leroy)
    • cName (e.g. WOW_LEROY)
  • kind examples:
    • bool
    • char
    • i8
    • i32
    • u8
    • u16
    • void
    • Comment
    • Constant
    • DynamicArray
    • Enum
    • Function
    • NonNull
    • Opaque
    • Optional
    • Pointer
    • Struct
  • isMutable rust mutability
  • valueParameters function parameter names and types
  • returnType function return types
  • comment doc comment strings

Example

[
    {
        "kind": "Enum",
        "name": "Wow",
        "cases": [
            {
                "rustName": "Leroy",
                "cName": "WOW_LEROY"
            },
            {
                "rustName": "Jenkins",
                "cName": "WOW_JENKINS"
            }
        ],
        "backingType": {
            "kind": "u8"
        }
    }
    ,{
        "kind": "Struct",
        "name": "AnUnusedStruct",
        "fields": [
            {
                "name": "are_you_still_there",
                "type": {
                    "kind": "Enum",
                    "name": "Wow"
                }
            }
        ]
    }
    ,{
        "kind": "Constant",
        "name": "FOO",
        "type": {
            "kind": "i32"
        }
    }

Purpose

This type metadata information is passed to external tools in order to generate safer Kotlin bindings vs using a C header with cinterop. Specifically, we're generating kotlin types for Ditto's new Kotlin Multiplatform (KMP) SDK (now in preview).

Our build process goes through the following steps:

  1. safer_ffi generates a C header (dittoffi.h) from the Ditto Rust code.
  2. safer_ffi generates JSON type metadata file from the Ditto Rust code.
  3. Kotlin cinterop uses the dittoffi.h C header to generate Kotlin bindings (dittoffi_native.kt in diagram below).
  4. The Kotlin types generated from the C header are wrapped in safer types (dittoffi.kt)

The Kotlin types generated from this metadata add in nullability, change enum names, add doc comments, etc.

safer_ffi Ditto Kotlin SDK Generation

The arrows in the above diagram show build order.

@TadeasKriz TadeasKriz changed the base branch from ben/sdks-1053/type-metadata-json-output to master August 15, 2025 14:27
@phatblat
Copy link
Member

phatblat commented Oct 6, 2025

This PR supersedes #258

@TadeasKriz TadeasKriz marked this pull request as ready for review October 7, 2025 13:59
@phatblat phatblat changed the title Ben/sdks 1053/type metadata json output feat: add Metadata language Oct 21, 2025
@phatblat phatblat requested a review from Copilot October 21, 2025 17:46
@phatblat phatblat self-assigned this Oct 21, 2025
@phatblat phatblat added the K-feature Kind: proposed new code to implement new behaviour label Oct 21, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a new Metadata language to safer_ffi that generates JSON metadata files containing detailed type information about FFI declarations. This metadata enhances C header exports with information lost during C translation, specifically for generating Kotlin Multiplatform bindings.

Key Changes:

  • Added Language::Metadata enum variant and corresponding metadata.rs language implementation
  • Implemented metadata_type_usage() method across all CType implementations to generate JSON type descriptions
  • Introduced wrapper types OptionCLayout and NonNullCLayout to preserve semantic information in metadata
  • Added ffi_metadata attribute macro for annotating special container types (Vector, DynamicArray)

Reviewed Changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/test_kotlin.rs Comprehensive test file demonstrating metadata generation with various FFI types
src/headers/languages/metadata.rs Core implementation of metadata language with JSON output formatting
src/layout/impls.rs Added metadata_type_usage() implementations for primitives, pointers, functions, and arrays; introduced NonNullCLayout wrapper
src/layout/niche.rs Introduced OptionCLayout wrapper to preserve Optional semantics in metadata
src/headers/_mod.rs Integrated Metadata language into header generation pipeline
src/layout/_mod.rs Added metadata_type_usage() to CType trait; fixed typo "trully" → "truly"
src/proc_macro/derives/c_type/struct_.rs Added metadata generation logic for structs with ffi_metadata attribute support
src/slice.rs, src/vec.rs Applied ffi_metadata attributes to slice and vector types
src/proc_macro/_mod.rs Added ffi_metadata procedural macro attribute

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@phatblat phatblat force-pushed the ben/sdks-1053/type-metadata-json-output branch from 067709b to a9fc308 Compare October 21, 2025 19:51
@phatblat phatblat force-pushed the ben/sdks-1053/type-metadata-json-output branch from a9fc308 to 95c9d56 Compare October 21, 2025 19:52
@phatblat phatblat requested a review from Copilot October 21, 2025 20:32
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 1 comment.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@phatblat
Copy link
Member

Fixed CI, build issues with js feature, fixed js_tests and applied formatting.

@phatblat
Copy link
Member

@danielhenrymantilla & @hamchapman Could I get your eyes on this PR?

@hamchapman
Copy link
Member

To be candid, I started to review it but there were so many changes I had questions about (little changes around using transmute rather than cast, etc etc) that I got bogged down.

I will try and just focus on the bigger parts later today and get a review in.

Copy link
Member

@hamchapman hamchapman left a comment

Choose a reason for hiding this comment

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

I think it'd be good to wait for @danielhenrymantilla's review if possible but this LGTM

call(data, c!("Hello, World!").to_str().as_ptr().cast());
call(
data,
::std::mem::transmute(c!("Hello, World!").to_str().as_ptr()),
Copy link
Member

Choose a reason for hiding this comment

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

What's the need for the change here?

unsafe impl Send for ThreadTiedJsFunction {}
unsafe impl Sync for ThreadTiedJsFunction {}

impl Drop for ThreadTiedJsFunction {
Copy link
Member

Choose a reason for hiding this comment

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

Did something prompt this to be moved?

out!(("\"kind\": \"Enum\","));

self.emit_docs(ctx, docs, indent)?;

Copy link
Member

Choose a reason for hiding this comment

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

nit: I picked a random line but the whitespacing in this file is kinda weird. Lots of newlines without any discernible consistent pattern for when to have a newline or not, at least to my eyes.

}

#[derive(Debug, Clone, Copy)]
pub struct NonNullCLayout<T: CType> {
Copy link
Member

Choose a reason for hiding this comment

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

Some documentation around this and OptionCLayout would be a good idea. What guarantees are there, etc

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

Labels

K-feature Kind: proposed new code to implement new behaviour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants