Skip to content

Commit 8b8c456

Browse files
committed
support renaming structs and enums
1 parent 467edea commit 8b8c456

File tree

4 files changed

+79
-31
lines changed

4 files changed

+79
-31
lines changed

capnpc/rust.capnp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
@0x83b3c14c3c8dd083;
22

3-
annotation name @0xc2fe4c6d100166d0 (field) :Text;
4-
# Rename something in the generated code.
5-
# Currently, only field renaming is supported.
3+
annotation name @0xc2fe4c6d100166d0 (field, struct, enum) :Text;
4+
# Rename something in the generated code. The value that you specify in this
5+
# annotion must follow capnp capitalization conventions. So, for example,
6+
# a struct could be named `StructFoo`, even though that will get translated
7+
# to a `struct_foo` module in the generated Rust code.
8+
#
9+
# TODO: support annoting more kinds of things with this.

capnpc/src/codegen.rs

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ use crate::schema_capnp;
3030
use crate::codegen_types::{ Leaf, RustTypeInfo, RustNodeInfo, TypeParameterTexts, do_branding };
3131
use self::FormattedText::{Indent, Line, Branch, BlankLine};
3232

33-
fn root_scope(root_name: String) -> Vec<String> {
34-
vec!["crate".into(), root_name]
35-
}
36-
3733
pub struct GeneratorContext<'a> {
3834
pub request: schema_capnp::code_generator_request::Reader<'a>,
3935
pub node_map: collections::hash_map::HashMap<u64, schema_capnp::node::Reader<'a>>,
@@ -67,15 +63,19 @@ impl <'a> GeneratorContext<'a> {
6763
path_to_stem_string(importpath)?.replace("-", "_"));
6864
populate_scope_map(&gen.node_map,
6965
&mut gen.scope_map,
70-
root_scope(root_name),
66+
vec!["crate".into()],
67+
root_name,
68+
NameKind::Verbatim,
7169
import.get_id())?;
7270
}
7371

7472
let root_name = path_to_stem_string(requested_file.get_filename()?)?;
7573
let root_mod = format!("{}_capnp", root_name.replace("-", "_"));
7674
populate_scope_map(&gen.node_map,
7775
&mut gen.scope_map,
78-
root_scope(root_mod),
76+
vec!["crate".into()],
77+
root_mod,
78+
NameKind::Verbatim,
7979
id)?;
8080
}
8181
Ok(gen)
@@ -229,7 +229,7 @@ const RUST_KEYWORDS : [&'static str; 53] =
229229
"typeof", "unsafe", "unsized", "use", "virtual",
230230
"where", "while", "yield"];
231231

232-
fn module_name(camel_case : &str) -> String {
232+
fn module_name(camel_case: &str) -> String {
233233
let mut name = camel_to_snake_case(camel_case);
234234
if RUST_KEYWORDS.contains(&&*name) {
235235
name.push('_');
@@ -252,31 +252,68 @@ fn get_field_name(field: schema_capnp::field::Reader) -> capnp::Result<&str> {
252252
field.get_name()
253253
}
254254

255+
enum NameKind {
256+
// convert camel case to snake case, and avoid Rust keywords
257+
Module,
258+
259+
// don't modify
260+
Verbatim,
261+
}
262+
263+
fn capnp_name_to_rust_name(capnp_name: &str, name_kind: NameKind) -> String {
264+
match name_kind {
265+
NameKind::Module => module_name(capnp_name),
266+
NameKind::Verbatim => capnp_name.to_string(),
267+
}
268+
}
269+
255270
fn populate_scope_map(node_map: &collections::hash_map::HashMap<u64, schema_capnp::node::Reader>,
256271
scope_map: &mut collections::hash_map::HashMap<u64, Vec<String>>,
257-
scope_names: Vec<String>,
272+
ancestor_scope_names: Vec<String>,
273+
mut current_node_name: String,
274+
current_name_kind: NameKind,
258275
node_id: u64) -> ::capnp::Result<()> {
259-
260-
scope_map.insert(node_id, scope_names.clone());
261-
262276
// unused nodes in imported files might be omitted from the node map
263277
let node_reader = match node_map.get(&node_id) { Some(node) => node, None => return Ok(()), };
264278

279+
'annotations: for annotation in node_reader.get_annotations()?.iter() {
280+
if annotation.get_id() == NAME_ANNOTATION_ID {
281+
if let schema_capnp::value::Text(t) = annotation.get_value()?.which()? {
282+
current_node_name = t?.to_string();
283+
break 'annotations;
284+
} else {
285+
return Err(capnp::Error::failed(format!("expected rust.name annotation value to be of type Text")));
286+
}
287+
}
288+
}
289+
290+
let mut scope_names = ancestor_scope_names;
291+
scope_names.push(capnp_name_to_rust_name(&current_node_name, current_name_kind));
292+
293+
scope_map.insert(node_id, scope_names.clone());
294+
265295
let nested_nodes = node_reader.get_nested_nodes()?;
266296
for nested_node in nested_nodes.iter(){
267-
let mut scope_names = scope_names.clone();
268297
let nested_node_id = nested_node.get_id();
269298
match node_map.get(&nested_node_id) {
270299
None => {}
271300
Some(node_reader) => {
272301
match node_reader.which() {
273302
Ok(schema_capnp::node::Enum(_enum_reader)) => {
274-
scope_names.push(nested_node.get_name()?.to_string());
275-
populate_scope_map(node_map, scope_map, scope_names, nested_node_id)?;
303+
populate_scope_map(node_map,
304+
scope_map,
305+
scope_names.clone(),
306+
nested_node.get_name()?.to_string(),
307+
NameKind::Verbatim,
308+
nested_node_id)?;
276309
}
277310
_ => {
278-
scope_names.push(module_name(nested_node.get_name()?));
279-
populate_scope_map(node_map, scope_map, scope_names, nested_node_id)?;
311+
populate_scope_map(node_map,
312+
scope_map,
313+
scope_names.clone(),
314+
nested_node.get_name()?.to_string(),
315+
NameKind::Module,
316+
nested_node_id)?;
280317
}
281318
}
282319
}
@@ -289,10 +326,12 @@ fn populate_scope_map(node_map: &collections::hash_map::HashMap<u64, schema_capn
289326
for field in fields.iter() {
290327
match field.which() {
291328
Ok(schema_capnp::field::Group(group)) => {
292-
let name = module_name(get_field_name(field)?);
293-
let mut scope_names = scope_names.clone();
294-
scope_names.push(name);
295-
populate_scope_map(node_map, scope_map, scope_names, group.get_type_id())?;
329+
populate_scope_map(node_map,
330+
scope_map,
331+
scope_names.clone(),
332+
get_field_name(field)?.to_string(),
333+
NameKind::Module,
334+
group.get_type_id())?;
296335
}
297336
_ => {}
298337
}

capnpc/test/test.capnp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -747,12 +747,17 @@ interface GenericBase(T) {}
747747
interface GenericExtend extends(GenericBase(Data)) {}
748748
interface GenericExtend2 extends (GenericBase(GenericBase(Data))) {}
749749
750-
struct TestNameAnnotation {
750+
struct TestNameAnnotation $Rust.name("RenamedStruct") {
751751
union {
752752
badFieldName @0 :Bool $Rust.name("goodFieldName");
753753
bar @1 :Int8;
754754
}
755755
756-
anotherBadFieldName @2 :UInt16 $Rust.name("anotherGoodFieldName");
756+
enum BadlyNamedEnum $Rust.name("RenamedEnum") {
757+
foo @0;
758+
bar @1;
759+
}
760+
761+
anotherBadFieldName @2 :BadlyNamedEnum $Rust.name("anotherGoodFieldName");
757762
# ...
758763
}

capnpc/test/test.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,20 +1476,20 @@ mod tests {
14761476

14771477
#[test]
14781478
fn name_annotation() {
1479-
use test_capnp::test_name_annotation;
1479+
use test_capnp::renamed_struct;
14801480
let mut message = message::Builder::new_default();
14811481
{
1482-
let mut root: test_name_annotation::Builder = message.init_root();
1482+
let mut root: renamed_struct::Builder = message.init_root();
14831483
root.set_good_field_name(true);
1484-
root.set_another_good_field_name(17);
1484+
root.set_another_good_field_name(renamed_struct::RenamedEnum::Bar);
14851485
}
14861486
{
1487-
let root: test_name_annotation::Reader = message.get_root_as_reader().unwrap();
1487+
let root: renamed_struct::Reader = message.get_root_as_reader().unwrap();
14881488
match root.which().unwrap() {
1489-
test_name_annotation::GoodFieldName(true) => (),
1489+
renamed_struct::GoodFieldName(true) => (),
14901490
_ => panic!("expected GoodFieldName(true)"),
14911491
}
1492-
assert_eq!(17, root.get_another_good_field_name());
1492+
assert!(renamed_struct::RenamedEnum::Bar == root.get_another_good_field_name().unwrap());
14931493
}
14941494
}
14951495
}

0 commit comments

Comments
 (0)