From 210a0464cc7b0f6d3201025b8092a862192d97dd Mon Sep 17 00:00:00 2001 From: Kwanho Lee Date: Wed, 6 Aug 2025 22:10:51 -0700 Subject: [PATCH] string_view --- src/source/CppMarshal.scala | 17 ++++-- src/source/Main.scala | 4 ++ src/source/generator.scala | 1 + test-suite/djinni/all.djinni | 1 + test-suite/djinni/string_view_test.djinni | 6 ++ .../cpp/test_interface_with_string.hpp | 19 ++++++ test-suite/generated-src/inFileList.txt | 1 + .../djinni/test/TestInterfaceWithString.java | 38 ++++++++++++ .../jni/NativeTestInterfaceWithString.cpp | 30 ++++++++++ .../jni/NativeTestInterfaceWithString.hpp | 32 ++++++++++ .../objc/DBTestInterfaceWithString+Private.h | 31 ++++++++++ .../objc/DBTestInterfaceWithString+Private.mm | 60 +++++++++++++++++++ .../objc/DBTestInterfaceWithString.h | 13 ++++ test-suite/generated-src/outFileList.txt | 9 +++ test-suite/generated-src/ts/test.ts | 6 ++ .../wasm/NativeTestInterfaceWithString.cpp | 33 ++++++++++ .../wasm/NativeTestInterfaceWithString.hpp | 30 ++++++++++ test_string_view.djinni | 17 ++++++ 18 files changed, 343 insertions(+), 5 deletions(-) create mode 100644 test-suite/djinni/string_view_test.djinni create mode 100644 test-suite/generated-src/cpp/test_interface_with_string.hpp create mode 100644 test-suite/generated-src/java/com/dropbox/djinni/test/TestInterfaceWithString.java create mode 100644 test-suite/generated-src/jni/NativeTestInterfaceWithString.cpp create mode 100644 test-suite/generated-src/jni/NativeTestInterfaceWithString.hpp create mode 100644 test-suite/generated-src/objc/DBTestInterfaceWithString+Private.h create mode 100644 test-suite/generated-src/objc/DBTestInterfaceWithString+Private.mm create mode 100644 test-suite/generated-src/objc/DBTestInterfaceWithString.h create mode 100644 test-suite/generated-src/wasm/NativeTestInterfaceWithString.cpp create mode 100644 test-suite/generated-src/wasm/NativeTestInterfaceWithString.hpp create mode 100644 test_string_view.djinni diff --git a/src/source/CppMarshal.scala b/src/source/CppMarshal.scala index d4876555..1fbc9fff 100644 --- a/src/source/CppMarshal.scala +++ b/src/source/CppMarshal.scala @@ -72,7 +72,9 @@ class CppMarshal(spec: Spec) extends Marshal(spec) { case "i8" | "i16" | "i32" | "i64" => List(ImportRef("")) case _ => List() } - case MString => List(ImportRef("")) + case MString => + val includes = List(ImportRef("")) + if (spec.cppUseStringView) ImportRef("") :: includes else includes case MDate => List(ImportRef("")) case MBinary => List(ImportRef(""), ImportRef("")) case MOptional => List(ImportRef(spec.cppOptionalHeader)) @@ -258,10 +260,15 @@ class CppMarshal(spec: Spec) extends Marshal(spec) { // this can be used in c++ generation to know whether a const& should be applied to the parameter or not private def toCppParamType(tm: MExpr, namespace: Option[String] = None, scopeSymbols: Seq[String] = Seq()): String = { - val cppType = toCppType(tm, namespace, scopeSymbols) - val refType = "const " + cppType + " &" - val valueType = cppType - if(byValue(tm)) valueType else refType + tm.base match { + case MString if spec.cppUseStringView => + if (spec.cppUseWideStrings) "std::wstring_view" else "std::string_view" + case _ => + val cppType = toCppType(tm, namespace, scopeSymbols) + val refType = "const " + cppType + " &" + val valueType = cppType + if(byValue(tm)) valueType else refType + } } private def moveOnly(tm: MExpr): Boolean = tm.base match { diff --git a/src/source/Main.scala b/src/source/Main.scala index 429d8710..29162e17 100644 --- a/src/source/Main.scala +++ b/src/source/Main.scala @@ -42,6 +42,7 @@ object Main { var cppNnCheckExpression: Option[String] = None var cppUseWideStrings: Boolean = false var cppLegacyRecords: Boolean = false + var cppUseStringView: Boolean = false var javaOutFolder: Option[File] = None var javaPackage: Option[String] = None var javaClassAccessModifier: JavaAccessModifier.Value = JavaAccessModifier.Public @@ -191,6 +192,8 @@ object Main { .text("Use wide strings in C++ code (default: false)") opt[Boolean]( "cpp-legacy-records").valueName("").foreach(x => cppLegacyRecords = x) .text("Use legacy record behavior for C++ code (default: false)") + opt[Boolean]( "cpp-use-string-view").valueName("").foreach(x => cppUseStringView = x) + .text("Use std::string_view for string parameters in C++ code (default: false)") note("") opt[File]("jni-out").valueName("").foreach(x => jniOutFolder = Some(x)) .text("The folder for the JNI C++ output files (Generator disabled if unspecified).") @@ -438,6 +441,7 @@ object Main { cppNnCheckExpression, cppUseWideStrings, cppLegacyRecords, + cppUseStringView, jniOutFolder, jniHeaderOutFolder, jniIncludePrefix, diff --git a/src/source/generator.scala b/src/source/generator.scala index e7b01dd4..90def292 100644 --- a/src/source/generator.scala +++ b/src/source/generator.scala @@ -60,6 +60,7 @@ package object generatorTools { cppNnCheckExpression: Option[String], cppUseWideStrings: Boolean, cppLegacyRecords: Boolean, + cppUseStringView: Boolean, jniOutFolder: Option[File], jniHeaderOutFolder: Option[File], jniIncludePrefix: String, diff --git a/test-suite/djinni/all.djinni b/test-suite/djinni/all.djinni index fec1d113..95900488 100644 --- a/test-suite/djinni/all.djinni +++ b/test-suite/djinni/all.djinni @@ -3,6 +3,7 @@ @import "enum_flags.djinni" @import "constant_enum.djinni" @import "data_ref_view.djinni" +@import "string_view_test.djinni" @import "vendor/third-party/date.djinni" @import "third-party/duration.djinni" diff --git a/test-suite/djinni/string_view_test.djinni b/test-suite/djinni/string_view_test.djinni new file mode 100644 index 00000000..8bd179a4 --- /dev/null +++ b/test-suite/djinni/string_view_test.djinni @@ -0,0 +1,6 @@ +# @flag "--cpp-use-string-view true" + +test_interface_with_string = interface +c { + # Method with string parameter to test string_view generation + process_string(message: string): string; +} diff --git a/test-suite/generated-src/cpp/test_interface_with_string.hpp b/test-suite/generated-src/cpp/test_interface_with_string.hpp new file mode 100644 index 00000000..65158c3d --- /dev/null +++ b/test-suite/generated-src/cpp/test_interface_with_string.hpp @@ -0,0 +1,19 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#pragma once + +#include + +namespace testsuite { + +/** @flag "--cpp-use-string-view true" */ +class TestInterfaceWithString { +public: + virtual ~TestInterfaceWithString() = default; + + /** Method with string parameter to test string_view generation */ + virtual std::string process_string(const std::string & message) = 0; +}; + +} // namespace testsuite diff --git a/test-suite/generated-src/inFileList.txt b/test-suite/generated-src/inFileList.txt index d3614d89..b00053f5 100644 --- a/test-suite/generated-src/inFileList.txt +++ b/test-suite/generated-src/inFileList.txt @@ -26,6 +26,7 @@ djinni/constant_enum.djinni djinni/data_ref_view.djinni ../support-lib/dataref.yaml ../support-lib/dataview.yaml +djinni/string_view_test.djinni djinni/vendor/third-party/date.djinni djinni/vendor/third-party/date.yaml djinni/vendor/third-party/duration.djinni diff --git a/test-suite/generated-src/java/com/dropbox/djinni/test/TestInterfaceWithString.java b/test-suite/generated-src/java/com/dropbox/djinni/test/TestInterfaceWithString.java new file mode 100644 index 00000000..22ffc758 --- /dev/null +++ b/test-suite/generated-src/java/com/dropbox/djinni/test/TestInterfaceWithString.java @@ -0,0 +1,38 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +package com.dropbox.djinni.test; + +import com.snapchat.djinni.NativeObjectManager; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +/** @flag "--cpp-use-string-view true" */ +public abstract class TestInterfaceWithString { + /** Method with string parameter to test string_view generation */ + @Nonnull + public abstract String processString(@Nonnull String message); + + public static final class CppProxy extends TestInterfaceWithString + { + private final long nativeRef; + private final AtomicBoolean destroyed = new AtomicBoolean(false); + + private CppProxy(long nativeRef) + { + if (nativeRef == 0) throw new RuntimeException("nativeRef is zero"); + this.nativeRef = nativeRef; + NativeObjectManager.register(this, nativeRef); + } + public static native void nativeDestroy(long nativeRef); + + @Override + public String processString(String message) + { + assert !this.destroyed.get() : "trying to use a destroyed object"; + return native_processString(this.nativeRef, message); + } + private native String native_processString(long _nativeRef, String message); + } +} diff --git a/test-suite/generated-src/jni/NativeTestInterfaceWithString.cpp b/test-suite/generated-src/jni/NativeTestInterfaceWithString.cpp new file mode 100644 index 00000000..fb6baa71 --- /dev/null +++ b/test-suite/generated-src/jni/NativeTestInterfaceWithString.cpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#include "NativeTestInterfaceWithString.hpp" // my header +#include "Marshal.hpp" + +namespace djinni_generated { + +NativeTestInterfaceWithString::NativeTestInterfaceWithString() : ::djinni::JniInterface<::testsuite::TestInterfaceWithString, NativeTestInterfaceWithString>("com/dropbox/djinni/test/TestInterfaceWithString$CppProxy") {} + +NativeTestInterfaceWithString::~NativeTestInterfaceWithString() = default; + + +CJNIEXPORT void JNICALL Java_com_dropbox_djinni_test_TestInterfaceWithString_00024CppProxy_nativeDestroy(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef) +{ + try { + delete reinterpret_cast<::djinni::CppProxyHandle<::testsuite::TestInterfaceWithString>*>(nativeRef); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, ) +} + +CJNIEXPORT jstring JNICALL Java_com_dropbox_djinni_test_TestInterfaceWithString_00024CppProxy_native_1processString(JNIEnv* jniEnv, jobject /*this*/, jlong nativeRef, jstring j_message) +{ + try { + const auto& ref = ::djinni::objectFromHandleAddress<::testsuite::TestInterfaceWithString>(nativeRef); + auto r = ref->process_string(::djinni::String::toCpp(jniEnv, j_message)); + return ::djinni::release(::djinni::String::fromCpp(jniEnv, r)); + } JNI_TRANSLATE_EXCEPTIONS_RETURN(jniEnv, 0 /* value doesn't matter */) +} + +} // namespace djinni_generated diff --git a/test-suite/generated-src/jni/NativeTestInterfaceWithString.hpp b/test-suite/generated-src/jni/NativeTestInterfaceWithString.hpp new file mode 100644 index 00000000..7e5b6ea4 --- /dev/null +++ b/test-suite/generated-src/jni/NativeTestInterfaceWithString.hpp @@ -0,0 +1,32 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#pragma once + +#include "djinni_support.hpp" +#include "test_interface_with_string.hpp" + +namespace djinni_generated { + +class NativeTestInterfaceWithString final : ::djinni::JniInterface<::testsuite::TestInterfaceWithString, NativeTestInterfaceWithString> { +public: + using CppType = std::shared_ptr<::testsuite::TestInterfaceWithString>; + using CppOptType = std::shared_ptr<::testsuite::TestInterfaceWithString>; + using JniType = jobject; + + using Boxed = NativeTestInterfaceWithString; + + ~NativeTestInterfaceWithString(); + + static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass::get()._fromJava(jniEnv, j); } + static ::djinni::LocalRef fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass::get()._toJava(jniEnv, c)}; } + static ::djinni::LocalRef fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); } + +private: + NativeTestInterfaceWithString(); + friend ::djinni::JniClass; + friend ::djinni::JniInterface<::testsuite::TestInterfaceWithString, NativeTestInterfaceWithString>; + +}; + +} // namespace djinni_generated diff --git a/test-suite/generated-src/objc/DBTestInterfaceWithString+Private.h b/test-suite/generated-src/objc/DBTestInterfaceWithString+Private.h new file mode 100644 index 00000000..f2a8ae1b --- /dev/null +++ b/test-suite/generated-src/objc/DBTestInterfaceWithString+Private.h @@ -0,0 +1,31 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#include "test_interface_with_string.hpp" +#include + +static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file"); + +@class DBTestInterfaceWithString; + +namespace djinni_generated { + +class TestInterfaceWithString +{ +public: + using CppType = std::shared_ptr<::testsuite::TestInterfaceWithString>; + using CppOptType = std::shared_ptr<::testsuite::TestInterfaceWithString>; + using ObjcType = DBTestInterfaceWithString*; + + using Boxed = TestInterfaceWithString; + + static CppType toCpp(ObjcType objc); + static ObjcType fromCppOpt(const CppOptType& cpp); + static ObjcType fromCpp(const CppType& cpp) { return fromCppOpt(cpp); } + +private: + class ObjcProxy; +}; + +} // namespace djinni_generated + diff --git a/test-suite/generated-src/objc/DBTestInterfaceWithString+Private.mm b/test-suite/generated-src/objc/DBTestInterfaceWithString+Private.mm new file mode 100644 index 00000000..91523a5b --- /dev/null +++ b/test-suite/generated-src/objc/DBTestInterfaceWithString+Private.mm @@ -0,0 +1,60 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#import "DBTestInterfaceWithString+Private.h" +#import "DBTestInterfaceWithString.h" +#import "DJICppWrapperCache+Private.h" +#import "DJIError.h" +#import "DJIMarshal+Private.h" +#include +#include +#include + +static_assert(__has_feature(objc_arc), "Djinni requires ARC to be enabled for this file"); + +@interface DBTestInterfaceWithString () + +- (id)initWithCpp:(const std::shared_ptr<::testsuite::TestInterfaceWithString>&)cppRef; + +@end + +@implementation DBTestInterfaceWithString { + ::djinni::CppProxyCache::Handle> _cppRefHandle; +} + +- (id)initWithCpp:(const std::shared_ptr<::testsuite::TestInterfaceWithString>&)cppRef +{ + if (self = [super init]) { + _cppRefHandle.assign(cppRef); + } + return self; +} + +- (nonnull NSString *)processString:(nonnull NSString *)message { + try { + auto objcpp_result_ = _cppRefHandle.get()->process_string(::djinni::String::toCpp(message)); + return ::djinni::String::fromCpp(objcpp_result_); + } DJINNI_TRANSLATE_EXCEPTIONS() +} + +namespace djinni_generated { + +auto TestInterfaceWithString::toCpp(ObjcType objc) -> CppType +{ + if (!objc) { + return nullptr; + } + return objc->_cppRefHandle.get(); +} + +auto TestInterfaceWithString::fromCppOpt(const CppOptType& cpp) -> ObjcType +{ + if (!cpp) { + return nil; + } + return ::djinni::get_cpp_proxy(cpp); +} + +} // namespace djinni_generated + +@end diff --git a/test-suite/generated-src/objc/DBTestInterfaceWithString.h b/test-suite/generated-src/objc/DBTestInterfaceWithString.h new file mode 100644 index 00000000..9c1c8441 --- /dev/null +++ b/test-suite/generated-src/objc/DBTestInterfaceWithString.h @@ -0,0 +1,13 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#import + + +/** @flag "--cpp-use-string-view true" */ +@interface DBTestInterfaceWithString : NSObject + +/** Method with string parameter to test string_view generation */ +- (nonnull NSString *)processString:(nonnull NSString *)message; + +@end diff --git a/test-suite/generated-src/outFileList.txt b/test-suite/generated-src/outFileList.txt index 555f56f8..f0c9d83f 100644 --- a/test-suite/generated-src/outFileList.txt +++ b/test-suite/generated-src/outFileList.txt @@ -10,6 +10,7 @@ djinni-output-temp/cpp/record_with_duration_and_derivings.cpp djinni-output-temp/cpp/date_record.hpp djinni-output-temp/cpp/date_record.cpp djinni-output-temp/cpp/map_date_record.hpp +djinni-output-temp/cpp/test_interface_with_string.hpp djinni-output-temp/cpp/DataRefTest.hpp djinni-output-temp/cpp/constant_enum.hpp djinni-output-temp/cpp/constant_with_enum.hpp @@ -81,6 +82,7 @@ djinni-output-temp/java/TestDuration.java djinni-output-temp/java/RecordWithDurationAndDerivings.java djinni-output-temp/java/DateRecord.java djinni-output-temp/java/MapDateRecord.java +djinni-output-temp/java/TestInterfaceWithString.java djinni-output-temp/java/DataRefTest.java djinni-output-temp/java/ConstantEnum.java djinni-output-temp/java/ConstantWithEnum.java @@ -150,6 +152,8 @@ djinni-output-temp/jni/NativeDateRecord.hpp djinni-output-temp/jni/NativeDateRecord.cpp djinni-output-temp/jni/NativeMapDateRecord.hpp djinni-output-temp/jni/NativeMapDateRecord.cpp +djinni-output-temp/jni/NativeTestInterfaceWithString.hpp +djinni-output-temp/jni/NativeTestInterfaceWithString.cpp djinni-output-temp/jni/NativeDataRefTest.hpp djinni-output-temp/jni/NativeDataRefTest.cpp djinni-output-temp/jni/NativeConstantEnum.hpp @@ -263,6 +267,7 @@ djinni-output-temp/objc/DBDateRecord.h djinni-output-temp/objc/DBDateRecord.mm djinni-output-temp/objc/DBMapDateRecord.h djinni-output-temp/objc/DBMapDateRecord.mm +djinni-output-temp/objc/DBTestInterfaceWithString.h djinni-output-temp/objc/DBDataRefTest.h djinni-output-temp/objc/DBConstantEnum.h djinni-output-temp/objc/DBConstantWithEnum.h @@ -355,6 +360,8 @@ djinni-output-temp/objc/DBDateRecord+Private.h djinni-output-temp/objc/DBDateRecord+Private.mm djinni-output-temp/objc/DBMapDateRecord+Private.h djinni-output-temp/objc/DBMapDateRecord+Private.mm +djinni-output-temp/objc/DBTestInterfaceWithString+Private.h +djinni-output-temp/objc/DBTestInterfaceWithString+Private.mm djinni-output-temp/objc/DBDataRefTest+Private.h djinni-output-temp/objc/DBDataRefTest+Private.mm djinni-output-temp/objc/DBConstantEnum+Private.h @@ -471,6 +478,8 @@ djinni-output-temp/wasm/NativeDateRecord.hpp djinni-output-temp/wasm/NativeDateRecord.cpp djinni-output-temp/wasm/NativeMapDateRecord.hpp djinni-output-temp/wasm/NativeMapDateRecord.cpp +djinni-output-temp/wasm/NativeTestInterfaceWithString.hpp +djinni-output-temp/wasm/NativeTestInterfaceWithString.cpp djinni-output-temp/wasm/NativeDataRefTest.hpp djinni-output-temp/wasm/NativeDataRefTest.cpp djinni-output-temp/wasm/NativeConstantEnum.hpp diff --git a/test-suite/generated-src/ts/test.ts b/test-suite/generated-src/ts/test.ts index b25df92d..fbb4d866 100644 --- a/test-suite/generated-src/ts/test.ts +++ b/test-suite/generated-src/ts/test.ts @@ -85,6 +85,12 @@ export interface /*record*/ MapDateRecord { datesById: Map; } +/** @flag "--cpp-use-string-view true" */ +export interface TestInterfaceWithString { + /** Method with string parameter to test string_view generation */ + processString(message: string): string; +} + export interface DataRefTest { sendData(data: Uint8Array): void; retriveAsBin(): Uint8Array; diff --git a/test-suite/generated-src/wasm/NativeTestInterfaceWithString.cpp b/test-suite/generated-src/wasm/NativeTestInterfaceWithString.cpp new file mode 100644 index 00000000..2a180dee --- /dev/null +++ b/test-suite/generated-src/wasm/NativeTestInterfaceWithString.cpp @@ -0,0 +1,33 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#include "NativeTestInterfaceWithString.hpp" // my header + +namespace djinni_generated { + +em::val NativeTestInterfaceWithString::cppProxyMethods() { + static const em::val methods = em::val::array(std::vector { + "processString", + }); + return methods; +} + +std::string NativeTestInterfaceWithString::process_string(const CppType& self, const std::string& w_message) { + try { + auto r = self->process_string(::djinni::String::toCpp(w_message)); + return ::djinni::String::fromCpp(r); + } + catch(const std::exception& e) { + return ::djinni::ExceptionHandlingTraits<::djinni::String>::handleNativeException(e); + } +} + +EMSCRIPTEN_BINDINGS(testsuite_test_interface_with_string) { + ::djinni::DjinniClass_<::testsuite::TestInterfaceWithString>("testsuite_TestInterfaceWithString", "testsuite.TestInterfaceWithString") + .smart_ptr>("testsuite_TestInterfaceWithString") + .function("nativeDestroy", &NativeTestInterfaceWithString::nativeDestroy) + .function("processString", NativeTestInterfaceWithString::process_string) + ; +} + +} // namespace djinni_generated diff --git a/test-suite/generated-src/wasm/NativeTestInterfaceWithString.hpp b/test-suite/generated-src/wasm/NativeTestInterfaceWithString.hpp new file mode 100644 index 00000000..3df2dc71 --- /dev/null +++ b/test-suite/generated-src/wasm/NativeTestInterfaceWithString.hpp @@ -0,0 +1,30 @@ +// AUTOGENERATED FILE - DO NOT MODIFY! +// This file was generated by Djinni from string_view_test.djinni + +#pragma once + +#include "djinni_wasm.hpp" +#include "test_interface_with_string.hpp" + +namespace djinni_generated { + +struct NativeTestInterfaceWithString : ::djinni::JsInterface<::testsuite::TestInterfaceWithString, NativeTestInterfaceWithString> { + using CppType = std::shared_ptr<::testsuite::TestInterfaceWithString>; + using CppOptType = std::shared_ptr<::testsuite::TestInterfaceWithString>; + using JsType = em::val; + using Boxed = NativeTestInterfaceWithString; + + static CppType toCpp(JsType j) { return _fromJs(j); } + static JsType fromCppOpt(const CppOptType& c) { return {_toJs(c)}; } + static JsType fromCpp(const CppType& c) { + ::djinni::checkForNull(c.get(), "NativeTestInterfaceWithString::fromCpp"); + return fromCppOpt(c); + } + + static em::val cppProxyMethods(); + + static std::string process_string(const CppType& self, const std::string& w_message); + +}; + +} // namespace djinni_generated diff --git a/test_string_view.djinni b/test_string_view.djinni new file mode 100644 index 00000000..2516c38a --- /dev/null +++ b/test_string_view.djinni @@ -0,0 +1,17 @@ +# Test interface for string_view functionality +test_interface = interface +c { + # Method with string parameter to test string_view generation + process_string(message: string): string; + + # Method with multiple string parameters + concatenate_strings(first: string, second: string): string; + + # Static method with string parameter + static validate_string(input: string): bool; +} + +# Record with string field (should still use std::string for fields) +test_record = record { + name: string; + description: string; +}