From e1261a94571cd021c79c719a798335f227a16c34 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Sun, 15 Feb 2026 13:13:12 -0600 Subject: [PATCH] [Rust] generated encoders now produce fluent interface --- rust/tests/baseline_test.rs | 85 +++++++++---------- rust/tests/big_endian_test.rs | 72 ++++++++-------- rust/tests/extension_test.rs | 80 +++++++++-------- .../sbe/generation/rust/RustGenerator.java | 24 ++++-- 4 files changed, 132 insertions(+), 129 deletions(-) diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index ab711b7c84..5ec352b7d0 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -181,24 +181,26 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(BooleanType::T); - car.code(Model::A); - car.some_numbers(&[1, 2, 3, 4]); - car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef - - extras.set_cruise_control(true); - extras.set_sports_pack(true); - extras.set_sun_roof(false); + car.serial_number(1234) + .model_year(2013) + .available(BooleanType::T) + .code(Model::A) + .some_numbers(&[1, 2, 3, 4]) + .vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef + + extras + .set_cruise_control(true) + .set_sports_pack(true) + .set_sun_roof(false); car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(&[49, 50, 51]); // 123 - engine.efficiency(35); - engine.booster_enabled(BooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(&[49, 50, 51]) // 123 + .efficiency(35) + .booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); booster.boost_type(BoostType::NITROUS); booster.horse_power(200); @@ -207,19 +209,22 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(30); - fuel_figures.mpg(35.9); - fuel_figures.usage_description(b"Urban Cycle"); + fuel_figures + .speed(30) + .mpg(35.9) + .usage_description(b"Urban Cycle"); assert_eq!(Some(1), fuel_figures.advance()?); - fuel_figures.speed(55); - fuel_figures.mpg(49.0); - fuel_figures.usage_description(b"Combined Cycle"); + fuel_figures + .speed(55) + .mpg(49.0) + .usage_description(b"Combined Cycle"); assert_eq!(Some(2), fuel_figures.advance()?); - fuel_figures.speed(75); - fuel_figures.mpg(40.0); - fuel_figures.usage_description(b"Highway Cycle"); + fuel_figures + .speed(75) + .mpg(40.0) + .usage_description(b"Highway Cycle"); car = fuel_figures.parent()?; performance_figures = car.performance_figures_encoder(2, performance_figures); @@ -228,16 +233,13 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(4.0); + acceleration.mph(30).seconds(4.0); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.5); + acceleration.mph(60).seconds(7.5); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(12.2); + acceleration.mph(100).seconds(12.2); performance_figures = acceleration.parent()?; assert_eq!(Some(1), performance_figures.advance()?); @@ -245,23 +247,20 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(3.8); + acceleration.mph(30).seconds(3.8); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.1); + acceleration.mph(60).seconds(7.1); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(11.8); + acceleration.mph(100).seconds(11.8); performance_figures = acceleration.parent()?; car = performance_figures.parent()?; - car.manufacturer("Honda"); - car.model("Civic VTi"); - car.activation_code(b"abcdef"); + car.manufacturer("Honda") + .model("Civic VTi") + .activation_code(b"abcdef"); let limit = car.get_limit(); Ok((limit, buffer)) @@ -269,7 +268,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { #[test] fn test_issue_1018() { - assert_eq!(1, examples_baseline::SBE_SCHEMA_ID); - assert_eq!(0, examples_baseline::SBE_SCHEMA_VERSION); - assert_eq!("5.2", examples_baseline::SBE_SEMANTIC_VERSION); -} \ No newline at end of file + assert_eq!(1, SBE_SCHEMA_ID); + assert_eq!(0, SBE_SCHEMA_VERSION); + assert_eq!("5.2", SBE_SEMANTIC_VERSION); +} diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index 1bef7278dd..693907b459 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -177,12 +177,12 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(BooleanType::T); - car.code(Model::A); - car.some_numbers(&[0, 1, 2, 3, 4]); - car.vehicle_code(b"abcdef"); + car.serial_number(1234) + .model_year(2013) + .available(BooleanType::T) + .code(Model::A) + .some_numbers(&[0, 1, 2, 3, 4]) + .vehicle_code(b"abcdef"); extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -190,32 +190,36 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(b"123"); - engine.efficiency(35); - engine.booster_enabled(BooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(b"123") + .efficiency(35) + .booster_enabled(BooleanType::T); + let mut booster = engine.booster_encoder(); - booster.boost_type(BoostType::NITROUS); - booster.horse_power(200); + booster.boost_type(BoostType::NITROUS).horse_power(200); engine = booster.parent()?; car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(30); - fuel_figures.mpg(35.9); - fuel_figures.usage_description("Urban Cycle"); + fuel_figures + .speed(30) + .mpg(35.9) + .usage_description("Urban Cycle"); assert_eq!(Some(1), fuel_figures.advance()?); - fuel_figures.speed(55); - fuel_figures.mpg(49.0); - fuel_figures.usage_description("Combined Cycle"); + fuel_figures + .speed(55) + .mpg(49.0) + .usage_description("Combined Cycle"); assert_eq!(Some(2), fuel_figures.advance()?); - fuel_figures.speed(75); - fuel_figures.mpg(40.0); - fuel_figures.usage_description("Highway Cycle"); + fuel_figures + .speed(75) + .mpg(40.0) + .usage_description("Highway Cycle"); car = fuel_figures.parent()?; performance_figures = car.performance_figures_encoder(2, performance_figures); @@ -224,16 +228,13 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(4.0); + acceleration.mph(30).seconds(4.0); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.5); + acceleration.mph(60).seconds(7.5); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(12.2); + acceleration.mph(100).seconds(12.2); performance_figures = acceleration.parent()?; assert_eq!(Some(1), performance_figures.advance()?); @@ -241,23 +242,20 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(3.8); + acceleration.mph(30).seconds(3.8); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.1); + acceleration.mph(60).seconds(7.1); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(11.8); + acceleration.mph(100).seconds(11.8); performance_figures = acceleration.parent()?; car = performance_figures.parent()?; - car.manufacturer("Honda"); - car.model("Civic VTi"); - car.activation_code("abcdef"); + car.manufacturer("Honda") + .model("Civic VTi") + .activation_code("abcdef"); let limit = car.get_limit(); Ok((limit, buffer)) diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index ab62a7715c..665d8f92b4 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -182,45 +182,49 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(BooleanType::T); - car.code(Model::A); - car.some_numbers(&[0, 1, 2, 3]); - car.vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef - - extras.set_cruise_control(true); - extras.set_sports_pack(true); - extras.set_sun_roof(false); + car.serial_number(1234) + .model_year(2013) + .available(BooleanType::T) + .code(Model::A) + .some_numbers(&[0, 1, 2, 3]) + .vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef + + extras + .set_cruise_control(true) + .set_sports_pack(true) + .set_sun_roof(false); car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(b"123"); - engine.efficiency(35); - engine.booster_enabled(BooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(b"123") + .efficiency(35) + .booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); - booster.boost_type(BoostType::NITROUS); - booster.horse_power(200); + booster.boost_type(BoostType::NITROUS).horse_power(200); engine = booster.parent()?; car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(30); - fuel_figures.mpg(35.9); - fuel_figures.usage_description(b"Urban Cycle"); + fuel_figures + .speed(30) + .mpg(35.9) + .usage_description(b"Urban Cycle"); assert_eq!(Some(1), fuel_figures.advance()?); - fuel_figures.speed(55); - fuel_figures.mpg(49.0); - fuel_figures.usage_description(b"Combined Cycle"); + fuel_figures + .speed(55) + .mpg(49.0) + .usage_description(b"Combined Cycle"); assert_eq!(Some(2), fuel_figures.advance()?); - fuel_figures.speed(75); - fuel_figures.mpg(40.0); - fuel_figures.usage_description(b"Highway Cycle"); + fuel_figures + .speed(75) + .mpg(40.0) + .usage_description(b"Highway Cycle"); car = fuel_figures.parent()?; performance_figures = car.performance_figures_encoder(2, performance_figures); @@ -229,16 +233,13 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(4.0); + acceleration.mph(30).seconds(4.0); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.5); + acceleration.mph(60).seconds(7.5); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(12.2); + acceleration.mph(100).seconds(12.2); performance_figures = acceleration.parent()?; assert_eq!(Some(1), performance_figures.advance()?); @@ -246,23 +247,20 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(3.8); + acceleration.mph(30).seconds(3.8); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.1); + acceleration.mph(60).seconds(7.1); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(11.8); + acceleration.mph(100).seconds(11.8); performance_figures = acceleration.parent()?; car = performance_figures.parent()?; - car.manufacturer("Honda"); - car.model("Civic VTi"); - car.activation_code(b"abcdef"); + car.manufacturer("Honda") + .model("Civic VTi") + .activation_code(b"abcdef"); let limit = car.get_limit(); Ok((limit, buffer)) 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 746f18d022..49f78c390e 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 @@ -353,7 +353,7 @@ static void generateEncoderVarData( // function to write slice ... todo - handle character encoding ? indent(sb, level, "/// VAR_DATA ENCODER - character encoding: '%s'\n", characterEncoding); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", propertyName, varDataType); + indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", propertyName, varDataType); indent(sb, level + 1, "let limit = self.get_limit();\n"); indent(sb, level + 1, "let data_length = value.len();\n"); @@ -367,6 +367,7 @@ static void generateEncoderVarData( lengthType.size(), toBytesFn); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); i += varDataToken.componentTokenCount(); @@ -408,7 +409,7 @@ private static void generatePrimitiveArrayFromIterEncoder( 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", + indent(sb, level, "pub fn %s_from_iter(&mut self, iter: impl Iterator) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); @@ -425,6 +426,7 @@ private static void generatePrimitiveArrayFromIterEncoder( rustPrimitiveType, primitiveType.size()); } indent(sb, level + 1, "}\n"); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -442,13 +444,14 @@ private static void generatePrimitiveArrayZeroPaddedEncoder( 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", + indent(sb, level, "pub fn %s_zero_padded(&mut self, value: &[%s]) -> &mut Self {\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 + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -464,7 +467,7 @@ private static void generatePrimitiveArrayEncoder( final int arrayLength = typeToken.arrayLength(); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_at(&mut self, index: usize, value: %s) {\n", + indent(sb, level, "pub fn %s_at(&mut self, index: usize, value: %s) -> &mut Self {\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"); @@ -478,12 +481,13 @@ private static void generatePrimitiveArrayEncoder( indent(sb, level + 1, "buf.put_%s_at(offset + index * %d, value);\n", rustPrimitiveType, primitiveType.size()); } + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\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", + indent(sb, level, "pub fn %s(&mut self, value: &[%s]) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); // NB: must create variable 'offset' before calling mutable self.get_buf_mut() @@ -494,6 +498,7 @@ private static void generatePrimitiveArrayEncoder( if (rustPrimitiveType.equals("u8")) { indent(sb, level + 1, "buf.put_slice_at(offset, value);\n"); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } else @@ -513,6 +518,7 @@ private static void generatePrimitiveArrayEncoder( } } + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -546,12 +552,13 @@ private static void generatePrimitiveEncoder( 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", + indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\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 + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -578,11 +585,12 @@ private static void generateEnumEncoder( indent(sb, level, "/// REQUIRED enum\n"); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", formatFunctionName(name), enumType); + indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", formatFunctionName(name), enumType); // 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 as %1$s)\n", rustPrimitiveType); + indent(sb, level + 1, "self.get_buf_mut().put_%s_at(offset, value as %1$s);\n", rustPrimitiveType); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } }