From b801471a3555e81f59e60d34707cb0fd9b0864d8 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 18 Jul 2026 11:08:35 +0100 Subject: Support String values in rust-transient-0 --- .../output/rust/src/gen/transient_0.rs | 13 ++- examples/10-transient-0/output/rust/src/lib.rs | 13 ++- .../rusttransient0/RustTransient0Generator.java | 111 ++++++++++++++++++++- 3 files changed, 131 insertions(+), 6 deletions(-) diff --git a/examples/10-transient-0/output/rust/src/gen/transient_0.rs b/examples/10-transient-0/output/rust/src/gen/transient_0.rs index 68aa0eb..24f5c9c 100644 --- a/examples/10-transient-0/output/rust/src/gen/transient_0.rs +++ b/examples/10-transient-0/output/rust/src/gen/transient_0.rs @@ -54,10 +54,19 @@ pub fn decode_int_64(reader: &mut impl std::io::Read) -> ::std::io::Result::<::c } pub fn encode_string(value: &::std::string::String, writer: &mut impl std::io::Write) -> ::std::io::Result::<()> { - todo!(); + { + crate::transient_0::encode_int_64(&((value.len()).try_into()).unwrap(), writer)?; + }; + writer.write_all(value.as_bytes())?; ::std::io::Result::Ok(()) } pub fn decode_string(reader: &mut impl std::io::Read) -> ::std::io::Result::<::std::string::String> { - std::io::Result::Ok(todo!()) + let len = crate::transient_0::decode_int_64(reader)?; + let bytes = { + let mut bytes = vec![0u8; (len.try_into()).unwrap()]; + reader.read_exact(&mut bytes)?; + bytes + }; + std::io::Result::Ok((::std::string::String::from_utf8(bytes)).unwrap()) } diff --git a/examples/10-transient-0/output/rust/src/lib.rs b/examples/10-transient-0/output/rust/src/lib.rs index 75a7b47..6ecb19e 100644 --- a/examples/10-transient-0/output/rust/src/lib.rs +++ b/examples/10-transient-0/output/rust/src/lib.rs @@ -4,7 +4,7 @@ pub mod transient_0; #[cfg(test)] mod test { use std::io::Cursor; - use super::data::{InnerStruct, OuterStruct, StructWithBool, StructWithInt32, StructWithInt64}; + use super::data::{InnerStruct, OuterStruct, StructWithBool, StructWithInt32, StructWithInt64, StructWithString}; #[test] fn struct_with_bool() { @@ -39,6 +39,17 @@ mod test { ); } + #[test] + fn struct_with_string() { + let value = StructWithString { a: "abc".to_string(), b: "def".to_string() }; + + assert_round_trip_encoding( + value, + super::data::transient_0::encode_struct_with_string, + super::data::transient_0::decode_struct_with_string, + ); + } + #[test] fn nested_struct() { let value = OuterStruct { inner: InnerStruct { a: 10, b: 25 }, c: 42 }; diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java index 5639ca2..f5e1f25 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java @@ -215,17 +215,68 @@ public class RustTransient0Generator implements Generator { return generateEncodeFunction( NativeTypes.STRING, List.of( - new RustExpressionStatement(generateTodo()) + new RustExpressionStatement(new RustBlockExpression( + generateEncode( + new RustPrefixExpression( + RustPrefixOperator.BORROW, + methodCall( + methodCall( + methodCall( + RustPath.of(VALUE_NAME), + RustIdentifier.of("len"), + List.of() + ), + RustIdentifier.of("try_into"), + List.of() + ), + // TODO: remove unwrap + RustIdentifier.of("unwrap"), + List.of() + ) + ), + NativeTypes.INT_64 + ), + Optional.empty() + )), + new RustExpressionStatement(generateWriterWrite( + methodCall( + RustPath.of(VALUE_NAME), + RustIdentifier.of("as_bytes"), + List.of() + ) + )) ) ); } private RustItem generateDecodeStringFunction() { + var len = RustIdentifier.of("len"); + var bytes = RustIdentifier.of("bytes"); + return generateDecodeFunction( NativeTypes.STRING, new RustBlockExpression( - List.of(), - Optional.of(generateTodo()) + List.of( + new RustLetStatement( + len, + false, + generateDecode(NativeTypes.INT_64) + ), + new RustLetStatement( + bytes, + false, + generateReaderReadExact(RustPath.of(len)) + ) + ), + Optional.of(methodCall( + new RustCallExpression( + RustPath.global("std", "string", "String", "from_utf8"), + List.of(RustPath.of(bytes)) + ), + // TODO: remove unwrap + RustIdentifier.of("unwrap"), + List.of() + )) ) ); } @@ -494,6 +545,46 @@ public class RustTransient0Generator implements Generator { ); } + private RustExpression generateReaderReadExact(RustExpression length) { + var bytes = RustIdentifier.of("bytes"); + + // TODO: extract into let + var lengthUsize = methodCall( + methodCall( + length, + RustIdentifier.of("try_into"), + List.of() + ), + // TODO: remove unwrap + RustIdentifier.of("unwrap"), + List.of() + ); + + return new RustBlockExpression( + List.of( + new RustLetStatement( + bytes, + true, + // TODO: use uninit + new RustVecRepeatExpression(new RustIntegerLiteral(0, Optional.of(RustIdentifier.of("u8"))), lengthUsize) + ), + new RustExpressionStatement(new RustTryPropagationExpression(new RustCallExpression( + new RustFieldExpression( + RustPath.of(READER_NAME), + RustIdentifier.of("read_exact") + ), + List.of( + new RustPrefixExpression( + RustPrefixOperator.BORROW_MUTABLE, + RustPath.of(bytes) + ) + ) + ))) + ), + Optional.of(RustPath.of(bytes)) + ); + } + private RustExpression generateTodo() { return new RustCallExpression( RustPath.of("todo!"), @@ -508,4 +599,18 @@ public class RustTransient0Generator implements Generator { private RustIdentifier decodeMethodName(Type type) { return this.rustGenerator.generateFieldName("decode" + type.name()); } + + private RustExpression methodCall( + RustExpression receiver, + RustIdentifier methodName, + List args + ) { + return new RustCallExpression( + new RustFieldExpression( + receiver, + methodName + ), + args + ); + } } -- cgit v1.2.3