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/baseline_enum_from_str.rs b/rust/tests/baseline_enum_from_str.rs index 4e52fd4bf9..a111d28364 100644 --- a/rust/tests/baseline_enum_from_str.rs +++ b/rust/tests/baseline_enum_from_str.rs @@ -1,21 +1,22 @@ +use BoostType::{NullVal, KERS, NITROUS, SUPERCHARGER, TURBO}; use examples_baseline::{ boost_type::BoostType, }; #[test] fn test_boost_type_from_str() -> Result<(), ()> { - assert_eq!("TURBO".parse::()?, BoostType::TURBO, "Parse \"TURBO\" as BoostType"); - assert_eq!("SUPERCHARGER".parse::()?, BoostType::SUPERCHARGER, "Parse \"SUPERCHARGER\" as BoostType"); - assert_eq!("NITROUS".parse::()?, BoostType::NITROUS, "Parse \"NITROUS\" as BoostType"); - assert_eq!("KERS".parse::()?, BoostType::KERS, "Parse \"KERS\" as BoostType"); + assert_eq!("TURBO".parse::()?, TURBO, "Parse \"TURBO\" as BoostType"); + assert_eq!("SUPERCHARGER".parse::()?, SUPERCHARGER, "Parse \"SUPERCHARGER\" as BoostType"); + assert_eq!("NITROUS".parse::()?, NITROUS, "Parse \"NITROUS\" as BoostType"); + assert_eq!("KERS".parse::()?, KERS, "Parse \"KERS\" as BoostType"); - assert_eq!("Turbo".parse::()?, BoostType::NullVal, "Parse \"Turbo\" as BoostType"); - assert_eq!("Supercharger".parse::()?, BoostType::NullVal, "Parse \"Supercharger\" as BoostType"); - assert_eq!("Nitrous".parse::()?, BoostType::NullVal, "Parse \"Nitrous\" as BoostType"); - assert_eq!("Kers".parse::()?, BoostType::NullVal, "Parse \"Kers\" as BoostType"); + assert_eq!("Turbo".parse::()?, NullVal, "Parse \"Turbo\" as BoostType"); + assert_eq!("Supercharger".parse::()?, NullVal, "Parse \"Supercharger\" as BoostType"); + assert_eq!("Nitrous".parse::()?, NullVal, "Parse \"Nitrous\" as BoostType"); + assert_eq!("Kers".parse::()?, NullVal, "Parse \"Kers\" as BoostType"); - assert_eq!("AA".parse::()?, BoostType::NullVal, "Parse \"AA\" as BoostType"); - assert_eq!("".parse::().unwrap(), BoostType::NullVal, "Parse \"\" as BoostType"); + assert_eq!("AA".parse::()?, NullVal, "Parse \"AA\" as BoostType"); + assert_eq!("".parse::().unwrap(), NullVal, "Parse \"\" as BoostType"); Ok(()) } diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index d7258bc39b..ab62a7715c 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -187,7 +187,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.available(BooleanType::T); car.code(Model::A); car.some_numbers(&[0, 1, 2, 3]); - car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef + car.vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -197,7 +197,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { let mut engine = car.engine_encoder(); engine.capacity(2000); engine.num_cylinders(4); - engine.manufacturer_code(&[49, 50, 51]); // 123 + engine.manufacturer_code(b"123"); engine.efficiency(35); engine.booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); diff --git a/rust/tests/fixed_sized_primitive_array.rs b/rust/tests/fixed_sized_primitive_array.rs new file mode 100644 index 0000000000..8542e3d488 --- /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.into_iter().copied()); + + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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.into_iter().copied()); + + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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.into_iter().copied()); + + 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_from_iter, + 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_from_iter, + 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_from_iter, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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_zero_padded, + 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/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index ae50c9bef7..39a5ed633c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -276,7 +276,14 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr indent(writer, 2, "dest.clone_from_slice(src);\n"); indent(writer, 2, "len\n"); indent(writer, 1, "}\n"); + indent(writer, 0, "}\n"); + // impl From for &[u8] + indent(writer, 0, "impl<%s> From<&%1$s mut %2$s<%1$s>> for &%1$s mut [u8] {\n", BUF_LIFETIME, WRITE_BUF_TYPE); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "fn from(buf: &%s mut %2$s<%1$s>) -> &%1$s mut [u8] {\n", BUF_LIFETIME, WRITE_BUF_TYPE); + indent(writer, 2, "buf.data\n"); + indent(writer, 1, "}\n"); indent(writer, 0, "}\n\n"); } } 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..d56c680d28 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 @@ -361,7 +361,62 @@ static void generateEncoderVarData( } } - private static void generatePrimitiveEncoder( + private static String rustNullLiteral(final Encoding encoding) + { + return generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue()); + } + + + private static void generateRustDoc( + final StringBuilder sb, + final int level, + final Token typeToken, + final Encoding encoding) throws IOException + { + 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", rustNullLiteral(encoding)); + 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()); + } + + private static void generatePrimitiveArrayFromIterEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final Encoding encoding = typeToken.encoding(); + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + + indent(sb, level, "/// primitive array field '%s' from an Iterator\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_from_iter(&mut self, iter: impl Iterator) {\n", + formatFunctionName(name), rustPrimitiveType); + + 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, "for (i, v) in iter.enumerate() {\n"); + + if (primitiveType.size() == 1) + { + indent(sb, level + 2, "buf.put_%s_at(offset + i, v);\n", rustPrimitiveType); + } + else + { + indent(sb, level + 2, "buf.put_%s_at(offset + i * %d, v);\n", + rustPrimitiveType, primitiveType.size()); + } + indent(sb, level + 1, "}\n"); + indent(sb, level, "}\n\n"); + } + + private static void generatePrimitiveArrayZeroPaddedEncoder( final StringBuilder sb, final int level, final Token typeToken, @@ -371,34 +426,66 @@ private static void generatePrimitiveEncoder( final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); final int arrayLength = typeToken.arrayLength(); - if (arrayLength > 1) + + indent(sb, level, "/// primitive array field '%s' with zero padding\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_zero_padded(&mut self, value: &[%s]) {\n", + formatFunctionName(name), rustPrimitiveType); + + indent(sb, level + 1, "let iter = value.iter().copied().chain(std::iter::repeat(0_%s)).take(%d);\n", + rustPrimitiveType, arrayLength); + + indent(sb, level + 1, "self.%s_from_iter(iter);\n", formatFunctionName(name)); + indent(sb, level, "}\n\n"); + } + + private static void generatePrimitiveArrayEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final Encoding encoding = typeToken.encoding(); + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + final int arrayLength = typeToken.arrayLength(); + + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_at(&mut self, index: usize, value: %s) {\n", + formatFunctionName(name), rustPrimitiveType); + indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); + indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); + + if (primitiveType.size() == 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); + indent(sb, level + 1, "buf.put_%s_at(offset + index, value);\n", rustPrimitiveType); + } + else + { + indent(sb, level + 1, "buf.put_%s_at(offset + index * %d, value);\n", + rustPrimitiveType, primitiveType.size()); + } + indent(sb, level, "}\n\n"); - // 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, "/// primitive array field '%s'\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s(&mut self, value: &[%s]) {\n", + formatFunctionName(name), rustPrimitiveType); - if (rustPrimitiveType.equals("u8")) - { - indent(sb, level + 1, "buf.put_bytes_at(offset, value);\n"); - indent(sb, level, "}\n\n"); - return; - } + // NB: must create variable 'offset' before calling mutable self.get_buf_mut() + indent(sb, level + 1, "debug_assert_eq!(%d, value.len());\n", arrayLength); + 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_slice_at(offset, value);\n"); + indent(sb, level, "}\n\n"); + } + else + { for (int i = 0; i < arrayLength; i++) { if (i == 0) @@ -416,34 +503,44 @@ private static void generatePrimitiveEncoder( indent(sb, level, "}\n\n"); } - else + + generatePrimitiveArrayFromIterEncoder(sb, level, typeToken, name); + generatePrimitiveArrayZeroPaddedEncoder(sb, level, typeToken, name); + } + + private static void generatePrimitiveEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final int arrayLength = typeToken.arrayLength(); + if (arrayLength > 1) { - if (encoding.presence() == Encoding.Presence.CONSTANT) - { - indent(sb, level, "// skipping CONSTANT %s\n\n", name); - } - else - { - indent(sb, level, "/// primitive 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) {\n", - formatFunctionName(name), - 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, "self.get_buf_mut().put_%s_at(offset, value);\n", rustPrimitiveType); - indent(sb, level, "}\n\n"); - } + generatePrimitiveArrayEncoder(sb, level, typeToken, name); + return; } + + final Encoding encoding = typeToken.encoding(); + if (encoding.presence() == Encoding.Presence.CONSTANT) + { + indent(sb, level, "// skipping CONSTANT %s\n\n", name); + return; + } + + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + + indent(sb, level, "/// primitive field '%s'\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", + formatFunctionName(name), 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, "self.get_buf_mut().put_%s_at(offset, value);\n", rustPrimitiveType); + indent(sb, level, "}\n\n"); } private static void generateEnumEncoder( @@ -679,7 +776,7 @@ private static void generatePrimitiveArrayDecoder( if (fieldToken.version() > 0) { indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); - indent(sb, level + 2, "return [%s; %d];\n", encoding.applicableNullValue(), arrayLength); + indent(sb, level + 2, "return [%s; %d];\n", rustNullLiteral(encoding), arrayLength); indent(sb, level + 1, "}\n\n"); } @@ -772,7 +869,7 @@ private static void generatePrimitiveOptionalDecoder( final String rustPrimitiveType = rustTypeName(primitiveType); final String characterEncoding = encoding.characterEncoding(); indent(sb, level, "/// primitive field - '%s' { null_value: '%s' }\n", - encoding.presence(), encoding.applicableNullValue()); + encoding.presence(), rustNullLiteral(encoding)); if (characterEncoding != null) { @@ -789,14 +886,14 @@ private static void generatePrimitiveOptionalDecoder( rustPrimitiveType, getBufOffset(fieldToken)); - final String literal = generateRustLiteral(primitiveType, encoding.applicableNullValue().toString()); - if (literal.endsWith("::NAN")) + final String nullLiteral = rustNullLiteral(encoding); + if (nullLiteral.endsWith("::NAN")) { indent(sb, level + 1, "if value.is_nan() {\n"); } else { - indent(sb, level + 1, "if value == %s {\n", literal); + indent(sb, level + 1, "if value == %s {\n", nullLiteral); } indent(sb, level + 2, "None\n"); @@ -833,8 +930,7 @@ private static void generatePrimitiveRequiredDecoder( if (fieldToken.version() > 0) { indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); - indent(sb, level + 2, "return %s;\n", - generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())); + indent(sb, level + 2, "return %s;\n", rustNullLiteral(encoding)); indent(sb, level + 1, "}\n\n"); } @@ -1257,8 +1353,7 @@ private static void generateEnum( // null value { final Encoding encoding = messageBody.get(0).encoding(); - final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), - encoding.applicableNullValue().toString()); + final CharSequence nullVal = rustNullLiteral(encoding); indent(writer, 1, "#[default]\n"); indent(writer, 1, "NullVal = %s, \n", nullVal); } @@ -1322,8 +1417,7 @@ private static void generateFromEnumForPrimitive( { final Encoding encoding = messageBody.get(0).encoding(); - final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), - encoding.applicableNullValue().toString()); + final CharSequence nullVal = rustNullLiteral(encoding); indent(writer, 3, "%s::NullVal => %s,\n", enumRustName, nullVal); } indent(writer, 2, "}\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 43b9c8ba8a..ae55de1e9e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -17,6 +17,7 @@ import org.agrona.Verify; import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.generation.Generators; import uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType; import uk.co.real_logic.sbe.ir.Encoding; @@ -65,6 +66,11 @@ static String rustTypeName(final PrimitiveType primitiveType) return TYPE_NAME_BY_PRIMITIVE_TYPE_MAP.get(primitiveType); } + static String generateRustLiteral(final PrimitiveType type, final PrimitiveValue value) + { + return generateRustLiteral(type, value.toString()); + } + static String generateRustLiteral(final PrimitiveType type, final String value) { Verify.notNull(type, "type"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index d6d7652b83..6092fb5d48 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -88,6 +88,7 @@ void generateRustLiteralsForUnsignedPrimitiveNulls() assertEquals("0xff_u8", generateRustLiteral(UINT8, UINT8.nullValue().toString())); assertEquals("0xffff_u16", generateRustLiteral(UINT16, UINT16.nullValue().toString())); assertEquals("0xffffffff_u32", generateRustLiteral(UINT32, UINT32.nullValue().toString())); + assertEquals("0xffffffffffffffff_u64", generateRustLiteral(UINT64, UINT64.nullValue())); assertEquals("0xffffffffffffffff_u64", generateRustLiteral(UINT64, UINT64.nullValue().toString())); } @@ -100,7 +101,7 @@ void generateRustLiteralNullPrimitiveTypeParam() @Test void generateRustLiteralNullValueParam() { - assertThrows(NullPointerException.class, () -> generateRustLiteral(INT8, null)); + assertThrows(NullPointerException.class, () -> generateRustLiteral(INT8, (String)null)); } @Test 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +