@@ -715,46 +715,82 @@ mod tests {
715715 }
716716 }
717717
718- /// The Rust `Sequence` must be the same size as the C
719- /// `rosidl_runtime_c__<T>__Sequence` it is cast to. From Lyrical on, every
720- /// type declared through ROSIDL_RUNTIME_C__PRIMITIVE_SEQUENCE gained two
721- /// trailing `bool` flags, and that macro covers `String`/`U16String` as well
722- /// as the numeric primitives. Message element types keep the 3-field layout.
718+ // The layout of the C structs, as reported by src/sequence_abi.c after the
719+ // C compiler read the headers of this ROS installation.
720+ #[ cfg( has_c_abi_probe) ]
721+ extern "C" {
722+ static rosidl_rs_primitive_sequence_size: usize ;
723+ static rosidl_rs_string_sequence_size: usize ;
724+ static rosidl_rs_u16string_sequence_size: usize ;
725+ static rosidl_rs_sequence_data_offset: usize ;
726+ static rosidl_rs_sequence_size_offset: usize ;
727+ static rosidl_rs_sequence_capacity_offset: usize ;
728+ static rosidl_rs_sequence_align: usize ;
729+ }
730+
731+ /// `Sequence<T>` is handed to C as `rosidl_runtime_c__<T>__Sequence`, so it
732+ /// has to be the size of that struct in the installed headers. From Lyrical
733+ /// on, every type declared through ROSIDL_RUNTIME_C__PRIMITIVE_SEQUENCE
734+ /// carries two trailing flags, and that macro covers `String` and
735+ /// `U16String` as well as the numeric primitives.
723736 #[ test]
724- fn test_sequence_layout_matches_c ( ) {
725- // Mirrors of the two C shapes, so the expected size includes the same
726- // padding the C compiler applies rather than a hand-computed number.
727- #[ repr( C ) ]
728- struct CSequence {
729- data : * mut u8 ,
730- size : usize ,
731- capacity : usize ,
732- }
733- #[ repr( C ) ]
734- struct CSequenceWithFlags {
735- data : * mut u8 ,
736- size : usize ,
737- capacity : usize ,
738- flags : BufferFlags ,
739- }
740- let expected = if cfg ! ( any(
741- ros_distro = "humble" ,
742- ros_distro = "jazzy" ,
743- ros_distro = "kilted"
744- ) ) {
745- std:: mem:: size_of :: < CSequence > ( )
746- } else {
747- std:: mem:: size_of :: < CSequenceWithFlags > ( )
737+ #[ cfg( has_c_abi_probe) ]
738+ fn test_sequence_size_matches_c ( ) {
739+ // SAFETY: These are `const size_t` objects with external linkage.
740+ let ( primitive, string, u16string) = unsafe {
741+ (
742+ rosidl_rs_primitive_sequence_size,
743+ rosidl_rs_string_sequence_size,
744+ rosidl_rs_u16string_sequence_size,
745+ )
748746 } ;
749- assert_eq ! ( std:: mem:: size_of:: <Sequence <f64 >>( ) , expected) ;
750- assert_eq ! ( std:: mem:: size_of:: <Sequence <u8 >>( ) , expected) ;
751- assert_eq ! ( std:: mem:: size_of:: <Sequence <crate :: String >>( ) , expected) ;
752- assert_eq ! ( std:: mem:: size_of:: <Sequence <crate :: WString >>( ) , expected) ;
753- assert_eq ! ( std:: mem:: size_of:: <BoundedSequence <f64 , 4 >>( ) , expected) ;
747+
748+ assert_eq ! ( std:: mem:: size_of:: <Sequence <f64 >>( ) , primitive) ;
749+ assert_eq ! ( std:: mem:: size_of:: <Sequence <u8 >>( ) , primitive) ;
750+ assert_eq ! ( std:: mem:: size_of:: <Sequence <i16 >>( ) , primitive) ;
751+ assert_eq ! ( std:: mem:: size_of:: <Sequence <bool >>( ) , primitive) ;
752+ assert_eq ! ( std:: mem:: size_of:: <BoundedSequence <f64 , 4 >>( ) , primitive) ;
753+
754+ assert_eq ! ( std:: mem:: size_of:: <Sequence <crate :: String >>( ) , string) ;
754755 assert_eq ! (
755756 std:: mem:: size_of:: <BoundedSequence <crate :: String , 4 >>( ) ,
756- expected
757+ string
757758 ) ;
759+ assert_eq ! (
760+ std:: mem:: size_of:: <Sequence <crate :: BoundedString <4 >>>( ) ,
761+ string
762+ ) ;
763+
764+ assert_eq ! ( std:: mem:: size_of:: <Sequence <crate :: WString >>( ) , u16string) ;
765+ assert_eq ! (
766+ std:: mem:: size_of:: <BoundedSequence <crate :: WString , 4 >>( ) ,
767+ u16string
768+ ) ;
769+ assert_eq ! (
770+ std:: mem:: size_of:: <Sequence <crate :: BoundedWString <4 >>>( ) ,
771+ u16string
772+ ) ;
773+ }
774+
775+ /// A matching size is not enough on its own, because it says nothing about
776+ /// the order of the fields C reads and writes.
777+ #[ test]
778+ #[ cfg( has_c_abi_probe) ]
779+ fn test_sequence_field_offsets_match_c ( ) {
780+ // SAFETY: These are `const size_t` objects with external linkage.
781+ let ( data, size, capacity, align) = unsafe {
782+ (
783+ rosidl_rs_sequence_data_offset,
784+ rosidl_rs_sequence_size_offset,
785+ rosidl_rs_sequence_capacity_offset,
786+ rosidl_rs_sequence_align,
787+ )
788+ } ;
789+
790+ assert_eq ! ( std:: mem:: offset_of!( Sequence <f64 >, data) , data) ;
791+ assert_eq ! ( std:: mem:: offset_of!( Sequence <f64 >, size) , size) ;
792+ assert_eq ! ( std:: mem:: offset_of!( Sequence <f64 >, capacity) , capacity) ;
793+ assert_eq ! ( std:: mem:: align_of:: <Sequence <f64 >>( ) , align) ;
758794 }
759795
760796 #[ test]
0 commit comments