diff --git a/crates/build/re_types_builder/src/codegen/rust/api.rs b/crates/build/re_types_builder/src/codegen/rust/api.rs index 2880f8c00077..c80138f4810e 100644 --- a/crates/build/re_types_builder/src/codegen/rust/api.rs +++ b/crates/build/re_types_builder/src/codegen/rust/api.rs @@ -284,6 +284,15 @@ fn quote_struct( let quoted_repr_clause = quote_meta_clause_from_obj(obj, ATTR_RUST_REPR, "repr"); let quoted_custom_clause = quote_meta_clause_from_obj(obj, ATTR_RUST_CUSTOM_CLAUSE, ""); + // Eager archetypes must always derive Default. + let quoted_eager_derive_default_clause = (obj.is_eager_rust_archetype() + && !quoted_derive_clause.to_string().contains("Default")) + .then(|| { + quote! { + #[derive(Default)] + } + }); + let quoted_fields = fields .iter() .map(|obj_field| ObjectFieldTokenizer(reporter, obj, obj_field).quoted(objects)); @@ -353,6 +362,7 @@ fn quote_struct( #quoted_doc #quoted_derive_clone_debug #quoted_derive_clause + #quoted_eager_derive_default_clause #quoted_repr_clause #quoted_custom_clause #quoted_deprecation_notice @@ -1731,7 +1741,7 @@ fn quote_builder_from_obj(reporter: &Reporter, objects: &Objects, obj: &Object) } }); - let eager_with_methods = optional.iter().map(|field| { + let eager_with_methods = required.iter().chain(optional.iter()).map(|field| { // fn with_*() let field_name = format_ident!("{}", field.name); let descr_fn_name = format_ident!("descriptor_{field_name}"); @@ -1760,8 +1770,47 @@ fn quote_builder_from_obj(reporter: &Reporter, objects: &Objects, obj: &Object) } }); + let partial_update_methods = obj.is_eager_rust_archetype().then(|| { + let update_fields_doc = + quote_doc_line(&format!("Update only some specific fields of a `{name}`.")); + let clear_fields_doc = quote_doc_line(&format!("Clear all the fields of a `{name}`.")); + + let fields = required.iter().chain(optional.iter()).map(|field| { + let field_name = format_ident!("{}", field.name); + let descr_fn_name = format_ident!("descriptor_{field_name}"); + let (typ, _) = quote_field_type_from_typ(&field.typ, true); + quote! { + #field_name: Some(SerializedComponentBatch::new( + #typ::arrow_empty(), + Self::#descr_fn_name(), + )) + } + }); + + quote! { + #update_fields_doc + #[inline] + pub fn update_fields() -> Self { + Self::default() + } + + #clear_fields_doc + #[inline] + pub fn clear_fields() -> Self { + use ::re_types_core::Loggable as _; + Self { + #(#fields),* + } + } + } + }); + let with_methods = if obj.is_eager_rust_archetype() { - quote!(#(#eager_with_methods)*) + quote! { + #partial_update_methods + + #(#eager_with_methods)* + } } else { quote!(#(#native_with_methods)*) }; diff --git a/crates/store/re_types/src/archetypes/points3d.rs b/crates/store/re_types/src/archetypes/points3d.rs index cd9ed1edb7b2..c540dcdc24a6 100644 --- a/crates/store/re_types/src/archetypes/points3d.rs +++ b/crates/store/re_types/src/archetypes/points3d.rs @@ -94,7 +94,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// /// /// -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Default)] pub struct Points3D { /// All the 3D positions at which the point cloud shows points. pub positions: Option, @@ -382,6 +382,58 @@ impl Points3D { } } + /// Update only some specific fields of a `Points3D`. + #[inline] + pub fn update_fields() -> Self { + Self::default() + } + + /// Clear all the fields of a `Points3D`. + #[inline] + pub fn clear_fields() -> Self { + use ::re_types_core::Loggable as _; + Self { + positions: Some(SerializedComponentBatch::new( + crate::components::Position3D::arrow_empty(), + Self::descriptor_positions(), + )), + radii: Some(SerializedComponentBatch::new( + crate::components::Radius::arrow_empty(), + Self::descriptor_radii(), + )), + colors: Some(SerializedComponentBatch::new( + crate::components::Color::arrow_empty(), + Self::descriptor_colors(), + )), + labels: Some(SerializedComponentBatch::new( + crate::components::Text::arrow_empty(), + Self::descriptor_labels(), + )), + show_labels: Some(SerializedComponentBatch::new( + crate::components::ShowLabels::arrow_empty(), + Self::descriptor_show_labels(), + )), + class_ids: Some(SerializedComponentBatch::new( + crate::components::ClassId::arrow_empty(), + Self::descriptor_class_ids(), + )), + keypoint_ids: Some(SerializedComponentBatch::new( + crate::components::KeypointId::arrow_empty(), + Self::descriptor_keypoint_ids(), + )), + } + } + + /// All the 3D positions at which the point cloud shows points. + #[inline] + pub fn with_positions( + mut self, + positions: impl IntoIterator>, + ) -> Self { + self.positions = try_serialize_field(Self::descriptor_positions(), positions); + self + } + /// Optional radii for the points, effectively turning them into circles. #[inline] pub fn with_radii( diff --git a/crates/store/re_types_core/src/loggable.rs b/crates/store/re_types_core/src/loggable.rs index 0be4bdcc9bf2..dab5fa39086d 100644 --- a/crates/store/re_types_core/src/loggable.rs +++ b/crates/store/re_types_core/src/loggable.rs @@ -25,6 +25,12 @@ pub trait Loggable: 'static + Send + Sync + Clone + Sized + SizeBytes { /// The underlying [`arrow::datatypes::DataType`], excluding datatype extensions. fn arrow_datatype() -> arrow::datatypes::DataType; + // Returns an empty Arrow array that matches this `Loggable`'s underlying datatype. + #[inline] + fn arrow_empty() -> arrow::array::ArrayRef { + arrow::array::new_empty_array(&Self::arrow_datatype()) + } + /// Given an iterator of owned or reference values to the current [`Loggable`], serializes /// them into an Arrow array. ///