Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
Cargo.lock
/target/

# IDEs
.idea
206 changes: 173 additions & 33 deletions capnpc/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ pub struct GeneratorContext<'a> {
pub request: schema_capnp::code_generator_request::Reader<'a>,
pub node_map: collections::hash_map::HashMap<u64, schema_capnp::node::Reader<'a>>,
pub scope_map: collections::hash_map::HashMap<u64, Vec<String>>,
pub source_info_map:
collections::hash_map::HashMap<u64, schema_capnp::node::source_info::Reader<'a>>,

/// Map from node ID to the node ID of its parent scope. This is equal to node.scope_id
/// for all nodes except for autogenerated interface Param and Result structs;
Expand Down Expand Up @@ -228,6 +230,10 @@ impl<'a> GeneratorContext<'a> {
request: message.get_root()?,
node_map: collections::hash_map::HashMap::<u64, schema_capnp::node::Reader<'a>>::new(),
scope_map: collections::hash_map::HashMap::<u64, Vec<String>>::new(),
source_info_map: collections::hash_map::HashMap::<
u64,
schema_capnp::node::source_info::Reader<'a>,
>::new(),
node_parents: collections::hash_map::HashMap::new(),
capnp_root: code_generation_command.capnp_root.clone(),
};
Expand All @@ -239,6 +245,13 @@ impl<'a> GeneratorContext<'a> {
ctx.node_parents.insert(node.get_id(), node.get_scope_id());
}

if ctx.request.has_source_info() {
for source_info in ctx.request.get_source_info()? {
ctx.source_info_map
.insert(source_info.get_id(), source_info);
}
}

// Fix up "anonymous" method params and results scopes.
for node in ctx.request.get_nodes()? {
if let Ok(schema_capnp::node::Interface(interface_reader)) = node.which() {
Expand Down Expand Up @@ -492,6 +505,57 @@ pub fn line(inner: impl ToString) -> FormattedText {
Line(inner.to_string())
}

fn get_node_doc_comment(ctx: &GeneratorContext, node_id: u64) -> Option<String> {
if let Some(source_info) = ctx.source_info_map.get(&node_id) {
if !source_info.has_doc_comment() {
return None;
}
if let Ok(comment) = source_info.get_doc_comment() {
if let Ok(comment_str) = comment.to_string() {
return Some(comment_str);
}
}
}
None
}

fn get_member_doc_comment(
ctx: &GeneratorContext,
node_id: u64,
member_index: u32,
) -> Option<String> {
if let Some(source_info) = ctx.source_info_map.get(&node_id) {
if !source_info.has_members() {
return None;
}
if let Ok(members) = source_info.get_members() {
if member_index >= members.len() {
return None;
}
let member = members.get(member_index);
if !member.has_doc_comment() {
return None;
}
if let Ok(comment) = member.get_doc_comment() {
if let Ok(comment_str) = comment.to_string() {
return Some(comment_str);
}
}
}
}
None
}

fn generate_doc_comment(comment: Option<String>) -> Vec<FormattedText> {
let mut result = Vec::new();
if let Some(comment_str) = comment {
for line_str in comment_str.lines() {
result.push(Line(format!("/// {}", line_str)));
}
}
result
}

fn to_lines(ft: &FormattedText, indent: usize) -> Vec<String> {
match ft {
Indent(ft) => to_lines(ft, indent + 1),
Expand Down Expand Up @@ -2015,12 +2079,23 @@ fn generate_node(

match node_reader.which()? {
node::File(()) => {
let file_doc_lines = get_node_doc_comment(ctx, node_id);
if let Some(comment_str) = file_doc_lines {
for line_str in comment_str.lines() {
output.push(Line(format!("// {}", line_str)));
}
}
output.push(Branch(nested_output));
}
node::Struct(struct_reader) => {
let params = node_reader.parameters_texts(ctx);
output.push(BlankLine);

let struct_doc_lines = generate_doc_comment(get_node_doc_comment(ctx, node_id));
if !struct_doc_lines.is_empty() {
output.push(Branch(struct_doc_lines.clone()));
}

let is_generic = node_reader.get_is_generic();
if is_generic {
output.push(Line(format!(
Expand Down Expand Up @@ -2079,7 +2154,10 @@ fn generate_node(

let mut has_pointer_field = false;
let fields = struct_reader.get_fields()?;
for field in fields {
for (field_index, field) in fields.iter().enumerate() {
let field_doc_lines =
generate_doc_comment(get_member_doc_comment(ctx, node_id, field_index as u32));

let name = get_field_name(field)?;
let styled_name = camel_to_snake_case(name);

Expand All @@ -2100,12 +2178,20 @@ fn generate_node(
}

if !is_union_field {
pipeline_impl_interior.push(generate_pipeline_getter(ctx, field)?);
let mut p_getter = generate_pipeline_getter(ctx, field)?;
if let Branch(ref mut p_vec) = p_getter {
if !p_vec.is_empty() {
p_vec.insert(0, Branch(field_doc_lines.clone()));
}
}
pipeline_impl_interior.push(p_getter);

let (ty, get, default_decl) = getter_text(ctx, &field, true, true)?;
if let Some(default) = default_decl {
private_mod_interior.push(default.clone());
}
reader_members.push(Branch(vec![
Branch(field_doc_lines.clone()),
line("#[inline]"),
Line(format!("pub fn get_{styled_name}(self) {ty} {{")),
indent(get),
Expand All @@ -2114,6 +2200,7 @@ fn generate_node(

let (ty_b, get_b, _) = getter_text(ctx, &field, false, true)?;
builder_members.push(Branch(vec![
Branch(field_doc_lines.clone()),
line("#[inline]"),
Line(format!("pub fn get_{styled_name}(self) {ty_b} {{")),
indent(get_b),
Expand All @@ -2123,25 +2210,29 @@ fn generate_node(
union_fields.push(field);
}

builder_members.push(generate_setter(
ctx,
discriminant_offset,
&styled_name,
&field,
)?);

reader_members.push(generate_haser(
discriminant_offset,
&styled_name,
&field,
true,
)?);
builder_members.push(generate_haser(
discriminant_offset,
&styled_name,
&field,
false,
)?);
let mut setter = generate_setter(ctx, discriminant_offset, &styled_name, &field)?;
if let Branch(ref mut s_vec) = setter {
if !s_vec.is_empty() {
s_vec.insert(0, Branch(field_doc_lines.clone()));
}
}
builder_members.push(setter);

let mut r_haser = generate_haser(discriminant_offset, &styled_name, &field, true)?;
if let Branch(ref mut h_vec) = r_haser {
if !h_vec.is_empty() {
h_vec.insert(0, Branch(field_doc_lines.clone()));
}
}
reader_members.push(r_haser);

let mut b_haser = generate_haser(discriminant_offset, &styled_name, &field, false)?;
if let Branch(ref mut h_vec) = b_haser {
if !h_vec.is_empty() {
h_vec.insert(0, Branch(field_doc_lines.clone()));
}
}
builder_members.push(b_haser);

if let Ok(field::Group(group)) = field.which() {
let id = group.get_type_id();
Expand Down Expand Up @@ -2451,10 +2542,18 @@ fn generate_node(
let name_as_mod = module_name(last_name);
output.push(BlankLine);

let enum_doc_lines = generate_doc_comment(get_node_doc_comment(ctx, node_id));

let mut members = Vec::new();
let mut match_branches = Vec::new();
let enumerants = enum_reader.get_enumerants()?;
for (ii, enumerant) in enumerants.into_iter().enumerate() {
let enumerant_doc_lines =
generate_doc_comment(get_member_doc_comment(ctx, node_id, ii as u32));
if !enumerant_doc_lines.is_empty() {
members.push(Branch(enumerant_doc_lines));
}

let enumerant = capitalize_first_letter(get_enumerant_name(enumerant)?);
members.push(Line(format!("{enumerant} = {ii},")));
match_branches.push(Line(format!(
Expand All @@ -2466,13 +2565,17 @@ fn generate_node(
"n => ::core::result::Result::Err({capnp}::NotInSchema(n)),"
)));

output.push(Branch(vec![
line("#[repr(u16)]"),
line("#[derive(Clone, Copy, Debug, PartialEq, Eq)]"),
Line(format!("pub enum {last_name} {{")),
indent(members),
line("}"),
]));
let mut enum_declaration = vec![];
if !enum_doc_lines.is_empty() {
enum_declaration.push(Branch(enum_doc_lines));
}
enum_declaration.push(line("#[repr(u16)]"));
enum_declaration.push(line("#[derive(Clone, Copy, Debug, PartialEq, Eq)]"));
enum_declaration.push(Line(format!("pub enum {last_name} {{")));
enum_declaration.push(indent(members));
enum_declaration.push(line("}"));

output.push(Branch(enum_declaration));

output.push(BlankLine);
output.push(Branch(vec![
Expand Down Expand Up @@ -2549,6 +2652,8 @@ fn generate_node(
let params = node_reader.parameters_texts(ctx);
output.push(BlankLine);

let interface_doc_lines = generate_doc_comment(get_node_doc_comment(ctx, node_id));

let is_generic = node_reader.get_is_generic();

let names = &ctx.scope_map[&node_id];
Expand Down Expand Up @@ -2605,6 +2710,9 @@ fn generate_node(
param_type
)));

let method_doc_lines =
generate_doc_comment(get_member_doc_comment(ctx, node_id, ordinal as u32));

let result_id = method.get_result_struct_type();
if result_id != STREAM_RESULT_ID {
dispatch_arms.push(
Expand Down Expand Up @@ -2639,6 +2747,10 @@ fn generate_node(
results_ty_params,
result_type
)));

if !method_doc_lines.is_empty() {
server_interior.push(Branch(method_doc_lines.clone()));
}
server_interior.push(
Line(fmt!(ctx,
"fn {}(self: {capnp}::capability::Rc<Self>, _: {}Params<{}>, _: {}Results<{}>) -> impl ::core::future::Future<Output = Result<(), {capnp}::Error>> + 'static {{ ::core::future::ready(Err({capnp}::Error::unimplemented(\"method {}::Server::{} not implemented\".to_string()))) }}",
Expand All @@ -2648,6 +2760,9 @@ fn generate_node(
node_name, module_name(name)
)));

if !method_doc_lines.is_empty() {
client_impl_interior.push(Branch(method_doc_lines.clone()));
}
client_impl_interior.push(Line(fmt!(
ctx,
"pub fn {}_request(&self) -> {capnp}::capability::Request<{},{}> {{",
Expand All @@ -2668,13 +2783,20 @@ fn generate_node(

module_name(name))));

if !method_doc_lines.is_empty() {
server_interior.push(Branch(method_doc_lines.clone()));
}
server_interior.push(
Line(fmt!(ctx,
"fn {}(self: {capnp}::capability::Rc<Self>, _: {}Params<{}>) -> impl ::core::future::Future<Output = Result<(), {capnp}::Error>> + 'static {{ ::core::future::ready(Err({capnp}::Error::unimplemented(\"method {}::Server::{} not implemented\".to_string()))) }}",
module_name(name),
capitalize_first_letter(name), params_ty_params,
node_name, module_name(name)
)));

if !method_doc_lines.is_empty() {
client_impl_interior.push(Branch(method_doc_lines.clone()));
}
client_impl_interior.push(Line(fmt!(
ctx,
"pub fn {}_request(&self) -> {capnp}::capability::StreamingRequest<{}> {{",
Expand Down Expand Up @@ -2739,6 +2861,9 @@ fn generate_node(
};

mod_interior.push(BlankLine);
if !interface_doc_lines.is_empty() {
mod_interior.push(Branch(interface_doc_lines.clone()));
}
mod_interior.push(Line(format!("pub struct Client{bracketed_params} {{")));
mod_interior.push(indent(Line(fmt!(
ctx,
Expand Down Expand Up @@ -2852,6 +2977,9 @@ fn generate_node(
line("}"),
]));

if !interface_doc_lines.is_empty() {
mod_interior.push(Branch(interface_doc_lines.clone()));
}
mod_interior.push(Branch(vec![
Line(format!(
"pub trait Server<{}> {} {} {{",
Expand Down Expand Up @@ -2972,6 +3100,8 @@ fn generate_node(
node::Const(c) => {
let styled_name = snake_to_upper_case(ctx.get_last_name(node_id)?);

let const_doc_lines = generate_doc_comment(get_node_doc_comment(ctx, node_id));

let typ = c.get_type()?;
let formatted_text = match (typ.which()?, c.get_value()?.which()?) {
(type_::Void(()), value::Void(())) => {
Expand Down Expand Up @@ -3096,10 +3226,15 @@ fn generate_node(
}
};

if !const_doc_lines.is_empty() {
output.push(Branch(const_doc_lines));
}
output.push(formatted_text);
}

node::Annotation(annotation_reader) => {
let annotation_doc_lines = generate_doc_comment(get_node_doc_comment(ctx, node_id));

let is_generic = node_reader.get_is_generic();
let params = node_reader.parameters_texts(ctx);
let last_name = ctx.get_last_name(node_id)?;
Expand All @@ -3113,11 +3248,16 @@ fn generate_node(
} else {
interior.push(Line(fmt!(ctx,"pub fn get_type<{0}>() -> {capnp}::introspect::Type {1} {{ <{2} as {capnp}::introspect::Introspect>::introspect() }}", params.params, params.where_clause, ty.type_string(ctx, Leaf::Owned)?)));
}
output.push(Branch(vec![
Line(format!("pub mod {last_name} {{")),
indent(interior),
Line("}".into()),
]));

let mut annotation_module = vec![];
if !annotation_doc_lines.is_empty() {
annotation_module.push(Branch(annotation_doc_lines));
}
annotation_module.push(Line(format!("pub mod {last_name} {{")));
annotation_module.push(indent(interior));
annotation_module.push(Line("}".into()));

output.push(Branch(annotation_module));
}
}

Expand Down
Loading