Skip to content

Commit 27cbc3d

Browse files
emilkWumpf
andauthored
Implement enum codegen for C++ (#5314)
### What * Part of #3384 ### Coming later * Python * Tests * Switching to using `enum` for existing types ### 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 the web demo (if applicable): * Using newly built examples: [app.rerun.io](https://app.rerun.io/pr/5314/index.html) * Using examples from latest `main` build: [app.rerun.io](https://app.rerun.io/pr/5314/index.html?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [app.rerun.io](https://app.rerun.io/pr/5314/index.html?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG * [x] If applicable, add a new check to the [release checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)! - [PR Build Summary](https://build.rerun.io/pr/5314) - [Docs preview](https://rerun.io/preview/cdd09f81a3a8fa16c2dbbffca7403165bc907739/docs) <!--DOCS-PREVIEW--> - [Examples preview](https://rerun.io/preview/cdd09f81a3a8fa16c2dbbffca7403165bc907739/examples) <!--EXAMPLES-PREVIEW--> - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) --------- Co-authored-by: Andreas Reich <andreas@rerun.io>
1 parent 1ff167c commit 27cbc3d

File tree

16 files changed

+262
-198
lines changed

16 files changed

+262
-198
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ function(rerun_strict_warning_settings target)
8585
-Wno-unreachable-code-return # TODO(emilk): remove this exception - we only need this because of codegen
8686
-Wno-unused-macros
8787
-Wno-unsafe-buffer-usage # There's a few helper ctors that run into this.
88+
-Wno-unknown-warning-option # Otherwise older clang will complain about `-Wno-unsafe-buffer-usage`
8889
)
8990
endif()
9091

crates/re_types/definitions/rerun/datatypes/angle.fbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ union Angle (
1313
"attr.rust.derive": "Copy, PartialEq"
1414
) {
1515
/// \py 3D rotation angle in radians. Only one of `degrees` or `radians` should be set.
16-
Radians: rerun.datatypes.Float32 (order: 100, transparent),
16+
Radians: rerun.datatypes.Float32 (transparent),
1717

1818
/// \py 3D rotation angle in degrees. Only one of `degrees` or `radians` should be set.
19-
Degrees: rerun.datatypes.Float32 (order: 200, transparent),
19+
Degrees: rerun.datatypes.Float32 (transparent),
2020
}

crates/re_types/definitions/rerun/datatypes/rotation3d.fbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ union Rotation3D (
1212
"attr.python.aliases": "Sequence[SupportsFloat]"
1313
) {
1414
/// Rotation defined by a quaternion.
15-
Quaternion: Quaternion (order: 100),
15+
Quaternion: Quaternion,
1616

1717
/// Rotation defined with an axis and an angle.
18-
AxisAngle: RotationAxisAngle (order: 200),
18+
AxisAngle: RotationAxisAngle,
1919
}

crates/re_types/definitions/rerun/datatypes/scale3d.fbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ union Scale3D (
2727
"attr.rust.derive": "Copy, PartialEq"
2828
) {
2929
/// Individual scaling factors for each axis, distorting the original object.
30-
ThreeD: rerun.datatypes.Vec3D (order: 100),
30+
ThreeD: rerun.datatypes.Vec3D,
3131

3232
/// Uniform scaling factor along all axis.
33-
Uniform: rerun.datatypes.Float32 (order: 200, transparent),
33+
Uniform: rerun.datatypes.Float32 (transparent),
3434
}

crates/re_types/definitions/rerun/datatypes/tensor_buffer.fbs

+14-14
Original file line numberDiff line numberDiff line change
@@ -70,48 +70,48 @@ union TensorBuffer (
7070
"attr.rust.derive_only": "Clone, PartialEq"
7171
) {
7272
/// 8bit unsigned integer.
73-
U8: U8Buffer (transparent, order:100),
73+
U8: U8Buffer (transparent),
7474

7575
/// 16bit unsigned integer.
76-
U16: U16Buffer (transparent, order:200),
76+
U16: U16Buffer (transparent),
7777

7878
/// 32bit unsigned integer.
79-
U32: U32Buffer (transparent, order:300),
79+
U32: U32Buffer (transparent),
8080

8181
/// 64bit unsigned integer.
82-
U64: U64Buffer (transparent, order:400),
82+
U64: U64Buffer (transparent),
8383

8484
/// 8bit signed integer.
85-
I8: I8Buffer (transparent, order:500),
85+
I8: I8Buffer (transparent),
8686

8787
/// 16bit signed integer.
88-
I16: I16Buffer (transparent, order:600),
88+
I16: I16Buffer (transparent),
8989

9090
/// 32bit signed integer.
91-
I32: I32Buffer (transparent, order:700),
91+
I32: I32Buffer (transparent),
9292

9393
/// 64bit signed integer.
94-
I64: I64Buffer (transparent, order:800),
94+
I64: I64Buffer (transparent),
9595

9696
/// 16bit IEEE-754 floating point, also known as `half`.
97-
F16: F16Buffer (transparent, order:900),
97+
F16: F16Buffer (transparent),
9898

9999
/// 32bit IEEE-754 floating point, also known as `float` or `single`.
100-
F32: F32Buffer (transparent, order:1000),
100+
F32: F32Buffer (transparent),
101101

102102
/// 64bit IEEE-754 floating point, also known as `double`.
103-
F64: F64Buffer (transparent, order:1200),
103+
F64: F64Buffer (transparent),
104104

105105
/// Raw bytes of a JPEG file.
106-
JPEG: JPEGBuffer (transparent, order:1300),
106+
JPEG: JPEGBuffer (transparent),
107107

108108
/// NV12 is a YUV 4:2:0 chroma downsamples format with 8 bits per channel.
109109
///
110110
/// First comes entire image in Y, followed by interleaved lines ordered as U0, V0, U1, V1, etc.
111-
NV12: NV12Buffer (transparent, order:1400),
111+
NV12: NV12Buffer (transparent),
112112

113113
/// YUY2, also known as YUYV is a YUV 4:2:2 chrome downsampled format with 8 bits per channel.
114114
///
115115
/// The order of the channels is Y0, U0, Y1, V0.
116-
YUY2: YUY2Buffer (transparent, order:1500),
116+
YUY2: YUY2Buffer (transparent),
117117
}

crates/re_types/definitions/rerun/datatypes/transform3d.fbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace rerun.datatypes;
1212
union Transform3D (
1313
"attr.rust.derive": "Copy, PartialEq"
1414
) {
15-
TranslationAndMat3x3: TranslationAndMat3x3 (order: 100),
16-
TranslationRotationScale: TranslationRotationScale3D (order: 200),
15+
TranslationAndMat3x3: TranslationAndMat3x3,
16+
TranslationRotationScale: TranslationRotationScale3D,
1717
// TODO(andreas): Raw 4x4 matrix.
1818
}

crates/re_types/definitions/rerun/testing/datatypes/fuzzy.fbs

+7-7
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ table AffixFuzzer2 (
5757
union AffixFuzzer3 (
5858
"attr.rust.derive": "PartialEq"
5959
) {
60-
degrees: FlattenedScalar (transparent, order: 100),
61-
radians: FlattenedScalar (transparent, nullable, order: 101),
62-
craziness: __AffixFuzzer1Vec (transparent, order: 102),
63-
fixed_size_shenanigans: ArrayOfFloats (transparent, order: 103),
60+
degrees: FlattenedScalar (transparent),
61+
radians: FlattenedScalar (transparent, nullable),
62+
craziness: __AffixFuzzer1Vec (transparent),
63+
fixed_size_shenanigans: ArrayOfFloats (transparent),
6464
}
6565

6666
table __AffixFuzzer3 (transparent, order: 0) {
@@ -74,9 +74,9 @@ table __AffixFuzzer3Vec (transparent, order: 0) {
7474
union AffixFuzzer4 (
7575
"attr.rust.derive": "PartialEq"
7676
) {
77-
single_required: __AffixFuzzer3 (transparent, order: 100),
78-
many_required: __AffixFuzzer3Vec (transparent, order: 101),
79-
many_optional: __AffixFuzzer3Vec (transparent, order: 102, nullable),
77+
single_required: __AffixFuzzer3 (transparent),
78+
many_required: __AffixFuzzer3Vec (transparent),
79+
many_optional: __AffixFuzzer3Vec (transparent, nullable),
8080
}
8181

8282
table AffixFuzzer5 (

crates/re_types_builder/src/bin/build_re_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ fn main() {
110110
let (report, reporter) = re_types_builder::report::init();
111111

112112
let (objects, arrow_registry) =
113-
re_types_builder::generate_lang_agnostic(definitions_dir_path, entrypoint_path);
113+
re_types_builder::generate_lang_agnostic(&reporter, definitions_dir_path, entrypoint_path);
114114

115115
re_tracing::profile_scope!("Language-specific code-gen");
116116
join!(

crates/re_types_builder/src/codegen/cpp/array_builder.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use proc_macro2::Ident;
22
use quote::{format_ident, quote};
33

4-
use crate::{Object, ObjectSpecifics, Objects, Type};
4+
use crate::{Object, ObjectClass, Objects, Type};
55

66
use super::forward_decl::{ForwardDecl, ForwardDecls};
77

@@ -98,9 +98,10 @@ pub fn arrow_array_builder_type_object(
9898
if obj.is_arrow_transparent() {
9999
arrow_array_builder_type_and_declaration(&obj.fields[0].typ, objects, declarations)
100100
} else {
101-
let class_ident = match obj.specifics {
102-
ObjectSpecifics::Struct => format_ident!("StructBuilder"),
103-
ObjectSpecifics::Union { .. } => format_ident!("DenseUnionBuilder"),
101+
let class_ident = match obj.class {
102+
ObjectClass::Struct => format_ident!("StructBuilder"),
103+
ObjectClass::Enum => format_ident!("SparseUnionBuilder"),
104+
ObjectClass::Union => format_ident!("DenseUnionBuilder"),
104105
};
105106

106107
declarations.insert("arrow", ForwardDecl::Class(class_ident.clone()));

crates/re_types_builder/src/codegen/cpp/mod.rs

+124-30
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use rayon::prelude::*;
1414
use crate::{
1515
codegen::{autogen_warning, common::collect_examples_for_api_docs},
1616
format_path,
17-
objects::ObjectType,
18-
ArrowRegistry, Docs, ElementType, GeneratedFiles, Object, ObjectField, ObjectKind,
19-
ObjectSpecifics, Objects, Reporter, Type, ATTR_CPP_NO_FIELD_CTORS,
17+
objects::ObjectClass,
18+
ArrowRegistry, Docs, ElementType, GeneratedFiles, Object, ObjectField, ObjectKind, Objects,
19+
Reporter, Type, ATTR_CPP_NO_FIELD_CTORS,
2020
};
2121

2222
use self::array_builder::{arrow_array_builder_type, arrow_array_builder_type_object};
@@ -381,14 +381,15 @@ struct QuotedObject {
381381
}
382382

383383
impl QuotedObject {
384+
#[allow(clippy::unnecessary_wraps)] // TODO(emilk): implement proper error handling instead of panicking
384385
pub fn new(
385386
objects: &Objects,
386387
obj: &Object,
387388
hpp_includes: Includes,
388389
hpp_type_extensions: &TokenStream,
389390
) -> Result<Self> {
390-
match obj.typ() {
391-
ObjectType::Struct => match obj.kind {
391+
match obj.class {
392+
ObjectClass::Struct => match obj.kind {
392393
ObjectKind::Datatype | ObjectKind::Component => Ok(Self::from_struct(
393394
objects,
394395
obj,
@@ -399,15 +400,13 @@ impl QuotedObject {
399400
Ok(Self::from_archetype(obj, hpp_includes, hpp_type_extensions))
400401
}
401402
},
402-
ObjectType::Union => Ok(Self::from_union(
403+
ObjectClass::Enum => Ok(Self::from_enum(objects, obj, hpp_includes)),
404+
ObjectClass::Union => Ok(Self::from_union(
403405
objects,
404406
obj,
405407
hpp_includes,
406408
hpp_type_extensions,
407409
)),
408-
ObjectType::Enum => {
409-
anyhow::bail!("Enums are not implemented in C++")
410-
}
411410
}
412411
}
413412

@@ -1160,6 +1159,78 @@ impl QuotedObject {
11601159

11611160
Self { hpp, cpp }
11621161
}
1162+
1163+
// C-style enum
1164+
fn from_enum(objects: &Objects, obj: &Object, mut hpp_includes: Includes) -> QuotedObject {
1165+
// We use a simple `enum class`, which is a type-safe enum.
1166+
// They don't support methods, but we don't need them,
1167+
// since `Loggable` is implemented outside the type.
1168+
1169+
let namespace_ident = obj.namespace_ident();
1170+
1171+
let quoted_namespace = if let Some(scope) = obj.scope() {
1172+
let scope = format_ident!("{}", scope);
1173+
quote! { #scope::#namespace_ident}
1174+
} else {
1175+
quote! {#namespace_ident}
1176+
};
1177+
1178+
let type_ident = obj.ident();
1179+
let quoted_docs = quote_obj_docs(obj);
1180+
let deprecation_notice = quote_deprecation_notice(obj);
1181+
1182+
let mut cpp_includes = Includes::new(obj.fqname.clone(), obj.scope());
1183+
let mut hpp_declarations = ForwardDecls::default();
1184+
1185+
let field_declarations = obj
1186+
.fields
1187+
.iter()
1188+
.enumerate()
1189+
.map(|(i, obj_field)| {
1190+
let docstring = quote_field_docs(obj_field);
1191+
let field_name = format_ident!("{}", obj_field.name);
1192+
1193+
// We assign the arrow type index to the enum fields to make encoding simpler and faster:
1194+
let arrow_type_index = proc_macro2::Literal::usize_unsuffixed(1 + i); // 0 is reserved for `_null_markers`
1195+
1196+
quote! {
1197+
#NEWLINE_TOKEN
1198+
#docstring
1199+
#field_name = #arrow_type_index
1200+
}
1201+
})
1202+
.collect_vec();
1203+
1204+
let (hpp_loggable, cpp_loggable) = quote_loggable_hpp_and_cpp(
1205+
obj,
1206+
objects,
1207+
&mut hpp_includes,
1208+
&mut cpp_includes,
1209+
&mut hpp_declarations,
1210+
);
1211+
1212+
let hpp = quote! {
1213+
#hpp_includes
1214+
1215+
#hpp_declarations
1216+
1217+
namespace rerun::#quoted_namespace {
1218+
#quoted_docs
1219+
enum class #deprecation_notice #type_ident : uint8_t {
1220+
#(#field_declarations,)*
1221+
};
1222+
}
1223+
1224+
#hpp_loggable
1225+
};
1226+
let cpp = quote! {
1227+
#cpp_includes
1228+
1229+
#cpp_loggable
1230+
};
1231+
1232+
Self { hpp, cpp }
1233+
}
11631234
}
11641235

11651236
fn single_field_constructor_methods(
@@ -1515,22 +1586,22 @@ fn quote_fill_arrow_array_builder(
15151586
}
15161587
}
15171588
} else {
1518-
match obj.specifics {
1519-
ObjectSpecifics::Struct => {
1589+
match obj.class {
1590+
ObjectClass::Struct => {
15201591
let fill_fields = obj.fields.iter().enumerate().map(
1521-
|(field_index, field)| {
1522-
let field_index = quote_integer(field_index);
1523-
let field_builder = format_ident!("field_builder");
1524-
let field_builder_type = arrow_array_builder_type(&field.typ, objects);
1525-
let field_append = quote_append_field_to_builder(field, &field_builder, false, includes, objects);
1526-
quote! {
1527-
{
1528-
auto #field_builder = static_cast<arrow::#field_builder_type*>(builder->field_builder(#field_index));
1529-
#field_append
1592+
|(field_index, field)| {
1593+
let field_index = quote_integer(field_index);
1594+
let field_builder = format_ident!("field_builder");
1595+
let field_builder_type = arrow_array_builder_type(&field.typ, objects);
1596+
let field_append = quote_append_field_to_builder(field, &field_builder, false, includes, objects);
1597+
quote! {
1598+
{
1599+
auto #field_builder = static_cast<arrow::#field_builder_type*>(builder->field_builder(#field_index));
1600+
#field_append
1601+
}
15301602
}
1531-
}
1532-
},
1533-
);
1603+
},
1604+
);
15341605

15351606
quote! {
15361607
#parameter_check
@@ -1539,7 +1610,21 @@ fn quote_fill_arrow_array_builder(
15391610
ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast<int64_t>(num_elements), nullptr));
15401611
}
15411612
}
1542-
ObjectSpecifics::Union { .. } => {
1613+
1614+
// C-style enum, encoded as a sparse arrow union
1615+
ObjectClass::Enum => {
1616+
quote! {
1617+
#parameter_check
1618+
ARROW_RETURN_NOT_OK(#builder->Reserve(static_cast<int64_t>(num_elements)));
1619+
for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) {
1620+
const auto variant = elements[elem_idx];
1621+
ARROW_RETURN_NOT_OK(#builder->Append(static_cast<int8_t>(variant)));
1622+
}
1623+
}
1624+
}
1625+
1626+
// sum-type union, encoded as a dense arrow union
1627+
ObjectClass::Union => {
15431628
let variant_builder = format_ident!("variant_builder");
15441629

15451630
let tag_cases = obj.fields
@@ -2227,16 +2312,25 @@ fn quote_arrow_data_type(
22272312
.iter()
22282313
.map(|field| quote_arrow_field_type(field, objects, includes));
22292314

2230-
match &obj.specifics {
2231-
ObjectSpecifics::Union { .. } => {
2315+
match &obj.class {
2316+
ObjectClass::Struct => {
2317+
quote!(arrow::struct_({ #(#quoted_fields,)* }))
2318+
}
2319+
ObjectClass::Enum => {
22322320
quote! {
2233-
arrow::dense_union({
2234-
arrow::field("_null_markers", arrow::null(), true, nullptr), #(#quoted_fields,)*
2321+
arrow::sparse_union({
2322+
arrow::field("_null_markers", arrow::null(), true, nullptr),
2323+
#(#quoted_fields,)*
22352324
})
22362325
}
22372326
}
2238-
ObjectSpecifics::Struct => {
2239-
quote!(arrow::struct_({ #(#quoted_fields,)* }))
2327+
ObjectClass::Union => {
2328+
quote! {
2329+
arrow::dense_union({
2330+
arrow::field("_null_markers", arrow::null(), true, nullptr),
2331+
#(#quoted_fields,)*
2332+
})
2333+
}
22402334
}
22412335
}
22422336
}

0 commit comments

Comments
 (0)