diff --git a/build.gradle b/build.gradle
index 6a20ee7201..59a1f41042 100644
--- a/build.gradle
+++ b/build.gradle
@@ -654,6 +654,7 @@ tasks.register('generateRustTestCodecs', JavaExec) {
'sbe-tool/src/test/resources/issue984.xml',
'sbe-tool/src/test/resources/issue987.xml',
'sbe-tool/src/test/resources/issue1028.xml',
+ 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml',
'sbe-tool/src/test/resources/example-bigendian-test-schema.xml',
'sbe-tool/src/test/resources/nested-composite-name.xml',
]
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index f15d4d2f6d..2d4f3d4a49 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -19,6 +19,7 @@ issue_987 = { path = "../generated/rust/issue987" }
issue_1028 = { path = "../generated/rust/issue1028" }
baseline_bigendian = { path = "../generated/rust/baseline-bigendian" }
nested_composite_name = { path = "../generated/rust/nested-composite-name" }
+fixed_sized_primitive_array = { path = "../generated/rust/fixed_sized_primitive_array" }
[dev-dependencies]
criterion = "0.5"
diff --git a/rust/tests/fixed_sized_primitive_array.rs b/rust/tests/fixed_sized_primitive_array.rs
new file mode 100644
index 0000000000..43e82f347d
--- /dev/null
+++ b/rust/tests/fixed_sized_primitive_array.rs
@@ -0,0 +1,1110 @@
+use fixed_sized_primitive_array::{
+ demo_codec::{DemoDecoder, DemoEncoder},
+ message_header_codec::{MessageHeaderDecoder, ENCODED_LENGTH},
+ ReadBuf, WriteBuf,
+};
+
+fn create_encoder(buffer: &mut [u8]) -> DemoEncoder {
+ let encoder = DemoEncoder::default().wrap(WriteBuf::new(buffer), ENCODED_LENGTH);
+ let mut header = encoder.header(0);
+ header.parent().unwrap()
+}
+
+#[test]
+fn test_encode_then_decode_u8_slice() {
+ let uninit = 1u8;
+
+ let test_data = [
+ b"" as &[u8],
+ b"0" as &[u8],
+ b"01" as &[u8],
+ b"012" as &[u8],
+ b"0123" as &[u8],
+ b"01234" as &[u8],
+ b"012345" as &[u8],
+ b"0123456" as &[u8],
+ b"01234567" as &[u8],
+ b"012345678" as &[u8],
+ b"0123456789" as &[u8],
+ b"0123456789A" as &[u8],
+ b"0123456789AB" as &[u8],
+ b"0123456789ABC" as &[u8],
+ b"0123456789ABCD" as &[u8],
+ b"0123456789ABCDE" as &[u8],
+ b"0123456789ABCDEF" as &[u8],
+ b"0123456789abcdef" as &[u8],
+ b"0123456789abcdef0" as &[u8],
+ b"0123456789abcdef01" as &[u8],
+ b"0123456789abcdef012" as &[u8],
+ b"0123456789abcdef0123" as &[u8],
+ b"0123456789abcdef01234" as &[u8],
+ b"0123456789abcdef012345" as &[u8],
+ b"0123456789abcdef0123456" as &[u8],
+ b"0123456789abcdef01234567" as &[u8],
+ b"0123456789abcdef012345678" as &[u8],
+ b"0123456789abcdef0123456789" as &[u8],
+ b"0123456789abcdef0123456789A" as &[u8],
+ b"0123456789abcdef0123456789AB" as &[u8],
+ b"0123456789abcdef0123456789ABC" as &[u8],
+ b"0123456789abcdef0123456789ABCD" as &[u8],
+ b"0123456789abcdef0123456789ABCDE" as &[u8],
+ b"0123456789abcdef0123456789ABCDEF" as &[u8],
+ ];
+
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ macro_rules! run_encode_then_decode_for_array_of_u8_len_16 {
+ ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr) => {
+ for each_slice in test_data {
+ let encode_func = $encode_func;
+ let decode_func = $decode_func;
+ let end_encode_func = $end_encode_func;
+ let end_decode_func = $end_decode_func;
+
+ let cur_len = each_slice.len();
+ let effective_len = cur_len.min(16);
+
+ // encode...
+ let mut buffer = [uninit; 1024];
+ let mut encoder = create_encoder(&mut buffer);
+
+ encode_func(&mut encoder, each_slice);
+
+ let end = 1i32;
+ end_encode_func(&mut encoder, end);
+
+ // decode...
+ let buf = ReadBuf::new(buffer.as_slice());
+ let header = MessageHeaderDecoder::default().wrap(buf, 0);
+
+ let decoder = DemoDecoder::default().header(header, 0);
+ let decoded = decode_func(&decoder);
+ for each_idx in 0..effective_len {
+ assert_eq!(
+ each_slice[each_idx], decoded[each_idx],
+ "Item mismatched at {}/{}",
+ each_idx, cur_len
+ );
+ }
+ for each_idx in effective_len..16 {
+ assert_eq!(
+ decoded[each_idx], uninit,
+ "Item should not be padded ZERO at {}/{}",
+ each_idx, cur_len
+ );
+ }
+ let decoded_end = end_decode_func(&decoder);
+ assert_eq!(decoded_end, end, "End Item should equal",);
+ }
+ };
+ }
+
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_char_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_char,
+ DemoEncoder::fixed_16_char_end,
+ DemoDecoder::fixed_16_char_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_ascii_char_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_ascii_char,
+ DemoEncoder::fixed_16_ascii_char_end,
+ DemoDecoder::fixed_16_ascii_char_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_gb_18030_char_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_gb_18030_char,
+ DemoEncoder::fixed_16_gb_18030_char_end,
+ DemoDecoder::fixed_16_gb_18030_char_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_utf_8_char_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_utf_8_char,
+ DemoEncoder::fixed_16_utf_8_char_end,
+ DemoDecoder::fixed_16_utf_8_char_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_u8_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_u8,
+ DemoEncoder::fixed_16_u8_end,
+ DemoDecoder::fixed_16_u8_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_ascii_u8_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_ascii_u8,
+ DemoEncoder::fixed_16_ascii_u8_end,
+ DemoDecoder::fixed_16_ascii_u8_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_gb_18030_u8_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_gb_18030_u8,
+ DemoEncoder::fixed_16_gb_18030_u8_end,
+ DemoDecoder::fixed_16_gb_18030_u8_end
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_utf_8_u8_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_utf_8_u8,
+ DemoEncoder::fixed_16_utf_8u_8_end,
+ DemoDecoder::fixed_16_utf_8u_8_end
+ );
+}
+
+#[test]
+fn test_encode_then_decode_non_u8_signed_primitive_slice() {
+ let uninit = 1u8;
+
+ //
+ //
+ //
+ //
+ macro_rules! run_encode_then_decode_for_array_of_signed_len_16 {
+ ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty, $existed:expr) => {
+ let test_data = [
+ &[] as &[$i_type],
+ &[1 as $i_type] as &[$i_type],
+ &[0 as $i_type] as &[$i_type],
+ &[-1 as $i_type] as &[$i_type],
+ &[-1, 1 as $i_type] as &[$i_type],
+ &[-1, 0, 1 as $i_type] as &[$i_type],
+ &[-2, -1, 1, 2 as $i_type] as &[$i_type],
+ &[-2, -1, 0, 1, 2 as $i_type] as &[$i_type],
+ &[-3, -2, -1, 1, 2, 3 as $i_type] as &[$i_type],
+ &[-3, -2, -1, 0, 1, 2, 3 as $i_type] as &[$i_type],
+ &[-4, -3, -2, -1, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[-4, -3, -2, -1, 0, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[-5, -4, -3, -2, -1, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[-6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[-7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type],
+ &[
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7 as $i_type,
+ ] as &[$i_type],
+ &[
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ -9,
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ &[
+ -9,
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ ];
+
+ let existed = $existed;
+
+ for each_slice in test_data {
+ let encode_func = $encode_func;
+ let decode_func = $decode_func;
+ let end_encode_func = $end_encode_func;
+ let end_decode_func = $end_decode_func;
+
+ let cur_len = each_slice.len();
+ let effective_len = cur_len.min(16);
+
+ // encode...
+ let mut buffer = [uninit; 1024];
+ let mut encoder = create_encoder(&mut buffer);
+
+ encode_func(&mut encoder, &each_slice);
+
+ let end = 1i32;
+ end_encode_func(&mut encoder, end);
+
+ // decode...
+ let buf = ReadBuf::new(buffer.as_slice());
+ let header = MessageHeaderDecoder::default().wrap(buf, 0);
+
+ let decoder = DemoDecoder::default().header(header, 0);
+ let decoded = decode_func(&decoder);
+ for each_idx in 0..effective_len {
+ assert_eq!(
+ each_slice[each_idx],
+ decoded[each_idx],
+ "Item mismatched at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ for each_idx in effective_len..16 {
+ assert_eq!(
+ decoded[each_idx],
+ existed,
+ "Item should not be padded ZERO at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ let decoded_end = end_decode_func(&decoder);
+ assert_eq!(decoded_end, end, "End Item should equal",);
+ }
+ };
+ }
+
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i8_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_i8,
+ DemoEncoder::fixed_16_i8_end,
+ DemoDecoder::fixed_16_i8_end,
+ i8, i8::from_le_bytes([uninit])
+ );
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i16_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_i16,
+ DemoEncoder::fixed_16_i16_end,
+ DemoDecoder::fixed_16_i16_end,
+ i16, i16::from_le_bytes([uninit, uninit])
+ );
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i32_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_i32,
+ DemoEncoder::fixed_16_i32_end,
+ DemoDecoder::fixed_16_i32_end,
+ i32, i32::from_le_bytes([uninit, uninit, uninit, uninit])
+ );
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i64_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_i64,
+ DemoEncoder::fixed_16_i64_end,
+ DemoDecoder::fixed_16_i64_end,
+ i64, i64::from_le_bytes([uninit, uninit, uninit, uninit, uninit, uninit, uninit, uninit])
+ );
+}
+
+#[test]
+fn test_encode_then_decode_non_u8_unsigned_primitive_slice() {
+ let uninit = 1u8;
+
+ //
+ //
+ macro_rules! run_encode_then_decode_for_array_of_unsigned_len_16 {
+ ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty, $existed:expr) => {
+ let test_data = [
+ &[] as &[$i_type],
+ &[1 as $i_type] as &[$i_type],
+ &[0 as $i_type] as &[$i_type],
+ &[11 as $i_type] as &[$i_type],
+ &[11, 1 as $i_type] as &[$i_type],
+ &[11, 0, 1 as $i_type] as &[$i_type],
+ &[12, 11, 1, 2 as $i_type] as &[$i_type],
+ &[12, 11, 0, 1, 2 as $i_type] as &[$i_type],
+ &[13, 12, 11, 1, 2, 3 as $i_type] as &[$i_type],
+ &[13, 12, 11, 0, 1, 2, 3 as $i_type] as &[$i_type],
+ &[14, 13, 12, 11, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[14, 13, 12, 11, 0, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[15, 14, 13, 12, 11, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[16, 15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[17, 16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type],
+ &[
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7 as $i_type,
+ ] as &[$i_type],
+ &[
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ 19,
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ &[
+ 19,
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ ];
+
+ let existed = $existed;
+
+ for each_slice in test_data {
+ let encode_func = $encode_func;
+ let decode_func = $decode_func;
+ let end_encode_func = $end_encode_func;
+ let end_decode_func = $end_decode_func;
+
+ let cur_len = each_slice.len();
+ let effective_len = cur_len.min(16);
+
+ // encode...
+ let mut buffer = [uninit; 1024];
+ let mut encoder = create_encoder(&mut buffer);
+
+ encode_func(&mut encoder, each_slice);
+
+ let end = 1i32;
+ end_encode_func(&mut encoder, end);
+
+ // decode...
+ let buf = ReadBuf::new(buffer.as_slice());
+ let header = MessageHeaderDecoder::default().wrap(buf, 0);
+
+ let decoder = DemoDecoder::default().header(header, 0);
+ let decoded = decode_func(&decoder);
+ for each_idx in 0..effective_len {
+ assert_eq!(
+ each_slice[each_idx],
+ decoded[each_idx],
+ "Item mismatched at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+
+ for each_idx in effective_len..16 {
+ assert_eq!(
+ decoded[each_idx],
+ existed,
+ "Item should not be padded ZERO at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ let decoded_end = end_decode_func(&decoder);
+ assert_eq!(decoded_end, end, "End Item should equal",);
+ }
+ };
+ }
+
+ run_encode_then_decode_for_array_of_unsigned_len_16!(
+ DemoEncoder::fixed_16_u16_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_u16,
+ DemoEncoder::fixed_16_u16_end,
+ DemoDecoder::fixed_16_u16_end,
+ u16,
+ u16::from_le_bytes([uninit, uninit])
+ );
+ run_encode_then_decode_for_array_of_unsigned_len_16!(
+ DemoEncoder::fixed_16_u32_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_u32,
+ DemoEncoder::fixed_16_u32_end,
+ DemoDecoder::fixed_16_u32_end,
+ u32,
+ u32::from_le_bytes([uninit, uninit, uninit, uninit])
+ );
+ run_encode_then_decode_for_array_of_unsigned_len_16!(
+ DemoEncoder::fixed_16_u64_at_most_16_items_from_slice,
+ DemoDecoder::fixed_16_u64,
+ DemoEncoder::fixed_16_u64_end,
+ DemoDecoder::fixed_16_u64_end,
+ u64,
+ u64::from_le_bytes([uninit, uninit, uninit, uninit, uninit, uninit, uninit, uninit])
+ );
+}
+
+#[test]
+fn test_encode_then_decode_u8_slice_padded() {
+ let uninit = 1u8;
+
+ let test_data = [
+ b"" as &[u8],
+ b"0" as &[u8],
+ b"01" as &[u8],
+ b"012" as &[u8],
+ b"0123" as &[u8],
+ b"01234" as &[u8],
+ b"012345" as &[u8],
+ b"0123456" as &[u8],
+ b"01234567" as &[u8],
+ b"012345678" as &[u8],
+ b"0123456789" as &[u8],
+ b"0123456789A" as &[u8],
+ b"0123456789AB" as &[u8],
+ b"0123456789ABC" as &[u8],
+ b"0123456789ABCD" as &[u8],
+ b"0123456789ABCDE" as &[u8],
+ b"0123456789ABCDEF" as &[u8],
+ b"0123456789abcdef" as &[u8],
+ b"0123456789abcdef0" as &[u8],
+ b"0123456789abcdef01" as &[u8],
+ b"0123456789abcdef012" as &[u8],
+ b"0123456789abcdef0123" as &[u8],
+ b"0123456789abcdef01234" as &[u8],
+ b"0123456789abcdef012345" as &[u8],
+ b"0123456789abcdef0123456" as &[u8],
+ b"0123456789abcdef01234567" as &[u8],
+ b"0123456789abcdef012345678" as &[u8],
+ b"0123456789abcdef0123456789" as &[u8],
+ b"0123456789abcdef0123456789A" as &[u8],
+ b"0123456789abcdef0123456789AB" as &[u8],
+ b"0123456789abcdef0123456789ABC" as &[u8],
+ b"0123456789abcdef0123456789ABCD" as &[u8],
+ b"0123456789abcdef0123456789ABCDE" as &[u8],
+ b"0123456789abcdef0123456789ABCDEF" as &[u8],
+ ];
+
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ macro_rules! run_encode_then_decode_for_array_of_u8_len_16 {
+ ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr,) => {
+ for each_slice in test_data {
+ let encode_func = $encode_func;
+ let decode_func = $decode_func;
+ let end_encode_func = $end_encode_func;
+ let end_decode_func = $end_decode_func;
+
+ let cur_len = each_slice.len();
+ let effective_len = cur_len.min(16);
+
+ // encode...
+ let mut buffer = [uninit; 1024];
+ let mut encoder = create_encoder(&mut buffer);
+
+ encode_func(&mut encoder, each_slice);
+
+ let end = 1i32;
+ end_encode_func(&mut encoder, end);
+
+ // decode...
+ let buf = ReadBuf::new(buffer.as_slice());
+ let header = MessageHeaderDecoder::default().wrap(buf, 0);
+
+ let decoder = DemoDecoder::default().header(header, 0);
+ let decoded = decode_func(&decoder);
+ for each_idx in 0..effective_len {
+ assert_eq!(
+ each_slice[each_idx], decoded[each_idx],
+ "Item mismatched at {}/{}",
+ each_idx, cur_len
+ );
+ }
+ for each_idx in effective_len..16 {
+ assert_eq!(
+ decoded[each_idx], 0,
+ "Item should be padded ZERO at {}/{}",
+ each_idx, cur_len
+ );
+ }
+ let decoded_end = end_decode_func(&decoder);
+ assert_eq!(decoded_end, end, "End Item should equal",);
+ }
+ };
+ }
+
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_char_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_char,
+ DemoEncoder::fixed_16_char_end,
+ DemoDecoder::fixed_16_char_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_ascii_char_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_ascii_char,
+ DemoEncoder::fixed_16_ascii_char_end,
+ DemoDecoder::fixed_16_ascii_char_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_gb_18030_char_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_gb_18030_char,
+ DemoEncoder::fixed_16_gb_18030_char_end,
+ DemoDecoder::fixed_16_gb_18030_char_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_utf_8_char_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_utf_8_char,
+ DemoEncoder::fixed_16_utf_8_char_end,
+ DemoDecoder::fixed_16_utf_8_char_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_u8_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_u8,
+ DemoEncoder::fixed_16_u8_end,
+ DemoDecoder::fixed_16_u8_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_ascii_u8_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_ascii_u8,
+ DemoEncoder::fixed_16_ascii_u8_end,
+ DemoDecoder::fixed_16_ascii_u8_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_gb_18030_u8_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_gb_18030_u8,
+ DemoEncoder::fixed_16_gb_18030_u8_end,
+ DemoDecoder::fixed_16_gb_18030_u8_end,
+ );
+ run_encode_then_decode_for_array_of_u8_len_16!(
+ DemoEncoder::fixed_16_utf_8_u8_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_utf_8_u8,
+ DemoEncoder::fixed_16_utf_8u_8_end,
+ DemoDecoder::fixed_16_utf_8u_8_end,
+ );
+}
+
+#[test]
+fn test_encode_then_decode_non_u8_signed_primitive_slice_padded() {
+ let uninit = 1u8;
+
+ //
+ //
+ //
+ //
+ macro_rules! run_encode_then_decode_for_array_of_signed_len_16 {
+ ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty,) => {
+ let test_data = [
+ &[] as &[$i_type],
+ &[1 as $i_type] as &[$i_type],
+ &[0 as $i_type] as &[$i_type],
+ &[-1 as $i_type] as &[$i_type],
+ &[-1, 1 as $i_type] as &[$i_type],
+ &[-1, 0, 1 as $i_type] as &[$i_type],
+ &[-2, -1, 1, 2 as $i_type] as &[$i_type],
+ &[-2, -1, 0, 1, 2 as $i_type] as &[$i_type],
+ &[-3, -2, -1, 1, 2, 3 as $i_type] as &[$i_type],
+ &[-3, -2, -1, 0, 1, 2, 3 as $i_type] as &[$i_type],
+ &[-4, -3, -2, -1, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[-4, -3, -2, -1, 0, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[-5, -4, -3, -2, -1, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[-6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[-7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type],
+ &[
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7 as $i_type,
+ ] as &[$i_type],
+ &[
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ -9,
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ &[
+ -9,
+ -8,
+ -7,
+ -6,
+ -5,
+ -4,
+ -3,
+ -2,
+ -1,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ ];
+ for each_slice in test_data {
+ let encode_func = $encode_func;
+ let decode_func = $decode_func;
+ let end_encode_func = $end_encode_func;
+ let end_decode_func = $end_decode_func;
+
+ let cur_len = each_slice.len();
+ let effective_len = cur_len.min(16);
+
+ // encode...
+ let mut buffer = [uninit; 1024];
+ let mut encoder = create_encoder(&mut buffer);
+
+ encode_func(&mut encoder, each_slice);
+
+ let end = 1i32;
+ end_encode_func(&mut encoder, end);
+
+ // decode...
+ let buf = ReadBuf::new(buffer.as_slice());
+ let header = MessageHeaderDecoder::default().wrap(buf, 0);
+
+ let decoder = DemoDecoder::default().header(header, 0);
+ let decoded = decode_func(&decoder);
+ for each_idx in 0..effective_len {
+ assert_eq!(
+ each_slice[each_idx],
+ decoded[each_idx],
+ "Item mismatched at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ for each_idx in effective_len..16 {
+ assert_eq!(
+ decoded[each_idx],
+ 0,
+ "Item should be padded ZERO at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ let decoded_end = end_decode_func(&decoder);
+ assert_eq!(decoded_end, end, "End Item should equal",);
+ }
+ };
+ }
+
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i8_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_i8,
+ DemoEncoder::fixed_16_i8_end,
+ DemoDecoder::fixed_16_i8_end,
+ i8,
+ );
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i16_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_i16,
+ DemoEncoder::fixed_16_i16_end,
+ DemoDecoder::fixed_16_i16_end,
+ i16,
+ );
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i32_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_i32,
+ DemoEncoder::fixed_16_i32_end,
+ DemoDecoder::fixed_16_i32_end,
+ i32,
+ );
+ run_encode_then_decode_for_array_of_signed_len_16!(
+ DemoEncoder::fixed_16_i64_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_i64,
+ DemoEncoder::fixed_16_i64_end,
+ DemoDecoder::fixed_16_i64_end,
+ i64,
+ );
+}
+
+#[test]
+fn test_encode_then_decode_non_u8_unsigned_primitive_slice_padded() {
+ let uninit = 1u8;
+
+ //
+ //
+ //
+ macro_rules! run_encode_then_decode_for_array_of_unsigned_len_16 {
+ ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty) => {
+ let test_data = [
+ &[] as &[$i_type],
+ &[1 as $i_type] as &[$i_type],
+ &[0 as $i_type] as &[$i_type],
+ &[11 as $i_type] as &[$i_type],
+ &[11, 1 as $i_type] as &[$i_type],
+ &[11, 0, 1 as $i_type] as &[$i_type],
+ &[12, 11, 1, 2 as $i_type] as &[$i_type],
+ &[12, 11, 0, 1, 2 as $i_type] as &[$i_type],
+ &[13, 12, 11, 1, 2, 3 as $i_type] as &[$i_type],
+ &[13, 12, 11, 0, 1, 2, 3 as $i_type] as &[$i_type],
+ &[14, 13, 12, 11, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[14, 13, 12, 11, 0, 1, 2, 3, 4 as $i_type] as &[$i_type],
+ &[15, 14, 13, 12, 11, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type],
+ &[16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[16, 15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type],
+ &[17, 16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type],
+ &[
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7 as $i_type,
+ ] as &[$i_type],
+ &[
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8 as $i_type,
+ ] as &[$i_type],
+ &[
+ 19,
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ &[
+ 19,
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9 as $i_type,
+ ] as &[$i_type],
+ ];
+ for each_slice in test_data {
+ let encode_func = $encode_func;
+ let decode_func = $decode_func;
+ let end_encode_func = $end_encode_func;
+ let end_decode_func = $end_decode_func;
+
+ let cur_len = each_slice.len();
+ let effective_len = cur_len.min(16);
+
+ // encode...
+ let mut buffer = [uninit; 1024];
+ let mut encoder = create_encoder(&mut buffer);
+
+ encode_func(&mut encoder, each_slice);
+
+ let end = 1i32;
+ end_encode_func(&mut encoder, end);
+
+ // decode...
+ let buf = ReadBuf::new(buffer.as_slice());
+ let header = MessageHeaderDecoder::default().wrap(buf, 0);
+
+ let decoder = DemoDecoder::default().header(header, 0);
+ let decoded = decode_func(&decoder);
+ for each_idx in 0..effective_len {
+ assert_eq!(
+ each_slice[each_idx],
+ decoded[each_idx],
+ "Item mismatched at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ for each_idx in effective_len..16 {
+ assert_eq!(
+ decoded[each_idx],
+ 0,
+ "Item should be padded ZERO at {}/{} for {}",
+ each_idx,
+ cur_len,
+ stringify!($i_type)
+ );
+ }
+ let decoded_end = end_decode_func(&decoder);
+ assert_eq!(decoded_end, end, "End Item should equal",);
+ }
+ };
+ }
+
+ run_encode_then_decode_for_array_of_unsigned_len_16!(
+ DemoEncoder::fixed_16_u16_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_u16,
+ DemoEncoder::fixed_16_u16_end,
+ DemoDecoder::fixed_16_u16_end,
+ u16
+ );
+ run_encode_then_decode_for_array_of_unsigned_len_16!(
+ DemoEncoder::fixed_16_u32_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_u32,
+ DemoEncoder::fixed_16_u32_end,
+ DemoDecoder::fixed_16_u32_end,
+ u32
+ );
+ run_encode_then_decode_for_array_of_unsigned_len_16!(
+ DemoEncoder::fixed_16_u64_at_most_16_items_from_slice_padded_with_zero,
+ DemoDecoder::fixed_16_u64,
+ DemoEncoder::fixed_16_u64_end,
+ DemoDecoder::fixed_16_u64_end,
+ u64
+ );
+}
diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java
index f78899cb4b..2e4a4d5499 100644
--- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java
+++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java
@@ -373,48 +373,12 @@ private static void generatePrimitiveEncoder(
final int arrayLength = typeToken.arrayLength();
if (arrayLength > 1)
{
- indent(sb, level, "/// primitive array field '%s'\n", name);
- indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue());
- indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue());
- indent(sb, level, "/// - null value: %s\n", encoding.applicableNullValue());
- indent(sb, level, "/// - characterEncoding: %s\n", encoding.characterEncoding());
- indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType());
- indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset());
- indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength());
- indent(sb, level, "/// - version: %d\n", typeToken.version());
- indent(sb, level, "#[inline]\n");
- indent(sb, level, "pub fn %s(&mut self, value: &[%s; %d]) {\n",
- formatFunctionName(name),
- rustPrimitiveType,
- arrayLength);
-
- // NB: must create variable 'offset' before calling mutable self.get_buf_mut()
- indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken));
- indent(sb, level + 1, "let buf = self.get_buf_mut();\n");
-
- if (rustPrimitiveType.equals("u8"))
- {
- indent(sb, level + 1, "buf.put_bytes_at(offset, value);\n");
- indent(sb, level, "}\n\n");
- return;
- }
-
- for (int i = 0; i < arrayLength; i++)
- {
- if (i == 0)
- {
- indent(sb, level + 1, "buf.put_%s_at(offset, value[%d]);\n", rustPrimitiveType, i);
- }
- else
- {
- indent(sb, level + 1, "buf.put_%s_at(offset + %d, value[%d]);\n",
- rustPrimitiveType,
- i * primitiveType.size(),
- i);
- }
- }
-
- indent(sb, level, "}\n\n");
+ generatePrimitiveArrayEncoderWithRef(
+ sb, level, typeToken, name, encoding, primitiveType, rustPrimitiveType);
+ generatePrimitiveArrayEncoderWithSliceRef(
+ sb, level, typeToken, name, encoding, primitiveType, rustPrimitiveType, false);
+ generatePrimitiveArrayEncoderWithSliceRef(
+ sb, level, typeToken, name, encoding, primitiveType, rustPrimitiveType, true);
}
else
{
@@ -446,6 +410,275 @@ private static void generatePrimitiveEncoder(
}
}
+ private static void generatePrimitiveArrayEncoderWithRef(
+ final StringBuilder sb,
+ final int level,
+ final Token typeToken,
+ final String name,
+ final Encoding encoding,
+ final PrimitiveType primitiveType,
+ final String rustPrimitiveType) throws IOException
+ {
+ final int arrayLength = typeToken.arrayLength();
+ indent(sb, level, "/// primitive array field '%s'\n", name);
+ indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue());
+ indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue());
+ indent(sb, level, "/// - null value: %s\n", encoding.applicableNullValue());
+ indent(sb, level, "/// - characterEncoding: %s\n", encoding.characterEncoding());
+ indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType());
+ indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset());
+ indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength());
+ indent(sb, level, "/// - version: %d\n", typeToken.version());
+ indent(sb, level, "#[inline]\n");
+ indent(sb, level, "pub fn %s(&mut self, value: &[%s; %d]) {\n",
+ formatFunctionName(name), rustPrimitiveType, arrayLength);
+
+ // NB: must create variable 'offset' before calling mutable self.get_buf_mut()
+ indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken));
+ indent(sb, level + 1, "let buf = self.get_buf_mut();\n");
+
+ if (rustPrimitiveType.equals("u8"))
+ {
+ indent(sb, level + 1, "buf.put_bytes_at(offset, value);\n");
+ indent(sb, level, "}\n\n");
+ return;
+ }
+
+ for (int i = 0; i < arrayLength; i++)
+ {
+ if (i == 0)
+ {
+ indent(sb, level + 1, "buf.put_%s_at(offset, value[%d]);\n", rustPrimitiveType, i);
+ }
+ else
+ {
+ indent(sb, level + 1, "buf.put_%s_at(offset + %d, value[%d]);\n",
+ rustPrimitiveType, i * primitiveType.size(), i);
+ }
+ }
+
+ indent(sb, level, "}\n\n");
+ }
+
+ private static void generatePrimitiveArrayEncoderWithSliceRefMethodBodyForU8(
+ final StringBuilder sb,
+ final int level,
+ final Token typeToken,
+ final String name,
+ final String rustPrimitiveType,
+ final boolean withPadding) throws IOException
+ {
+ final int arrayLength = typeToken.arrayLength();
+
+ indent(sb, level + 1, "match len {\n");
+
+ // Handle case when slice len is greater than 0 and less than {@code arrayLength}
+ indent(sb, level + 2, "(1..%d) => {\n", arrayLength);
+ indent(sb, level + 3, "// Copy all items from 'value' into '%s' of [%s; %d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "buf.put_slice_at(offset, value);\n");
+ if (!withPadding)
+ {
+ indent(sb, level + 3, "// Leave all left items as is (no padding) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ }
+ else
+ {
+ indent(sb, level + 3, "// Pad all left items with ZERO(0%2$s) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "const ZEROS: [%1$s; %2$d] = [0%1$s; %2$d];\n", rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "buf.put_slice_at(offset + len, &ZEROS[len..]);\n");
+ }
+ indent(sb, level + 2, "}\n");
+
+ // Handle case when slice is empty
+ indent(sb, level + 2, "0 => {\n");
+ if (!withPadding)
+ {
+ indent(sb, level + 3, "// Leave all %3$d items as is (no padding) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ }
+ else
+ {
+ indent(sb, level + 3, "// Pad all %3$d items with ZERO(0%2$s) in '%s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "const ZEROS: [%1$s; %2$d] = [0%1$s; %2$d];\n", rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "buf.put_bytes_at(offset, &ZEROS);\n");
+ }
+ indent(sb, level + 2, "}\n");
+
+ // Handle case when slice len is equal to or greater than {@code arrayLength}
+ indent(sb, level + 2, "_ /* >= %d */ => {\n", arrayLength);
+ indent(sb, level + 3, "// Copy at most %3$d items from 'value' into '%s' of [%s; %d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "buf.put_slice_at(offset, &value[..%d]);\n", arrayLength);
+ indent(sb, level + 2, "}\n");
+
+ indent(sb, level + 1, "}\n");
+ }
+
+ private static void generatePrimitiveArrayEncoderWithSliceRefMethodBodyForNonU8(
+ final StringBuilder sb,
+ final int level,
+ final Token typeToken,
+ final String name,
+ final PrimitiveType primitiveType,
+ final String rustPrimitiveType,
+ final boolean withPadding) throws IOException
+ {
+ final int arrayLength = typeToken.arrayLength();
+
+ indent(sb, level + 1, "match len {\n");
+
+ // Handle case when slice len is greater than 1 and less than {@code arrayLength}
+ if (arrayLength > 2)
+ {
+ indent(sb, level + 2, "(2..%d) => {\n", arrayLength);
+ indent(sb, level + 3, "// Copy all items from 'value' into '%s' of [%s; %d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "for each_i in 0..len {\n");
+ indent(sb, level + 4, "buf.put_%s_at(offset + %d * each_i, value[each_i]);\n",
+ rustPrimitiveType, primitiveType.size());
+ indent(sb, level + 3, "}\n");
+ if (!withPadding)
+ {
+ indent(sb, level + 3, "// Leave all left items as is (no padding) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ }
+ else
+ {
+ indent(sb, level + 3, "// Pad all left items with ZERO(0%2$s) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "for each_i in len..%d {\n", arrayLength);
+ indent(sb, level + 4, "buf.put_%s_at(offset + %d * each_i, 0%1$s);\n",
+ rustPrimitiveType, primitiveType.size());
+ indent(sb, level + 3, "}\n");
+ }
+ indent(sb, level + 2, "}\n");
+ }
+
+ // Handle case when slice len is 1 (eliminate the need of loop)
+ indent(sb, level + 2, "1 => {\n");
+ indent(sb, level + 3, "// Copy first 1 items from 'value' into '%s' of [%s; %d]\n",
+ name, rustPrimitiveType, arrayLength);
+ indent(sb, level + 3, "buf.put_%s_at(offset, value[0]);\n", rustPrimitiveType);
+ if (!withPadding)
+ {
+ indent(sb, level + 3, "// Leave all left %4$d items as is (no padding) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength, arrayLength - 1);
+ }
+ else
+ {
+ indent(sb, level + 3, "// Pad all left %4$d items with ZERO(0%2$s) in '%s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength, arrayLength - 1);
+ for (int i = 1; i < arrayLength; i++)
+ {
+ indent(sb, level + 3, "buf.put_%s_at(offset + %d, 0%1$s);\n",
+ rustPrimitiveType, i * primitiveType.size());
+ }
+ }
+ indent(sb, level + 2, "}\n");
+
+ // Handle case when slice is empty
+ indent(sb, level + 2, "0 => {\n");
+ if (!withPadding)
+ {
+ indent(sb, level + 3, "// Leave all %3$d items as is (no padding) in '%1$s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ }
+ else
+ {
+ indent(sb, level + 3, "// Pad all %3$d items with ZERO(0%2$s) in '%s' of [%2$s; %3$d]\n",
+ name, rustPrimitiveType, arrayLength);
+ for (int i = 0; i < arrayLength; i++)
+ {
+ if (i == 0)
+ {
+ indent(sb, level + 3, "buf.put_%s_at(offset, 0%1$s);\n", rustPrimitiveType);
+ }
+ else
+ {
+ indent(sb, level + 3, "buf.put_%s_at(offset + %d, 0%1$s);\n",
+ rustPrimitiveType, i * primitiveType.size());
+ }
+ }
+ }
+ indent(sb, level + 2, "}\n");
+
+ // Handle case when slice len is equal to or greater than {@code arrayLength}
+ indent(sb, level + 2, "_ /* >= %d */ => {\n", arrayLength);
+ indent(sb, level + 3, "// Copy at most %3$d items from 'value' into '%s' of [%s; %d]\n",
+ name, rustPrimitiveType, arrayLength);
+ for (int i = 0; i < arrayLength; i++)
+ {
+ if (i == 0)
+ {
+ indent(sb, level + 3, "buf.put_%s_at(offset, value[%d]);\n", rustPrimitiveType, i);
+ }
+ else
+ {
+ indent(sb, level + 3, "buf.put_%s_at(offset + %d, value[%d]);\n",
+ rustPrimitiveType, i * primitiveType.size(), i);
+ }
+ }
+ indent(sb, level + 2, "}\n");
+
+ indent(sb, level + 1, "}\n");
+ }
+
+ private static void generatePrimitiveArrayEncoderWithSliceRef(
+ final StringBuilder sb,
+ final int level,
+ final Token typeToken,
+ final String name,
+ final Encoding encoding,
+ final PrimitiveType primitiveType,
+ final String rustPrimitiveType,
+ final boolean withPadding) throws IOException
+ {
+ final int arrayLength = typeToken.arrayLength();
+ indent(sb, level, "/// primitive array field '%s': copy at most %d items from slice %s padding ZEROs\n",
+ name, arrayLength, withPadding ? "with" : "without");
+ indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue());
+ indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue());
+ indent(sb, level, "/// - null value: %s\n", encoding.applicableNullValue());
+ indent(sb, level, "/// - characterEncoding: %s\n", encoding.characterEncoding());
+ indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType());
+ indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset());
+ indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength());
+ indent(sb, level, "/// - version: %d\n", typeToken.version());
+ indent(sb, level, "#[inline]\n");
+
+ if (!withPadding)
+ {
+ indent(sb, level, "pub fn %s_at_most_%d_items_from_slice(&mut self, value: &[%s]) {\n",
+ formatFunctionName(name), arrayLength, rustPrimitiveType);
+ }
+ else
+ {
+ indent(sb, level, "pub fn %s_at_most_%d_items_from_slice_padded_with_zero(&mut self, value: &[%s]) {\n",
+ formatFunctionName(name), arrayLength, rustPrimitiveType);
+ }
+
+ // NB: must create variable 'offset' before calling mutable self.get_buf_mut()
+ indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken));
+ indent(sb, level + 1, "let buf = self.get_buf_mut();\n");
+ indent(sb, level + 1, "let len = value.len();\n");
+
+ if (rustPrimitiveType.equals("u8"))
+ {
+ generatePrimitiveArrayEncoderWithSliceRefMethodBodyForU8(
+ sb, level, typeToken, name, rustPrimitiveType, withPadding);
+ }
+ else
+ {
+ generatePrimitiveArrayEncoderWithSliceRefMethodBodyForNonU8(
+ sb, level, typeToken, name, primitiveType, rustPrimitiveType, withPadding);
+ }
+
+ indent(sb, level, "}\n\n");
+ }
+
private static void generateEnumEncoder(
final StringBuilder sb,
final int level,
diff --git a/sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml b/sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml
new file mode 100644
index 0000000000..62f3b9a5b0
--- /dev/null
+++ b/sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+