From ab3ecdd969872a62b6d46056dd01bcde81af3ff4 Mon Sep 17 00:00:00 2001 From: Robert Goss Date: Fri, 29 Sep 2023 00:59:47 +0100 Subject: [PATCH] Track memory across boundary add error API --- Source/buildimplementationrust.go | 144 +++++++++++++++++++++++++----- Source/languagerust.go | 6 +- Source/languagewriter.go | 99 ++++++++++---------- 3 files changed, 172 insertions(+), 77 deletions(-) diff --git a/Source/buildimplementationrust.go b/Source/buildimplementationrust.go index 4411272e..f5980f9c 100644 --- a/Source/buildimplementationrust.go +++ b/Source/buildimplementationrust.go @@ -278,15 +278,13 @@ func writeRustTrait(component ComponentDefinition, class ComponentDefinitionClas methods, GetLastErrorMessageMethod(), ClearErrorMessageMethod(), - RegisterErrorMessageMethod(), - IncRefCountMethod(), - DecRefCountMethod()) + RegisterErrorMessageMethod()) } for j := 0; j < len(methods); j++ { method := methods[j] w.Writeln("") - err := writeRustTraitFn(method, w, true, false, false) + err := writeRustTraitFn(method, w, true, false, false, nil) if err != nil { return err } @@ -298,7 +296,7 @@ func writeRustTrait(component ComponentDefinition, class ComponentDefinitionClas return nil } -func writeRustTraitFn(method ComponentDefinitionMethod, w LanguageWriter, hasSelf bool, hasImpl bool, hasImplParent bool) error { +func writeRustTraitFn(method ComponentDefinitionMethod, w LanguageWriter, hasSelf bool, hasImpl bool, hasImplParent bool, impl []string) error { methodName := toSnakeCase(method.MethodName) w.Writeln("// %s", methodName) w.Writeln("//") @@ -352,7 +350,13 @@ func writeRustTraitFn(method ComponentDefinitionMethod, w LanguageWriter, hasSel } w.AddIndentationLevel(1) if !hasImplParent { - w.Writeln("unimplemented!();") + if impl == nil { + w.Writeln("unimplemented!();") + } else { + for i := 0; i < len(impl); i++ { + w.Writeln(impl[i]) + } + } } else { w.Writeln("self.parent.%s(%s)", methodName, parameterNames) } @@ -371,7 +375,7 @@ func writeRustGlobalTrait(component ComponentDefinition, w LanguageWriter) error for j := 0; j < len(methods); j++ { method := methods[j] w.Writeln("") - err := writeRustTraitFn(method, w, false, false, false) + err := writeRustTraitFn(method, w, false, false, false, nil) if err != nil { return err } @@ -395,7 +399,7 @@ func buildRustGlobalStubFile(component ComponentDefinition, w LanguageWriter, In for j := 0; j < len(methods); j++ { method := methods[j] w.Writeln("") - err := writeRustTraitFn(method, w, false, true, false) + err := writeRustTraitFn(method, w, false, true, false, nil) if err != nil { return err } @@ -461,7 +465,11 @@ func buildRustStubFile(component ComponentDefinition, class ComponentDefinitionC w.Writeln("") w.Writeln("// Stub struct to implement the %s trait", Name) if len(parents) == 0 { - w.Writeln("pub struct C%s;", Name) + w.Writeln("pub struct C%s {", Name) + w.AddIndentationLevel(1) + w.Writeln("last_error : Option") + w.ResetIndentationLevel() + w.Writeln("}") } else { w.Writeln("pub struct C%s {", Name) w.AddIndentationLevel(1) @@ -485,14 +493,12 @@ func buildRustStubFile(component ComponentDefinition, class ComponentDefinitionC methods, GetLastErrorMessageMethod(), ClearErrorMessageMethod(), - RegisterErrorMessageMethod(), - IncRefCountMethod(), - DecRefCountMethod()) + RegisterErrorMessageMethod()) } for j := 0; j < len(methods); j++ { method := methods[j] w.Writeln("") - err := writeRustTraitFn(method, w, true, true, true) + err := writeRustTraitFn(method, w, true, true, true, nil) if err != nil { return err } @@ -507,18 +513,14 @@ func buildRustStubFile(component ComponentDefinition, class ComponentDefinitionC w.AddIndentationLevel(1) methods := class.Methods if component.isBaseClass(class) { - methods = append( - methods, - GetLastErrorMessageMethod(), - ClearErrorMessageMethod(), - RegisterErrorMessageMethod(), - IncRefCountMethod(), - DecRefCountMethod()) + writeRustStubGetLastErrorMessageMethod(class, w) + writeRustStubClearErrorMessageMethod(class, w) + writeRustStubRegisterErrorMessageMethod(class, w) } for j := 0; j < len(methods); j++ { method := methods[j] w.Writeln("") - err := writeRustTraitFn(method, w, true, true, false) + err := writeRustTraitFn(method, w, true, true, false, nil) if err != nil { return err } @@ -529,6 +531,31 @@ func buildRustStubFile(component ComponentDefinition, class ComponentDefinitionC return nil } +func writeRustStubGetLastErrorMessageMethod(base ComponentDefinitionClass, w LanguageWriter) { + method := GetLastErrorMessageMethod() + impl := []string{ + "match &self.last_error {", + " None => false,", + " Some(error_val) => {", + " *_error_message = error_val.clone();", + " true", + " }", + "}"} + writeRustTraitFn(method, w, true, true, false, impl) +} +func writeRustStubClearErrorMessageMethod(base ComponentDefinitionClass, w LanguageWriter) { + method := ClearErrorMessageMethod() + impl := []string{ + "self.last_error = None;"} + writeRustTraitFn(method, w, true, true, false, impl) +} +func writeRustStubRegisterErrorMessageMethod(base ComponentDefinitionClass, w LanguageWriter) { + method := RegisterErrorMessageMethod() + impl := []string{ + "self.last_error = Some(_error_message.to_string());"} + writeRustTraitFn(method, w, true, true, false, impl) +} + func buildRustWrapper(component ComponentDefinition, w LanguageWriter, InterfaceMod string) error { // Imports ModName := strings.ToLower(component.NameSpace) @@ -572,6 +599,8 @@ func buildRustHandle(component ComponentDefinition, w LanguageWriter, InterfaceM writeRustHandleAs(component, w, class, true) w.Writeln("") } + writeRustHandleIncRef(component, w) + writeRustHandleDecRef(component, w) w.AddIndentationLevel(-1) w.Writeln("}") return nil @@ -591,9 +620,9 @@ func writeRustHandleAs(component ComponentDefinition, w LanguageWriter, class Co for i := 0; i < len(children); i++ { child := children[i] if !mut { - w.Writeln("HandleImpl::T%s(ptr) => Some(ptr.as_ref()),", child) + w.Writeln("HandleImpl::T%s(_, ptr) => Some(ptr.as_ref()),", child) } else { - w.Writeln("HandleImpl::T%s(ptr) => Some(ptr.as_mut()),", child) + w.Writeln("HandleImpl::T%s(_, ptr) => Some(ptr.as_mut()),", child) } } w.Writeln("_ => None") @@ -604,11 +633,51 @@ func writeRustHandleAs(component ComponentDefinition, w LanguageWriter, class Co return nil } +func writeRustHandleIncRef(component ComponentDefinition, w LanguageWriter) error { + w.Writeln("pub fn inc_ref_count(&mut self) {") + w.AddIndentationLevel(1) + w.Writeln("match self {") + w.AddIndentationLevel(1) + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + w.Writeln("HandleImpl::T%s(count, _) => *count += 1,", class.ClassName) + } + w.AddIndentationLevel(-1) + w.Writeln("}") + w.AddIndentationLevel(-1) + w.Writeln("}") + return nil +} + +func writeRustHandleDecRef(component ComponentDefinition, w LanguageWriter) error { + w.Writeln("pub fn dec_ref_count(&mut self) -> bool {") + w.AddIndentationLevel(1) + w.Writeln("match self {") + w.AddIndentationLevel(1) + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + w.Writeln("HandleImpl::T%s(count, _) => {*count -= 1; *count == 0},", class.ClassName) + } + w.AddIndentationLevel(-1) + w.Writeln("}") + w.AddIndentationLevel(-1) + w.Writeln("}") + return nil +} + func writeGlobalRustWrapper(component ComponentDefinition, w LanguageWriter, cprefix string) error { errorprefix := strings.ToUpper(component.NameSpace) methods := component.Global.Methods for i := 0; i < len(methods); i++ { method := methods[i] + if method.MethodName == component.Global.AcquireMethod { + writeGlobalRustAquireWrapper(w, cprefix, errorprefix) + continue + } + if method.MethodName == component.Global.ReleaseMethod { + writeGlobalRustReleaseWrapper(w, cprefix, errorprefix) + continue + } err := writeRustMethodWrapper(method, nil, w, cprefix, errorprefix) if err != nil { return err @@ -618,6 +687,33 @@ func writeGlobalRustWrapper(component ComponentDefinition, w LanguageWriter, cpr return nil } +func writeGlobalRustAquireWrapper(w LanguageWriter, cprefix string, errorprefix string) { + w.Writeln("#[no_mangle]") + w.Writeln("fn %sacquireinstance(instance : BaseHandle) -> i32 {", cprefix) + w.AddIndentationLevel(1) + w.Writeln("if instance.is_null() { return %s_ERROR_INVALIDPARAM; }", errorprefix) + w.Writeln("let _handle_instance = unsafe {&mut *instance};") + w.Writeln("_handle_instance.inc_ref_count();") + w.Writeln("%s_SUCCESS", errorprefix) + w.AddIndentationLevel(-1) + w.Writeln("}") +} + +func writeGlobalRustReleaseWrapper(w LanguageWriter, cprefix string, errorprefix string) { + w.Writeln("#[no_mangle]") + w.Writeln("fn %sreleaseinstance(instance : BaseHandle) -> i32 {", cprefix) + w.AddIndentationLevel(1) + w.Writeln("if instance.is_null() { return %s_ERROR_INVALIDPARAM; }", errorprefix) + w.Writeln("let _handle_instance = unsafe {&mut *instance};") + w.Writeln("let free = _handle_instance.dec_ref_count();") + w.Writeln("if free {") + w.Writeln(" unsafe { let _ = Box::from_raw(instance); }") + w.Writeln("}") + w.Writeln("%s_SUCCESS", errorprefix) + w.AddIndentationLevel(-1) + w.Writeln("}") +} + func writeClassRustWrapper(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, cprefix string) error { errorprefix := strings.ToUpper(component.NameSpace) methods := class.Methods @@ -945,7 +1041,7 @@ func writeRustParameterConversionReturn(param ComponentDefinitionParam, w Langua HName := "_handle_" + IName RefName := "_ref_" + IName w.Writeln("if %s.is_null() { return %s_ERROR_INVALIDPARAM; }", IName, errorprefix) - w.Writeln("let %s = Box::new(HandleImpl::T%s(%s));", HName, param.ParamClass, RetName) + w.Writeln("let %s = Box::new(HandleImpl::T%s(1, %s));", HName, param.ParamClass, RetName) w.Writeln("let mut %s = unsafe{&mut *%s};", RefName, IName) w.Writeln("*%s = Box::into_raw(%s);", RefName, HName) case "bool": diff --git a/Source/languagerust.go b/Source/languagerust.go index 1c3dbefe..2c97d25c 100644 --- a/Source/languagerust.go +++ b/Source/languagerust.go @@ -99,9 +99,9 @@ func writeRustBaseTypeDefinitions(componentdefinition ComponentDefinition, w Lan for i := 0; i < len(componentdefinition.Classes); i++ { class := componentdefinition.Classes[i] if i != len(componentdefinition.Classes)-1 { - w.Writeln("T%s(Box),", class.ClassName, class.ClassName) + w.Writeln("T%s(u64, Box),", class.ClassName, class.ClassName) } else { - w.Writeln("T%s(Box)", class.ClassName, class.ClassName) + w.Writeln("T%s(u64, Box)", class.ClassName, class.ClassName) } } w.AddIndentationLevel(-1) @@ -424,7 +424,7 @@ func generateRustParameterType(param ComponentDefinitionParam, isPlain bool) (st } else { switch param.ParamPass { case "out": - RustParamTypeName = "&mut str" + RustParamTypeName = "&mut String" case "in": RustParamTypeName = "&str" case "return": diff --git a/Source/languagewriter.go b/Source/languagewriter.go index 4de9b5a3..2e586ae1 100644 --- a/Source/languagewriter.go +++ b/Source/languagewriter.go @@ -42,10 +42,10 @@ import ( // LanguageWriter is a wrapper around a io.Writer that handles indentation type LanguageWriter struct { - Indentation int + Indentation int IndentString string - Writer io.Writer - CurrentLine string + Writer io.Writer + CurrentLine string } func max(x, y int) int { @@ -56,100 +56,99 @@ func max(x, y int) int { } // AddIndentationLevel adds number of indentation the writers output -func (writer *LanguageWriter) AddIndentationLevel (levels int) (error) { - writer.Indentation = max(writer.Indentation + levels, 0) +func (writer *LanguageWriter) AddIndentationLevel(levels int) error { + writer.Indentation = max(writer.Indentation+levels, 0) return nil } // ResetIndentationLevel adds indentation to all output -func (writer *LanguageWriter) ResetIndentationLevel () (error) { +func (writer *LanguageWriter) ResetIndentationLevel() error { writer.Indentation = 0 return nil } // Writeln formats a string and writes it to a line. Pairs of leading spaces will be replaced by the indent IndentString. -func (writer *LanguageWriter) Writeln (format string, a ...interface{}) (int, error) { +func (writer *LanguageWriter) Writeln(format string, a ...interface{}) (int, error) { - leadingSpaces := 0; + leadingSpaces := 0 for _, rune := range format { if rune == ' ' { - leadingSpaces = leadingSpaces + 1; + leadingSpaces = leadingSpaces + 1 } else { - break; + break } } - leadingIndents := leadingSpaces / 2; - - indentedFormat := strings.Repeat (writer.IndentString, leadingIndents + writer.Indentation) + format[leadingIndents * 2:]; - return fmt.Fprintf (writer.Writer, indentedFormat + "\n", a...); + leadingIndents := leadingSpaces / 2 + + indentedFormat := strings.Repeat(writer.IndentString, leadingIndents+writer.Indentation) + format[leadingIndents*2:] + return fmt.Fprintf(writer.Writer, indentedFormat+"\n", a...) } // Writelns writes multiple lines and processes indentation -func (writer *LanguageWriter) Writelns (prefix string, lines []string) (error) { +func (writer *LanguageWriter) Writelns(prefix string, lines []string) error { for idx := 0; idx < len(lines); idx++ { - _, err := writer.Writeln (prefix + lines[idx]); + _, err := writer.Writeln(prefix + lines[idx]) if err != nil { - return err; + return err } } - - return nil; + + return nil } - + // BeginLine clears the CurrentLine buffer -func (writer *LanguageWriter) BeginLine () () { - writer.CurrentLine = ""; +func (writer *LanguageWriter) BeginLine() { + writer.CurrentLine = "" } // Printf formats a string and appends it to the CurrentLine buffer -func (writer *LanguageWriter) Printf (format string, a ...interface{}) () { - writer.CurrentLine = writer.CurrentLine + fmt.Sprintf (format, a...); +func (writer *LanguageWriter) Printf(format string, a ...interface{}) { + writer.CurrentLine = writer.CurrentLine + fmt.Sprintf(format, a...) } // EndLine flushes the CurrentBuffer to the internal writer -func (writer *LanguageWriter) EndLine () (int, error) { - return writer.Writeln (writer.CurrentLine); +func (writer *LanguageWriter) EndLine() (int, error) { + return writer.Writeln(writer.CurrentLine) } - // WriteCMakeLicenseHeader writes a license header into a writer with CMake-style comments -func (writer *LanguageWriter) WriteCMakeLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "#[[", "\n]]", ""); +func (writer *LanguageWriter) WriteCMakeLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "#[[", "\n]]", "") } // WriteCLicenseHeader writes a license header into a writer with C-style comments -func (writer *LanguageWriter) WriteCLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "/*", "*/", ""); +func (writer *LanguageWriter) WriteCLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "/*", "*/", "") } // WritePascalLicenseHeader writes a license header into a writer Pascal-style comments -func (writer *LanguageWriter) WritePascalLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "(*", "*)", ""); +func (writer *LanguageWriter) WritePascalLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "(*", "*)", "") } // WritePythonLicenseHeader writes a license header into a writer Python-style comments -func (writer *LanguageWriter) WritePythonLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "'''", "'''", ""); +func (writer *LanguageWriter) WritePythonLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "'''", "'''", "") } // WriteJavaLicenseHeader writes a license header into a writer Java-style comments -func (writer *LanguageWriter) WriteJavaLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "/*", "*/", ""); +func (writer *LanguageWriter) WriteJavaLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "/*", "*/", "") } // WriteTomlLicenseHeader writes a license header into a writer for TOML-style line prefix comments -func (writer *LanguageWriter) WriteTomlLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "", "", "//"); +func (writer *LanguageWriter) WriteTomlLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "", "", "# ") } // WritePlainLicenseHeader writes a license header into a writer without comments -func (writer *LanguageWriter) WritePlainLicenseHeader (component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (writer.Writer, component, abstract, includeVersion, "", "", ""); +func (writer *LanguageWriter) WritePlainLicenseHeader(component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(writer.Writer, component, abstract, includeVersion, "", "", "") } // WriteLicenseHeader writes a license header into a writer with C-style comments -func WriteLicenseHeader (w io.Writer, component ComponentDefinition, abstract string, includeVersion bool) { - writeLicenseHeaderEx (w, component, abstract, includeVersion, "/*", "*/", ""); +func WriteLicenseHeader(w io.Writer, component ComponentDefinition, abstract string, includeVersion bool) { + writeLicenseHeaderEx(w, component, abstract, includeVersion, "/*", "*/", "") } // writeLicenseHeaderEx writes a license header into a writer. @@ -188,16 +187,16 @@ func writeLicenseHeaderEx(w io.Writer, component ComponentDefinition, abstract s } // CreateLanguageFile creates a LanguageWriter and sets its indent string -func CreateLanguageFile (fileName string, indentString string) (LanguageWriter, error) { - var result LanguageWriter; - var err error; - +func CreateLanguageFile(fileName string, indentString string) (LanguageWriter, error) { + var result LanguageWriter + var err error + result.IndentString = indentString result.Indentation = 0 result.Writer, err = os.Create(fileName) if err != nil { - return result, err; + return result, err } - - return result, nil; + + return result, nil }