Skip to content

Schema metadata API #255

Open
Open
@freopen

Description

@freopen

This is a follow-up to #246. I was thinking about ways to introduce access to the schema metadata for user code, here are my thoughts. I could try to implement a PR for something mentioned below, but it sounds like a lot of work, not sure if I'll handle that...

The problem

Rust has no reflection, also lots of schema information is not introduced in generated code at all. This information could be used for automatic generation of additional traits or altering runtime behavior. In addition, there is a whole annotation system in Cap'n Proto that seems to be completely ignored currently.

#247 introduced a way to access the whole CodeGeneratorRequest that contains all the information about schema. It resolves the problem but it's pretty hard to use. The goal of this issue is to introduce a usable alternative that will attach relevant information from CodeGeneratorRequest to relevant places.

Since my personal goal is to do a proc-macro based on the capnp reflection information, I'm going to try and design proc-macro friendly solution. Const functions are resolved on compile time, but there seem to be fundamental obstacles to calling just generated const functions from macro expanding part: rust-lang/rfcs#2279. So the only option to make data available is macro attributes: https://doc.rust-lang.org/reference/attributes.html. In the future there could be a separate macro library that will generate const functions based on annotations so the data could be used at runtime too.

Option 1: generate full metadata

The currently generated code doesn't have actual fields for structs, but each field could be associated with a set of functions in generated Reader and Builder structs. I suggest to add the annotation for Reader and Builder structs that will contain a corresponding Node from schema.capnp, also add annotation to every single field related function that contains Field, the Node from parent struct and the ordinal number of a field in a struct. Also every annotation should contain a map of id -> Node to all the dependencies and a enum that specifies the annotated object (Reader struct, Builder struct, get_* function, set_* function, has_* function, etc...)

Since the annotations are generated, there is no big incentive to make annotations readable. It could be just a single path like #[capnp::meta(<byte string literal>)] for every single annotation. The byte string is a Cap'n Proto encoded message called MacroMetadata that contains all the information above. There will be a separate library that will provide a TokenStream to a MacroMetadata's Reader. Also every annotation declaration should generate a function that will take MacroMetadata and return the Option<Reader> to the annotation type if that annotation is attached to that object.

Option 2: allow custom annotations that generate only needed metadata

Another solution is based on the ability of Cap'n Proto to annotate annotations. That allows for a less invasive and more elegant solution. We could extend rust.capnp with generateAttributes that could be used to annotate user defined annotations that will generate macro attributes and/or derives. Annotation parameters would configure the generated macro: path, format, additional info (field id, type, name, deps, etc...) as well as which structs/functions to annotate. Annotated annotation should generate the code that will help extracting useful data from generated attributes.

With enough flexibility in generateAttributes parameters that could allow integrating with third-party macros. Correct parameters will generate exactly the macro that a third-party crate expects. On the other hand there could be virtually no parameters so it's similar to Option 1 but just for annotated nodes instead of for everything.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions