Skip to content

Commit

Permalink
C++ codegen for reporting arrow data type for structs (#2756)
Browse files Browse the repository at this point in the history
* Part of #2647
* Next step after #2707

### What

Implements `to_arrow_data_type` (same exists in Rust) for all C++
components and datatypes.

Started splitting up `cpp.rs` a tiny little bit, not gonna go the single
file way `rust.rs` went there, too hard to handle now that there's more
than one author on it.

Test it yourself with `cargo codegen &&
./examples/cpp/minimal/build_and_run.sh`

Rough next steps:
* implement same for unions
* implement extension type decl (missing in this PR!), needed for
instance to declare component types
* serialize out data
* testing (nothing in this PR is tested other than "it compiles!")
* utilities for better usability

### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested [demo.rerun.io](https://demo.rerun.io/pr/2756) (if
applicable)

- [PR Build Summary](https://build.rerun.io/pr/2756)
- [Docs
preview](https://rerun.io/preview/pr%3Aandreas%2Fcpp-arrow-datatype-definition-for-structs/docs)
- [Examples
preview](https://rerun.io/preview/pr%3Aandreas%2Fcpp-arrow-datatype-definition-for-structs/examples)
  • Loading branch information
Wumpf committed Jul 20, 2023
1 parent fad984a commit 96f5dde
Show file tree
Hide file tree
Showing 94 changed files with 2,487 additions and 62 deletions.
2 changes: 1 addition & 1 deletion crates/re_types/source_hash.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This is a sha256 hash for all direct and indirect dependencies of this crate's build script.
# It can be safely removed at anytime to force the build script to run again.
# Check out build.rs to see how it's computed.
e11a5960ff29c75374e3298ae9f2728d9d6d838c517e1b1ee3bc2a18fada0efb
e45f620a5a7e37189161bd67ebaa7b111fa0569a315fb28bd960dd0e564b1149
74 changes: 74 additions & 0 deletions crates/re_types_builder/src/codegen/cpp/forward_decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::collections::{BTreeMap, BTreeSet};

use proc_macro2::TokenStream;
use quote::{format_ident, quote};

use super::NEWLINE_TOKEN;

/// A C++ forward declaration.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[allow(dead_code)]
pub enum ForwardDecl {
Struct(String),
Class(String),
}

impl quote::ToTokens for ForwardDecl {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
ForwardDecl::Struct(name) => {
let name_ident = format_ident!("{name}");
quote! { struct #name_ident; }
}
ForwardDecl::Class(name) => {
let name_ident = format_ident!("{name}");
quote! { class #name_ident; }
}
}
.to_tokens(tokens);
}
}

/// Keeps track of necessary forward decls for a file.
#[derive(Default)]
pub struct ForwardDecls {
/// E.g. `DataType` in `arrow` etc.
declarations_per_namespace: BTreeMap<String, BTreeSet<ForwardDecl>>,
}

impl ForwardDecls {
pub fn insert(&mut self, namespace: impl Into<String>, decl: ForwardDecl) {
self.declarations_per_namespace
.entry(namespace.into())
.or_default()
.insert(decl);
}
}

impl quote::ToTokens for ForwardDecls {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self {
declarations_per_namespace,
} = self;

let declarations = declarations_per_namespace
.iter()
.map(|(namespace, declarations)| {
let namespace_ident = format_ident!("{namespace}");
quote! {
#NEWLINE_TOKEN
namespace #namespace_ident {
#(#declarations)*
}
}
});

quote! {
#NEWLINE_TOKEN
#(#declarations)*
#NEWLINE_TOKEN
#NEWLINE_TOKEN
}
.to_tokens(tokens);
}
}
40 changes: 40 additions & 0 deletions crates/re_types_builder/src/codegen/cpp/includes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::collections::BTreeSet;

use proc_macro2::TokenStream;
use quote::quote;

use super::{NEWLINE_TOKEN, SYS_INCLUDE_PATH_PREFIX_TOKEN, SYS_INCLUDE_PATH_SUFFIX_TOKEN};

/// Keeps track of necessary includes for a file.
#[derive(Default)]
pub struct Includes {
/// `#include <vector>` etc
pub system: BTreeSet<String>,

/// `#include datatypes.hpp"` etc
pub local: BTreeSet<String>,
}

impl quote::ToTokens for Includes {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self { system, local } = self;

let hash = quote! { # };
let system = system.iter().map(|name| {
// Need to mark system includes with tokens since they are usually not idents (can contain slashes and dots)
quote! { #hash include #SYS_INCLUDE_PATH_PREFIX_TOKEN #name #SYS_INCLUDE_PATH_SUFFIX_TOKEN #NEWLINE_TOKEN }
});
let local = local.iter().map(|name| {
quote! { #hash include #name #NEWLINE_TOKEN }
});

quote! {
#(#system)*
#NEWLINE_TOKEN
#(#local)*
#NEWLINE_TOKEN
#NEWLINE_TOKEN
}
.to_tokens(tokens);
}
}
122 changes: 122 additions & 0 deletions crates/re_types_builder/src/codegen/cpp/method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use proc_macro2::{Ident, TokenStream};
use quote::quote;

use super::{doc_comment, NEWLINE_TOKEN};

#[derive(Default)]
pub struct MethodDeclaration {
pub is_static: bool,
pub return_type: TokenStream,
pub name_and_parameters: TokenStream,
}

impl MethodDeclaration {
pub fn constructor(declaration: TokenStream) -> Self {
Self {
is_static: false,
return_type: TokenStream::new(),
name_and_parameters: declaration,
}
}

pub fn to_hpp_tokens(&self) -> TokenStream {
let Self {
is_static,
return_type,
name_and_parameters,
} = self;

let modifiers = if *is_static {
quote! { static }
} else {
quote! {}
};
quote! {
#modifiers #return_type #name_and_parameters
}
}

pub fn to_cpp_tokens(&self, class_or_struct_name: &Ident) -> TokenStream {
let Self {
is_static: _,
return_type,
name_and_parameters,
} = self;

quote! {
#return_type #class_or_struct_name::#name_and_parameters
}
}
}

/// A Cpp struct/class method.
pub struct Method {
pub doc_string: String,
pub declaration: MethodDeclaration,
pub definition_body: TokenStream,
pub inline: bool,
}

impl Default for Method {
fn default() -> Self {
Self {
doc_string: String::new(),
declaration: MethodDeclaration::default(),
definition_body: TokenStream::new(),
inline: true,
}
}
}

impl Method {
pub fn to_hpp_tokens(&self) -> TokenStream {
let Self {
doc_string,
declaration,
definition_body,
inline: is_inline,
} = self;

let quoted_doc = if doc_string.is_empty() {
quote! {}
} else {
doc_comment(doc_string)
};
let declaration = declaration.to_hpp_tokens();
if *is_inline {
quote! {
#NEWLINE_TOKEN
#quoted_doc
#declaration {
#definition_body
}
}
} else {
quote! {
#NEWLINE_TOKEN
#quoted_doc
#declaration;
}
}
}

pub fn to_cpp_tokens(&self, class_or_struct_name: &Ident) -> TokenStream {
let Self {
doc_string: _,
declaration,
definition_body,
inline,
} = self;

let declaration = declaration.to_cpp_tokens(class_or_struct_name);
if *inline {
quote! {}
} else {
quote! {
#declaration {
#definition_body
}
}
}
}
}
Loading

0 comments on commit 96f5dde

Please sign in to comment.