Adds module support of includes for Rust code generation#8563
Adds module support of includes for Rust code generation#8563csmulhern wants to merge 5 commits intogoogle:masterfrom
Conversation
b9695b0 to
e4bfc82
Compare
00f566c to
b6974c0
Compare
|
Hey @dbaileychess @aardappel, any guidance on how I can get this reviewed? |
|
@CasperN can you have a look? |
|
@dbaileychess is there anyone who can look at this? |
c2b50bc to
a2fc889
Compare
|
@aardappel I've tried to make this more reviewable, if you're up for some slightly more complex Rust changes. The first commit is simply adding a new The second commit updates the Rust code generator to use these mappings when resolving types. The only change in code generation here is changing how types are referenced in the generated code. All existing code generation that doesn't use the For example, imagine something like: Normally, the generated code for The third commit adds a Rust test for this new functionality. |
|
Not being familiar with the module requirements of these languages, I don't follow why this is necessary. I'd assume |
include/flatbuffers/idl.h
Outdated
| // Contains a mapping from schema names to module names. | ||
| struct ModuleMap { | ||
| // The type used to represent a schema name. | ||
| using Schema = std::string; |
There was a problem hiding this comment.
As much as I could agree that distinguishing different kinds of strings is a good thing, this is not a style we use in most of the code afaik, so it being used in only few spots is not helping readability: a reader may see Schema and expect it to be a complex type and be rather surprised it is actually just a std::string. This to me seems the kind of coding style that only works well if applied consistently.
There was a problem hiding this comment.
Agreed, and I am happy to remove this. I'm still not super familiar with the flatbuffers codebase, and was just emulating the style I saw here:
flatbuffers/src/idl_gen_fbs.cpp
Line 192 in cfce38e
There was a problem hiding this comment.
Ah yes, I thought it must have crept in somewhere :)
The problem is that the module that code is a part of is an essential part of the namespace, independent of the file path, and independent of the namespace within a module. For example, with type In C++ this is all self contained: namespace foo {
namespace bar {
namespace baz {
struct Qux { ... };
} // namespace baz
} // namespace bar
} // namespace foo
// In any compilation unit, you can reference foo::bar::baz::QuxBut in Rust (and e.g. Swift), the module (or # crate = foo
mod bar {
mod baz {
struct Qux { ... }
}
}
// Inside this crate, you can refer to Qux as crate::bar::baz::Qux, where crate
// is a special keyword that resolves to the name of the crate this source file
// belongs to. Inside another crate, e.g. waldo, the path to refer to Qux is
// <crate_name>::path::to::Qux, or in this case, foo::bar::baz::Qux.If you just typed In C++, there's no impact to splitting code into many libraries. E.g. I'm sure you're familiar with the common pattern at Google of using one E.g. imagine the following where you take my example from the original post (a type fbs_library(
name = "foo",
srcs = ["foo.fbs"],
)
rust_fbs_library(
name = "foo_rust",
deps = [":foo"]
)
fbs_library(
name = "bar",
srcs = ["bar.fbs"],
deps = [":foo"],
)
rust_fbs_library(
name = "bar_rust",
deps = [":bar"],
rust_deps = [":foo_rust"],
)The only way to refer to The approach taken here is to use To be very concrete, you can reference the test I added in the third commit. tests/rust_module_test/module_b.fbs defines a schema that depends on the type The dependency between the Rust code is managed through the build tool Then within the Rust code for module b, we refer to I really appreciate you taking the time to have a look at this. Let me know if there's any other details I can add color to. |
|
Thanks so much for educating me :) So I am learning that the design of FlatBuffers schemas is biased towards languages where namespaces and files are orthogonal concerns.. not surprising it started with C++. Also, theoretically it could be made to work directly with Rust, but only if:
And I guess that is too much of a restriction given the amount of Rust FlatBuffers already in the wild, hence we need a workaround like this module mapping? I guess the only question remaining is if this module mapping were to be better specified in a schema, if it can be equal for all module languages? Any reason command-line is preferrable? |
|
Thanks for the engagement. I agree with your breakdown. I think this point is the most problematic:
I think this limitation isn't super great either:
I spent a bit of time writing up a survey of what the solution space might look like here. See: https://docs.google.com/document/d/1E1eiGlZ0DHMw5a5PvLtVffdfXHz_3Mp0_W4HAjQRPM0/edit?tab=t.0 After going through that exercise, I think I agree with you that putting this in the schema file itself might be the better solution. If we can align on the best approach here, I'm happy to update this PR to be in line with that. I think the open questions would be:
My feeling here is that something like "option" style syntax (see my doc) may be more extensible to other future use cases, rather than a "module" keyword.
My feeling here is that language-specific is probably the least likely to run into future issues where we've painted ourselves into a corner. |
|
Thanks for spelling it out in the doc. My sense is that needing a whole string of command-line args for code to generate correctly is not great, though I see that this in the most flexible. In schema seems pretty good to me, and I guess it be fine to do it per language. We don't already have such a syntax, so you'll have to invent one, and your You could implement this in a very generic way where |
This syntax currently only supports setting the Rust module associated with a schema file.
|
I've updated this PR to implement the option syntax we've discussed. cc @jtdavis777 as well. |
Adds a new
optionsyntax to flatbuffers. The first usage allows setting the arust_modulefor the schema file, to support mapping included file paths to existing modules that have been compiled for those schemas.For more background and discussion on this approach, see: https://docs.google.com/document/d/1E1eiGlZ0DHMw5a5PvLtVffdfXHz_3Mp0_W4HAjQRPM0/edit.
This is useful for module based languages (e.g. Swift, Rust), as it allows schemas to be compiled into different units (modules) while still referencing one another.
For more background on what motivated this change, see the discussion in #8273.
Fixes #8273.