Skip to content

Adds support for parsing doc comments on Rust types #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
41 changes: 41 additions & 0 deletions csbindgen/src/doc_comment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use syn::Attribute;

use crate::util::get_str_from_meta;

pub fn gather_docs(attrs: &[Attribute]) -> Vec<String> {
attrs
.iter()
.filter(|x| x.path().is_ident("doc"))
.filter_map(|x| get_str_from_meta(&x.meta))
.collect::<Vec<_>>()
}

pub fn escape_doc_comment(doc_comment: &[String], indent: &str) -> Option<String> {
if doc_comment.is_empty() {
return None;
}

let mut lines = Vec::with_capacity(doc_comment.len() + 2);

lines.push(format!("{}/// <summary>", indent));

for comment in doc_comment.iter() {
if comment.trim().is_empty() {
lines.push(format!("{}///", indent));
} else {
for line in comment.lines() {
lines.push(format!(
"{}/// {}",
indent,
line.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;"),
));
}
}
}

lines.push(format!("{}/// </summary>", indent));

Some(lines.join("\n"))
}
36 changes: 29 additions & 7 deletions csbindgen/src/emitter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::alias_map::AliasMap;
use crate::builder::BindgenOptions;
use crate::doc_comment::escape_doc_comment;
use crate::type_meta::ExportSymbolNaming::{ExportName, NoMangle};
use crate::type_meta::*;
use crate::util::*;
Expand Down Expand Up @@ -128,7 +129,8 @@ pub fn emit_csharp(
&"return".to_string(),
) {
method_list_string.push_str(
format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n")
" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n"
.to_string()
.as_str(),
);
method_list_string
Expand All @@ -145,7 +147,8 @@ pub fn emit_csharp(
&p.name,
) {
method_list_string.push_str(
format!(" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n")
" [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n"
.to_string()
.as_str(),
);
method_list_string
Expand Down Expand Up @@ -185,7 +188,7 @@ pub fn emit_csharp(
.collect::<Vec<_>>()
.join(", ");

if let Some(x) = item.escape_doc_comment(" ") {
if let Some(x) = escape_doc_comment(&item.doc_comment, " ") {
method_list_string.push_str_ln(&x);
}

Expand All @@ -210,12 +213,19 @@ pub fn emit_csharp(
"Sequential"
};

if let Some(doc_comment) = escape_doc_comment(&item.doc_comment, " ") {
structs_string.push_str_ln(&doc_comment);
}

structs_string
.push_str_ln(format!(" [StructLayout(LayoutKind.{layout_kind})]").as_str());
structs_string
.push_str_ln(format!(" {accessibility} unsafe partial struct {name}").as_str());
structs_string.push_str_ln(" {");
for field in &item.fields {
if let Some(doc_comment) = escape_doc_comment(&field.doc_comment, " ") {
structs_string.push_str_ln(&doc_comment);
}
if item.is_union {
structs_string.push_str_ln(" [FieldOffset(0)]");
}
Expand Down Expand Up @@ -275,6 +285,10 @@ pub fn emit_csharp(

let mut enum_string = String::new();
for item in enums {
if let Some(doc_comment) = escape_doc_comment(&item.doc_comment, " ") {
enum_string.push_str_ln(&doc_comment);
}

let repr = match &item.repr {
Some(x) => format!(" : {}", convert_token_enum_repr(x)),
None => "".to_string(),
Expand All @@ -285,19 +299,27 @@ pub fn emit_csharp(
}
enum_string.push_str_ln(format!(" {accessibility} enum {name}{repr}").as_str());
enum_string.push_str_ln(" {");
for (name, value) in &item.fields {
let value = match value {
for field in &item.fields {
if let Some(doc_comment) = escape_doc_comment(&field.doc_comment, " ") {
enum_string.push_str_ln(&doc_comment);
}

let value = match &field.value {
Some(x) => format!(" = {x},"),
None => ",".to_string(),
};
enum_string.push_str_ln(format!(" {name}{value}").as_str());
enum_string.push_str_ln(format!(" {}{}", field.name, value).as_str());
}
enum_string.push_str_ln(" }");
enum_string.push('\n');
}

let mut const_string: String = String::new();
for item in consts {
if let Some(doc_comment) = escape_doc_comment(&item.doc_comment, " ") {
const_string.push_str_ln(&doc_comment);
}

let mut type_name = item.rust_type.to_csharp_string(
options,
aliases,
Expand Down Expand Up @@ -359,7 +381,7 @@ pub fn emit_csharp(
)
};

let file_header = if options.csharp_file_header.len() > 0 {
let file_header = if !options.csharp_file_header.is_empty() {
options.csharp_file_header.to_string() + "\n"
} else {
"".to_string()
Expand Down
8 changes: 4 additions & 4 deletions csbindgen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod alias_map;
mod builder;
mod doc_comment;
mod emitter;
mod field_map;
mod parser;
Expand All @@ -14,7 +15,7 @@ use emitter::*;
use field_map::FieldMap;
use parser::*;
use std::{collections::HashSet, error::Error};
use type_meta::{ExternMethod, RustEnum, RustStruct, RustType, RustConst};
use type_meta::{ExternMethod, RustConst, RustEnum, RustStruct, RustType};

enum GenerateKind {
InputBindgen,
Expand Down Expand Up @@ -49,8 +50,7 @@ pub(crate) fn generate(
collect_struct(&file_ast, &mut structs);
collect_enum(&file_ast, &mut enums);

collect_const(&file_ast, &mut consts,options.csharp_generate_const_filter);

collect_const(&file_ast, &mut consts, options.csharp_generate_const_filter);
}

// collect using_types
Expand Down Expand Up @@ -203,7 +203,7 @@ mod tests {
}

fn compare_and_delete_files(original_file_path: &str, generated_file_path: &str) {
let original = fs::read_to_string(original_file_path)
let original = fs::read_to_string(original_file_path)
.expect("Should have been able to read original file");

let generated = fs::read_to_string(generated_file_path)
Expand Down
Loading