Skip to content

Commit e119e13

Browse files
committed
Basic conversion of parameters for global wrappers
1 parent 0ac7f75 commit e119e13

File tree

2 files changed

+264
-29
lines changed

2 files changed

+264
-29
lines changed

Source/buildimplementationrust.go

Lines changed: 192 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,38 @@ func BuildImplementationRust(component ComponentDefinition, outputFolder string,
7676
return err
7777
}
7878

79+
IntfWrapperFileName := BaseName + "_interface_wrapper.rs"
80+
IntfWrapperFilePath := path.Join(outputFolder, IntfWrapperFileName)
81+
modfiles = append(modfiles, IntfWrapperFilePath)
82+
log.Printf("Creating \"%s\"", IntfWrapperFilePath)
83+
IntfWrapperRSFile, err := CreateLanguageFile(IntfWrapperFilePath, indentString)
84+
if err != nil {
85+
return err
86+
}
87+
IntfWrapperRSFile.WriteCLicenseHeader(component,
88+
fmt.Sprintf("This is an autogenerated Rust implementation file in order to allow easy\ndevelopment of %s. The functions in this file need to be implemented. It needs to be generated only once.", LibraryName),
89+
true)
90+
err = buildRustWrapper(component, IntfWrapperRSFile, InterfaceMod)
91+
if err != nil {
92+
return err
93+
}
94+
95+
IntfHandleFileName := BaseName + "_interface_handle.rs"
96+
IntfHandleFilePath := path.Join(outputFolder, IntfHandleFileName)
97+
modfiles = append(modfiles, IntfHandleFilePath)
98+
log.Printf("Creating \"%s\"", IntfHandleFilePath)
99+
IntfHandleRSFile, err := CreateLanguageFile(IntfHandleFilePath, indentString)
100+
if err != nil {
101+
return err
102+
}
103+
IntfHandleRSFile.WriteCLicenseHeader(component,
104+
fmt.Sprintf("This is an autogenerated Rust implementation file in order to allow easy\ndevelopment of %s. The functions in this file need to be implemented. It needs to be generated only once.", LibraryName),
105+
true)
106+
err = buildRustHandle(component, IntfHandleRSFile, InterfaceMod)
107+
if err != nil {
108+
return err
109+
}
110+
79111
IntfWrapperStubName := path.Join(stubOutputFolder, BaseName+stubIdentifier+".rs")
80112
modfiles = append(modfiles, IntfWrapperStubName)
81113
if forceRebuild || !FileExists(IntfWrapperStubName) {
@@ -344,7 +376,7 @@ func buildRustGlobalStubFile(component ComponentDefinition, w LanguageWriter, In
344376
w.Writeln("use %s::*;", InterfaceMod)
345377
w.Writeln("")
346378
w.Writeln("// Wrapper struct to implement the wrapper trait for global methods")
347-
w.Writeln("struct CWrapper;")
379+
w.Writeln("pub struct CWrapper;")
348380
w.Writeln("")
349381
w.Writeln("impl Wrapper for CWrapper {")
350382
w.Writeln("")
@@ -474,3 +506,162 @@ func buildRustStubFile(component ComponentDefinition, class ComponentDefinitionC
474506
w.Writeln("")
475507
return nil
476508
}
509+
510+
func buildRustWrapper(component ComponentDefinition, w LanguageWriter, InterfaceMod string) error {
511+
// Imports
512+
ModName := strings.ToLower(component.NameSpace)
513+
w.Writeln("")
514+
w.Writeln("// Calls from the C-Interface to the Rust traits via the CWrapper")
515+
w.Writeln("// These are the symbols exposed in the shared object interface")
516+
w.Writeln("")
517+
w.Writeln("use %s::*;", InterfaceMod)
518+
w.Writeln("use %s::CWrapper;", ModName)
519+
w.Writeln("use std::ffi::{c_char, CStr};")
520+
w.Writeln("")
521+
cprefix := ModName + "_"
522+
// Build the global methods
523+
err := writeGlobalRustWrapper(component, w, cprefix)
524+
if err != nil {
525+
return err
526+
}
527+
return nil
528+
}
529+
530+
func buildRustHandle(component ComponentDefinition, w LanguageWriter, InterfaceMod string) error {
531+
w.Writeln("")
532+
w.Writeln("// Handle passed through interface define the casting maps needed to extract")
533+
w.Writeln("")
534+
w.Writeln("use %s::*;", InterfaceMod)
535+
w.Writeln("")
536+
w.Writeln("impl HandleImpl {")
537+
w.AddIndentationLevel(1)
538+
for i := 0; i < len(component.Classes); i++ {
539+
class := component.Classes[i]
540+
writeRustHandleAs(component, w, class, false)
541+
writeRustHandleAs(component, w, class, true)
542+
w.Writeln("")
543+
}
544+
w.AddIndentationLevel(-1)
545+
w.Writeln("}")
546+
return nil
547+
}
548+
549+
func writeRustHandleAs(component ComponentDefinition, w LanguageWriter, class ComponentDefinitionClass, mut bool) error {
550+
//parents, err := getParentList(component, class)
551+
//if err != nil {
552+
// return err
553+
//}
554+
Name := class.ClassName
555+
if !mut {
556+
w.Writeln("pub fn as_%s(&self) -> Option<&dyn %s> {", toSnakeCase(Name), Name)
557+
} else {
558+
w.Writeln("pub fn as_mut_%s(&mut self) -> Option<&mut dyn %s> {", toSnakeCase(Name), Name)
559+
}
560+
w.AddIndentationLevel(1)
561+
w.Writeln("None")
562+
w.AddIndentationLevel(-1)
563+
w.Writeln("}")
564+
return nil
565+
}
566+
567+
func writeGlobalRustWrapper(component ComponentDefinition, w LanguageWriter, cprefix string) error {
568+
methods := component.Global.Methods
569+
for i := 0; i < len(methods); i++ {
570+
method := methods[i]
571+
err := writeRustMethodWrapper(method, w, cprefix)
572+
if err != nil {
573+
return err
574+
}
575+
w.Writeln("")
576+
}
577+
return nil
578+
}
579+
580+
func writeRustMethodWrapper(method ComponentDefinitionMethod, w LanguageWriter, cprefix string) error {
581+
// Build up the parameter strings
582+
parameterString := ""
583+
returnName := ""
584+
for k := 0; k < len(method.Params); k++ {
585+
param := method.Params[k]
586+
RustParams, err := generateRustParameters(param, true)
587+
if err != nil {
588+
return err
589+
}
590+
for i := 0; i < len(RustParams); i++ {
591+
RustParam := RustParams[i]
592+
if parameterString == "" {
593+
parameterString += fmt.Sprintf("%s : %s", RustParam.ParamName, RustParam.ParamType)
594+
} else {
595+
parameterString += fmt.Sprintf(", %s : %s", RustParam.ParamName, RustParam.ParamType)
596+
}
597+
}
598+
}
599+
w.Writeln("pub fn %s%s(%s) -> i32 {", cprefix, strings.ToLower(method.MethodName), parameterString)
600+
w.AddIndentationLevel(1)
601+
argsString := ""
602+
for k := 0; k < len(method.Params); k++ {
603+
param := method.Params[k]
604+
OName, err := writeRustParameterConversionArg(param, w)
605+
if err != nil {
606+
return err
607+
}
608+
if OName != "" {
609+
if argsString == "" {
610+
argsString = OName
611+
} else {
612+
argsString += fmt.Sprintf(", %s", OName)
613+
}
614+
}
615+
}
616+
if returnName != "" {
617+
w.Writeln("let %s = CWrapper::%s(%s);", returnName, toSnakeCase(method.MethodName), argsString)
618+
} else {
619+
w.Writeln("CWrapper::%s(%s);", toSnakeCase(method.MethodName), argsString)
620+
}
621+
w.Writeln("// All ok")
622+
w.Writeln("0")
623+
w.AddIndentationLevel(-1)
624+
w.Writeln("}")
625+
return nil
626+
}
627+
628+
func writeRustParameterConversionArg(param ComponentDefinitionParam, w LanguageWriter) (string, error) {
629+
if param.ParamPass == "return" {
630+
return "", nil
631+
}
632+
IName := toSnakeCase(param.ParamName)
633+
OName := "_" + IName
634+
switch param.ParamType {
635+
case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "single", "double":
636+
if param.ParamPass == "in" {
637+
w.Writeln("let %s = %s;", OName, IName)
638+
} else {
639+
w.Writeln("let %s = unsafe {&mut *%s};", OName, IName)
640+
}
641+
case "class", "optionalclass":
642+
if param.ParamPass == "in" {
643+
HName := "_Handle_" + IName
644+
w.Writeln("let %s = unsafe {&*%s};", HName, IName)
645+
w.Writeln("let %s = %s.as_%s().unwrap();", OName, HName, toSnakeCase(param.ParamClass))
646+
} else {
647+
HName := "_Handle_" + IName
648+
w.Writeln("let %s = unsafe {&mut *%s};", HName, IName)
649+
w.Writeln("let %s = %s.as_mut_%s().unwrap();", OName, HName, toSnakeCase(param.ParamClass))
650+
}
651+
case "string":
652+
if param.ParamPass == "in" {
653+
SName := "_Str_" + IName
654+
w.Writeln("let %s = unsafe{ CStr::from_ptr(%s) };", SName, IName)
655+
w.Writeln("let %s = %s.to_str().unwrap();", OName, SName)
656+
} else {
657+
SName := "_String_" + IName
658+
w.Writeln("let mut %s = String::new();", SName)
659+
w.Writeln("let %s = &mut %s;", OName, SName)
660+
}
661+
case "bool", "pointer", "struct", "basicarray", "structarray":
662+
//return fmt.Errorf("Conversion of type %s for parameter %s not supported", param.ParamType, IName)
663+
default:
664+
return "", fmt.Errorf("Conversion of type %s for parameter %s not supported as is unknown", param.ParamType, IName)
665+
}
666+
return OName, nil
667+
}

Source/languagerust.go

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func toSnakeCase(BaseType string) string {
4747

4848
func writeRustBaseTypeDefinitions(componentdefinition ComponentDefinition, w LanguageWriter, NameSpace string, BaseName string) error {
4949
w.Writeln("#[allow(unused_imports)]")
50-
w.Writeln("use std::ffi;")
50+
w.Writeln("use std::ffi::c_void;")
5151
w.Writeln("")
5252
w.Writeln("/*************************************************************************************************************************")
5353
w.Writeln(" Version definition for %s", NameSpace)
@@ -63,10 +63,28 @@ func writeRustBaseTypeDefinitions(componentdefinition ComponentDefinition, w Lan
6363
w.Writeln("")
6464

6565
w.Writeln("/*************************************************************************************************************************")
66-
w.Writeln(" Basic pointers definition for %s", NameSpace)
66+
w.Writeln(" Handle definiton for %s", NameSpace)
6767
w.Writeln("**************************************************************************************************************************/")
6868
w.Writeln("")
69-
w.Writeln("type Handle = std::ffi::c_void;")
69+
w.Writeln("// Enum of all traits - this acts as a handle as we pass trait pointers through the interface")
70+
w.Writeln("pub enum HandleImpl {")
71+
w.AddIndentationLevel(1)
72+
for i := 0; i < len(componentdefinition.Classes); i++ {
73+
class := componentdefinition.Classes[i]
74+
if i != len(componentdefinition.Classes)-1 {
75+
w.Writeln("T%s(Box<dyn %s>),", class.ClassName, class.ClassName)
76+
} else {
77+
w.Writeln("T%s(Box<dyn %s>)", class.ClassName, class.ClassName)
78+
}
79+
}
80+
w.AddIndentationLevel(-1)
81+
w.Writeln("}")
82+
w.Writeln("")
83+
w.Writeln("pub type Handle = *mut HandleImpl;")
84+
for i := 0; i < len(componentdefinition.Classes); i++ {
85+
class := componentdefinition.Classes[i]
86+
w.Writeln("pub type %sHandle = *mut HandleImpl;", class.ClassName)
87+
}
7088

7189
if len(componentdefinition.Enums) > 0 {
7290
w.Writeln("/*************************************************************************************************************************")
@@ -211,6 +229,25 @@ func generateRustParameters(param ComponentDefinitionParam, isPlain bool) ([]Rus
211229
}
212230

213231
if isPlain {
232+
if param.ParamType == "string" {
233+
if param.ParamPass == "out" {
234+
Params = make([]RustParameter, 3)
235+
Params[0].ParamType = "u64"
236+
Params[0].ParamName = toSnakeCase(param.ParamName) + "_buffer_size"
237+
Params[0].ParamComment = fmt.Sprintf("* @param[in] %s - size of the buffer (including trailing 0)", Params[0].ParamName)
238+
239+
Params[1].ParamType = "*mut u64"
240+
Params[1].ParamName = toSnakeCase(param.ParamName) + "_needed_chars"
241+
Params[1].ParamComment = fmt.Sprintf("* @param[out] %s - will be filled with the count of the written bytes, or needed buffer size.", Params[1].ParamName)
242+
243+
Params[2].ParamType = "*mut c_char"
244+
Params[2].ParamName = toSnakeCase(param.ParamName) + "_buffer"
245+
Params[2].ParamComment = fmt.Sprintf("* @param[out] %s - %s buffer of %s, may be NULL", Params[2].ParamName, param.ParamClass, param.ParamDescription)
246+
247+
return Params, nil
248+
}
249+
}
250+
214251
if param.ParamType == "basicarray" {
215252
return nil, fmt.Errorf("Not yet handled")
216253
}
@@ -231,50 +268,51 @@ func generateRustParameterType(param ComponentDefinitionParam, isPlain bool) (st
231268
RustParamTypeName := ""
232269
ParamTypeName := param.ParamType
233270
ParamClass := param.ParamClass
271+
BasicType := false
234272
switch ParamTypeName {
235273
case "uint8":
236274
RustParamTypeName = "u8"
237-
275+
BasicType = true
238276
case "uint16":
239277
RustParamTypeName = "u16"
240-
278+
BasicType = true
241279
case "uint32":
242280
RustParamTypeName = "u32"
243-
281+
BasicType = true
244282
case "uint64":
245283
RustParamTypeName = "u64"
246-
284+
BasicType = true
247285
case "int8":
248286
RustParamTypeName = "i8"
249-
287+
BasicType = true
250288
case "int16":
251289
RustParamTypeName = "i16"
252-
290+
BasicType = true
253291
case "int32":
254292
RustParamTypeName = "i32"
255-
293+
BasicType = true
256294
case "int64":
257295
RustParamTypeName = "i64"
258-
296+
BasicType = true
259297
case "bool":
260298
if isPlain {
261299
RustParamTypeName = "u8"
262300
} else {
263301
RustParamTypeName = "bool"
264302
}
265-
303+
BasicType = true
266304
case "single":
267305
RustParamTypeName = "f32"
268-
306+
BasicType = true
269307
case "double":
270308
RustParamTypeName = "f64"
271-
309+
BasicType = true
272310
case "pointer":
273311
RustParamTypeName = "c_void"
274-
312+
BasicType = true
275313
case "string":
276314
if isPlain {
277-
RustParamTypeName = "*mut char"
315+
RustParamTypeName = "*const c_char"
278316
} else {
279317
switch param.ParamPass {
280318
case "out":
@@ -290,17 +328,12 @@ func generateRustParameterType(param ComponentDefinitionParam, isPlain bool) (st
290328
if isPlain {
291329
RustParamTypeName = fmt.Sprintf("u16")
292330
} else {
293-
switch param.ParamPass {
294-
case "out":
295-
RustParamTypeName = fmt.Sprintf("&mut %s", ParamClass)
296-
case "in", "return":
297-
RustParamTypeName = fmt.Sprintf("%s", ParamClass)
298-
}
331+
RustParamTypeName = ParamClass
299332
}
300-
333+
BasicType = true
301334
case "functiontype":
302335
RustParamTypeName = fmt.Sprintf("%s", ParamClass)
303-
336+
BasicType = true
304337
case "struct":
305338
if isPlain {
306339
RustParamTypeName = fmt.Sprintf("*mut %s", ParamClass)
@@ -353,13 +386,14 @@ func generateRustParameterType(param ComponentDefinitionParam, isPlain bool) (st
353386

354387
case "class", "optionalclass":
355388
if isPlain {
356-
RustParamTypeName = fmt.Sprintf("Handle")
389+
RustParamTypeName = fmt.Sprintf("%sHandle", ParamClass)
390+
BasicType = true
357391
} else {
358392
switch param.ParamPass {
359393
case "out":
360-
RustParamTypeName = fmt.Sprintf("&mut impl %s", ParamClass)
394+
RustParamTypeName = fmt.Sprintf("&mut dyn %s", ParamClass)
361395
case "in":
362-
RustParamTypeName = fmt.Sprintf("& impl %s", ParamClass)
396+
RustParamTypeName = fmt.Sprintf("& dyn %s", ParamClass)
363397
case "return":
364398
RustParamTypeName = fmt.Sprintf("Box<dyn %s>", ParamClass)
365399
}
@@ -368,6 +402,16 @@ func generateRustParameterType(param ComponentDefinitionParam, isPlain bool) (st
368402
default:
369403
return "", fmt.Errorf("invalid parameter type \"%s\" for Rust parameter", ParamTypeName)
370404
}
371-
405+
if BasicType {
406+
if param.ParamPass == "out" {
407+
if isPlain {
408+
RustParamOutTypeName := fmt.Sprintf("*mut %s", RustParamTypeName)
409+
return RustParamOutTypeName, nil
410+
} else {
411+
RustParamOutTypeName := fmt.Sprintf("&mut %s", RustParamTypeName)
412+
return RustParamOutTypeName, nil
413+
}
414+
}
415+
}
372416
return RustParamTypeName, nil
373417
}

0 commit comments

Comments
 (0)