mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-29 19:22:01 +00:00
Implement a config based name manager and use it in Rust codegen (#7144)
* Refactor out a class from Rust Codegen * Convert GenerateRustModuleRootFile * git-clang-format * unused variable * parenthesis * update BUILD file * buildifier * Delete bfbs_gen_rust.h * Delete bfbs_gen_rust.cpp * Addressed some comments * Namer::EnumVariant * Remove do not submit; Add Namespace vector overload * Unshadow variable * removed redundant variables * Warn if converting from kKeep case. Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
@@ -701,6 +701,8 @@ enum class Case {
|
|||||||
kAllLower = 6,
|
kAllLower = 6,
|
||||||
// the-quick-brown-fox
|
// the-quick-brown-fox
|
||||||
kDasher = 7,
|
kDasher = 7,
|
||||||
|
// THEQuiCKBr_ownFox (or whatever you want, we won't change it)
|
||||||
|
kKeep = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert the `input` string of case `input_case` to the specified `output_case`.
|
// Convert the `input` string of case `input_case` to the specified `output_case`.
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ cc_library(
|
|||||||
"idl_gen_swift.cpp",
|
"idl_gen_swift.cpp",
|
||||||
"idl_gen_text.cpp",
|
"idl_gen_text.cpp",
|
||||||
"idl_gen_ts.cpp",
|
"idl_gen_ts.cpp",
|
||||||
|
"namer.h",
|
||||||
"util.cpp",
|
"util.cpp",
|
||||||
],
|
],
|
||||||
hdrs = [
|
hdrs = [
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
185
src/namer.h
Normal file
185
src/namer.h
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#ifndef FLATBUFFERS_NAMER
|
||||||
|
#define FLATBUFFERS_NAMER
|
||||||
|
|
||||||
|
#include "flatbuffers/idl.h"
|
||||||
|
#include "flatbuffers/util.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
|
||||||
|
// Options for Namer::File.
|
||||||
|
enum class SkipFile {
|
||||||
|
None = 0,
|
||||||
|
Suffix = 1,
|
||||||
|
Extension = 2,
|
||||||
|
SuffixAndExtension = 3,
|
||||||
|
};
|
||||||
|
SkipFile operator&(SkipFile a, SkipFile b) {
|
||||||
|
return static_cast<SkipFile>(static_cast<int>(a) & static_cast<int>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// `Namer` applies style configuration to symbols in generated code. It manages
|
||||||
|
// casing, escapes keywords, and object API naming.
|
||||||
|
// TODO: Refactor all code generators to use this.
|
||||||
|
class Namer {
|
||||||
|
public:
|
||||||
|
struct Config {
|
||||||
|
// Symbols in code.
|
||||||
|
|
||||||
|
// Case style for flatbuffers-defined types.
|
||||||
|
// e.g. `class TableA {}`
|
||||||
|
Case types;
|
||||||
|
// Case style for flatbuffers-defined constants.
|
||||||
|
// e.g. `uint64_t ENUM_A_MAX`;
|
||||||
|
Case constants;
|
||||||
|
// Case style for flatbuffers-defined methods.
|
||||||
|
// e.g. `class TableA { int field_a(); }`
|
||||||
|
Case methods;
|
||||||
|
// Case style for flatbuffers-defined functions.
|
||||||
|
// e.g. `TableA* get_table_a_root()`;
|
||||||
|
Case functions;
|
||||||
|
// Case style for flatbuffers-defined fields.
|
||||||
|
// e.g. `struct Struct { int my_field; }`
|
||||||
|
Case fields;
|
||||||
|
// Case style for flatbuffers-defined variants.
|
||||||
|
// e.g. `enum class Enum { MyVariant, }`
|
||||||
|
Case variants;
|
||||||
|
// Seperator for qualified enum names.
|
||||||
|
// e.g. `Enum::MyVariant` uses `::`.
|
||||||
|
std::string enum_variant_seperator;
|
||||||
|
|
||||||
|
// Namespaces
|
||||||
|
|
||||||
|
// e.g. `namespace my_namespace {}`
|
||||||
|
Case namespaces;
|
||||||
|
// The seperator between namespaces in a namespace path.
|
||||||
|
std::string namespace_seperator;
|
||||||
|
|
||||||
|
// Object API.
|
||||||
|
// Native versions flatbuffers types have this prefix.
|
||||||
|
// e.g. "" (it's usually empty string)
|
||||||
|
std::string object_prefix;
|
||||||
|
// Native versions flatbuffers types have this suffix.
|
||||||
|
// e.g. "T"
|
||||||
|
std::string object_suffix;
|
||||||
|
|
||||||
|
// Keywords.
|
||||||
|
// Prefix used to escape keywords. It is usually empty string.
|
||||||
|
std::string keyword_prefix;
|
||||||
|
// Suffix used to escape keywords. It is usually "_".
|
||||||
|
std::string keyword_suffix;
|
||||||
|
|
||||||
|
// Files.
|
||||||
|
|
||||||
|
// Case style for filenames. e.g. `foo_bar_generated.rs`
|
||||||
|
Case filenames;
|
||||||
|
// Case style for directories, e.g. `output_files/foo_bar/baz/`
|
||||||
|
Case directories;
|
||||||
|
// The directory within which we will generate files.
|
||||||
|
std::string output_path;
|
||||||
|
// Suffix for generated file names, e.g. "_generated".
|
||||||
|
std::string filename_suffix;
|
||||||
|
// Extension for generated files, e.g. ".cpp" or ".rs".
|
||||||
|
std::string filename_extension;
|
||||||
|
|
||||||
|
// This is a temporary helper function for code generators to call until all
|
||||||
|
// code generators are using `Namer`. After that point, we can centralize
|
||||||
|
// flag-overriding logic into flatc.cpp
|
||||||
|
Config WithFlagOptions(const IDLOptions &opts,
|
||||||
|
const std::string &path) const {
|
||||||
|
Config result = *this;
|
||||||
|
result.object_prefix = opts.object_prefix;
|
||||||
|
result.object_suffix = opts.object_suffix;
|
||||||
|
result.output_path = path;
|
||||||
|
result.filename_suffix = opts.filename_suffix;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Namer(Config config, std::set<std::string> keywords)
|
||||||
|
: config_(config), keywords_(std::move(keywords)) {}
|
||||||
|
|
||||||
|
std::string Type(const std::string &s) const {
|
||||||
|
return Format(s, config_.types);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Method(const std::string &s) const {
|
||||||
|
return Format(s, config_.methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Constant(const std::string &s) const {
|
||||||
|
return Format(s, config_.constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Function(const std::string &s) const {
|
||||||
|
return Format(s, config_.functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Field(const std::string &s) const {
|
||||||
|
return Format(s, config_.fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Variant(const std::string &s) const {
|
||||||
|
return Format(s, config_.variants);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string EnumVariant(const std::string &e, const std::string v) const {
|
||||||
|
return Type(e) + config_.enum_variant_seperator + Variant(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ObjectType(const std::string &s) const {
|
||||||
|
return config_.object_prefix + Type(s) + config_.object_suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Namespace(const std::string &s) const {
|
||||||
|
return Format(s, config_.namespaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Namespace(const std::vector<std::string> &ns) const {
|
||||||
|
std::string result;
|
||||||
|
for (auto it = ns.begin(); it != ns.end(); it++) {
|
||||||
|
if (it != ns.begin()) result += config_.namespace_seperator;
|
||||||
|
result += Namespace(*it);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns `filename` with the right casing, suffix, and extension.
|
||||||
|
std::string File(const std::string &filename,
|
||||||
|
SkipFile skips = SkipFile::None) const {
|
||||||
|
const bool skip_suffix = (skips & SkipFile::Suffix) != SkipFile::None;
|
||||||
|
const bool skip_ext = (skips & SkipFile::Extension) != SkipFile::None;
|
||||||
|
return ConvertCase(filename, config_.filenames, Case::kUpperCamel) +
|
||||||
|
(skip_suffix ? "" : config_.filename_suffix) +
|
||||||
|
(skip_ext ? "" : config_.filename_extension);
|
||||||
|
}
|
||||||
|
// Formats `directories` and returns a filepath with the right seperator.
|
||||||
|
// Callers may want to use `EnsureDirExists` with the result.
|
||||||
|
std::string Directories(const std::vector<std::string> &directories) const {
|
||||||
|
std::string result = config_.output_path;
|
||||||
|
for (auto d = directories.begin(); d != directories.end(); d++) {
|
||||||
|
result += ConvertCase(*d, config_.directories, Case::kUpperCamel);
|
||||||
|
result.push_back(kPathSeparator);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string EscapeKeyword(const std::string &name) const {
|
||||||
|
if (keywords_.find(name) == keywords_.end()) {
|
||||||
|
return name;
|
||||||
|
} else {
|
||||||
|
return config_.keyword_prefix + name + config_.keyword_suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string Format(const std::string &s, Case casing) const {
|
||||||
|
// NOTE: If you need to escape keywords after converting case, which would
|
||||||
|
// make more sense than this, make it a config option.
|
||||||
|
return ConvertCase(EscapeKeyword(s), casing, Case::kLowerCamel);
|
||||||
|
}
|
||||||
|
const Config config_;
|
||||||
|
const std::set<std::string> keywords_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_NAMER
|
||||||
@@ -416,6 +416,7 @@ static std::string ToDasher(const std::string &input) {
|
|||||||
|
|
||||||
std::string ConvertCase(const std::string &input, Case output_case,
|
std::string ConvertCase(const std::string &input, Case output_case,
|
||||||
Case input_case) {
|
Case input_case) {
|
||||||
|
if (output_case == Case::kKeep) return input;
|
||||||
// The output cases expect snake_case inputs, so if we don't have that input
|
// The output cases expect snake_case inputs, so if we don't have that input
|
||||||
// format, try to convert to snake_case.
|
// format, try to convert to snake_case.
|
||||||
switch (input_case) {
|
switch (input_case) {
|
||||||
@@ -423,6 +424,7 @@ std::string ConvertCase(const std::string &input, Case output_case,
|
|||||||
case Case::kUpperCamel:
|
case Case::kUpperCamel:
|
||||||
return ConvertCase(CamelToSnake(input), output_case);
|
return ConvertCase(CamelToSnake(input), output_case);
|
||||||
case Case::kDasher: return ConvertCase(DasherToSnake(input), output_case);
|
case Case::kDasher: return ConvertCase(DasherToSnake(input), output_case);
|
||||||
|
case Case::kKeep: printf("WARNING: Converting from kKeep case.\n");
|
||||||
default:
|
default:
|
||||||
case Case::kSnake:
|
case Case::kSnake:
|
||||||
case Case::kScreamingSnake:
|
case Case::kScreamingSnake:
|
||||||
|
|||||||
@@ -1414,6 +1414,8 @@ void UtilConvertCase() {
|
|||||||
"THE_QUICK_BROWN_FOX" },
|
"THE_QUICK_BROWN_FOX" },
|
||||||
{ "the_quick_brown_fox", flatbuffers::Case::kUnknown,
|
{ "the_quick_brown_fox", flatbuffers::Case::kUnknown,
|
||||||
"the_quick_brown_fox" },
|
"the_quick_brown_fox" },
|
||||||
|
{ "the_quick_brown_fox", flatbuffers::Case::kKeep,
|
||||||
|
"the_quick_brown_fox" },
|
||||||
|
|
||||||
// Tests for some snake_cases where the _ is oddly placed or missing.
|
// Tests for some snake_cases where the _ is oddly placed or missing.
|
||||||
{ "single", flatbuffers::Case::kUpperCamel, "Single" },
|
{ "single", flatbuffers::Case::kUpperCamel, "Single" },
|
||||||
@@ -1444,7 +1446,7 @@ void UtilConvertCase() {
|
|||||||
std::get<1>(test_case)));
|
std::get<1>(test_case)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests for the non snake_case inputs.
|
// Tests for the non snake_case inputs.
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<flatbuffers::Case, std::string, flatbuffers::Case,
|
std::vector<std::tuple<flatbuffers::Case, std::string, flatbuffers::Case,
|
||||||
@@ -1464,6 +1466,8 @@ void UtilConvertCase() {
|
|||||||
"single" },
|
"single" },
|
||||||
{ flatbuffers::Case::kUpperCamel, "ABCtest",
|
{ flatbuffers::Case::kUpperCamel, "ABCtest",
|
||||||
flatbuffers::Case::kSnake, "abctest" },
|
flatbuffers::Case::kSnake, "abctest" },
|
||||||
|
{ flatbuffers::Case::kUpperCamel, "tHe_qUiCk_BrOwN_fOx",
|
||||||
|
flatbuffers::Case::kKeep, "tHe_qUiCk_BrOwN_fOx" },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto &test_case : cases) {
|
for (auto &test_case : cases) {
|
||||||
|
|||||||
Reference in New Issue
Block a user