diff --git a/build/golang.go b/build/golang.go index e562ac76..66ef4b5f 100644 --- a/build/golang.go +++ b/build/golang.go @@ -84,6 +84,8 @@ type LocalGolangOptions struct { // Args are the optional arguments to pass to the compiler Args []string + + Extensions []extension.Info } func LocalGolang(options *LocalGolangOptions) (*scalefunc.V1BetaSchema, error) { @@ -192,7 +194,24 @@ func LocalGolang(options *LocalGolangOptions) (*scalefunc.V1BetaSchema, error) { _ = options.Storage.Delete(build) }() - modfile, err := golang.GenerateGoModfile(signatureInfo, functionInfo) + // Copy over any replacements from the go.mod + replacements := make([]golang.GoModReplacement, 0) + + r := manifest.GetReplacements() + for _, resp := range r { + // Check if the target is a local dir... + newPath := resp.New.Path + + if !filepath.IsAbs(newPath) { + newPath = filepath.Join(options.SourceDirectory, newPath) + } + replacements = append(replacements, golang.GoModReplacement{ + Name: fmt.Sprintf("%s %s", resp.Old.Path, resp.Old.Version), + Path: fmt.Sprintf("%s %s", newPath, resp.New.Version), + }) + } + + modfile, err := golang.GenerateGoModfile(signatureInfo, functionInfo, replacements) if err != nil { return nil, fmt.Errorf("unable to generate go.mod file: %w", err) } diff --git a/compile/golang/generator.go b/compile/golang/generator.go index f489d915..299c6e9f 100644 --- a/compile/golang/generator.go +++ b/compile/golang/generator.go @@ -28,8 +28,13 @@ import ( var generator *Generator -func GenerateGoModfile(signatureInfo *SignatureInfo, functionInfo *FunctionInfo) ([]byte, error) { - return generator.GenerateGoModfile(signatureInfo, functionInfo) +type GoModReplacement struct { + Name string + Path string +} + +func GenerateGoModfile(signatureInfo *SignatureInfo, functionInfo *FunctionInfo, replacements []GoModReplacement) ([]byte, error) { + return generator.GenerateGoModfile(signatureInfo, functionInfo, replacements) } func GenerateGoMain(scalefileSchema *scalefile.Schema, signatureSchema *signature.Schema, functionInfo *FunctionInfo) ([]byte, error) { @@ -50,14 +55,15 @@ func New() *Generator { } } -func (g *Generator) GenerateGoModfile(signatureInfo *SignatureInfo, functionInfo *FunctionInfo) ([]byte, error) { +func (g *Generator) GenerateGoModfile(signatureInfo *SignatureInfo, functionInfo *FunctionInfo, replacements []GoModReplacement) ([]byte, error) { signatureInfo.normalize() functionInfo.normalize() buf := new(bytes.Buffer) err := g.template.ExecuteTemplate(buf, "mod.go.templ", map[string]interface{}{ - "function": functionInfo, - "signature": signatureInfo, + "function": functionInfo, + "signature": signatureInfo, + "replacements": replacements, }) if err != nil { return nil, err diff --git a/compile/golang/manifest.go b/compile/golang/manifest.go index 270f5417..35eb10d0 100644 --- a/compile/golang/manifest.go +++ b/compile/golang/manifest.go @@ -31,6 +31,10 @@ func ParseManifest(data []byte) (*Manifest, error) { }, nil } +func (m *Manifest) GetReplacements() []*modfile.Replace { + return m.modfile.Replace +} + func (m *Manifest) AddReplacement(oldDependency string, oldVersion string, newDependency string, newVersion string) error { return m.modfile.AddReplace(oldDependency, oldVersion, newDependency, newVersion) } diff --git a/compile/golang/templates/mod.go.templ b/compile/golang/templates/mod.go.templ index f78d082e..9108e2c3 100644 --- a/compile/golang/templates/mod.go.templ +++ b/compile/golang/templates/mod.go.templ @@ -1,6 +1,7 @@ module compile go 1.20 + {{ if .signature.Local }} replace signature v0.1.0 => {{ .signature.ImportPath }} {{ else }} @@ -9,7 +10,11 @@ replace signature v0.1.0 => {{ .signature.ImportPath }} {{ .signature.ImportVers replace {{ .function.PackageName }} v0.1.0 => {{ .function.ImportPath }} +{{ range $replacements := .replacements }} + replace {{ $replacements.Name }} => {{ $replacements.Path }} +{{ end }} + require ( signature v0.1.0 {{ .function.PackageName }} v0.1.0 -) \ No newline at end of file +) diff --git a/config.go b/config.go index 53be8ad3..88525912 100644 --- a/config.go +++ b/config.go @@ -22,6 +22,7 @@ import ( "io" "regexp" + extension "github.com/loopholelabs/scale-extension-interfaces" interfaces "github.com/loopholelabs/scale-signature-interfaces" "github.com/loopholelabs/scale/scalefunc" ) @@ -50,6 +51,7 @@ type Config[T interfaces.Signature] struct { stdout io.Writer stderr io.Writer rawOutput bool + extensions []extension.Extension } // NewConfig returns a new Scale Runtime Config @@ -85,6 +87,11 @@ func (c *Config[T]) validate() error { return nil } +func (c *Config[T]) WithExtension(e extension.Extension) *Config[T] { + c.extensions = append(c.extensions, e) + return c +} + func (c *Config[T]) WithSignature(newSignature interfaces.New[T]) *Config[T] { c.newSignature = newSignature return c diff --git a/extension/generator/file.go b/extension/generator/file.go new file mode 100644 index 00000000..85ef2026 --- /dev/null +++ b/extension/generator/file.go @@ -0,0 +1,88 @@ +/* + Copyright 2023 Loophole Labs + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package generator + +import ( + "bytes" + "io" + "io/fs" + "os" + "time" + + "golang.org/x/mod/zip" +) + +var _ zip.File = (*File)(nil) +var _ os.FileInfo = (*File)(nil) + +type File struct { + name string + path string + content []byte + reader *bytes.Reader + size int64 +} + +func NewFile(name string, path string, content []byte) File { + return File{ + name: name, + path: path, + content: content, + reader: bytes.NewReader(content), + size: int64(len(content)), + } +} + +func (g File) Name() string { + return g.name +} + +func (g File) Size() int64 { + return g.size +} + +func (g File) Mode() fs.FileMode { + return 0700 +} + +func (g File) ModTime() time.Time { + return time.Now() +} + +func (g File) IsDir() bool { + return false +} + +func (g File) Sys() any { + return g.content +} + +func (g File) Path() string { + return g.path +} + +func (g File) Lstat() (os.FileInfo, error) { + return g, nil +} + +func (g File) Open() (io.ReadCloser, error) { + return io.NopCloser(g.reader), nil +} + +func (g File) Data() []byte { + return g.content +} diff --git a/extension/generator/generator.go b/extension/generator/generator.go new file mode 100644 index 00000000..2d62b741 --- /dev/null +++ b/extension/generator/generator.go @@ -0,0 +1,163 @@ +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package generator + +import ( + "bytes" + "encoding/hex" + + "github.com/loopholelabs/scale/extension" + "github.com/loopholelabs/scale/extension/generator/golang" + "github.com/loopholelabs/scale/extension/generator/rust" +) + +type GuestRegistryPackage struct { + GolangModule *bytes.Buffer + GolangModfile []byte + RustCrate *bytes.Buffer + RustCargofile []byte + TypescriptPackage *bytes.Buffer + TypescriptPackageJSON []byte +} + +type GuestLocalPackage struct { + GolangFiles []File + RustFiles []File + TypescriptFiles []File +} + +type HostRegistryPackage struct { + GolangModule *bytes.Buffer + GolangModfile []byte + TypescriptPackage *bytes.Buffer + TypescriptPackageJSON []byte +} + +type HostLocalPackage struct { + GolangFiles []File + TypescriptFiles []File +} + +type Options struct { + Extension *extension.Schema + + GolangPackageImportPath string + GolangPackageName string + + RustPackageName string + RustPackageVersion string + + TypescriptPackageName string + TypescriptPackageVersion string +} + +func GenerateGuestLocal(options *Options) (*GuestLocalPackage, error) { + hash, err := options.Extension.Hash() + if err != nil { + return nil, err + } + hashString := hex.EncodeToString(hash) + + golangTypes, err := golang.GenerateTypes(options.Extension, options.GolangPackageName) + if err != nil { + return nil, err + } + + golangGuest, err := golang.GenerateGuest(options.Extension, hashString, options.GolangPackageName) + if err != nil { + return nil, err + } + + golangInterfaces, err := golang.GenerateInterfaces(options.Extension, options.GolangPackageName) + if err != nil { + return nil, err + } + + modfile, err := golang.GenerateModfile(options.GolangPackageName) + if err != nil { + return nil, err + } + + golangFiles := []File{ + NewFile("types.go", "types.go", golangTypes), + NewFile("guest.go", "guest.go", golangGuest), + NewFile("interfaces.go", "interfaces.go", golangInterfaces), + NewFile("go.mod", "go.mod", modfile), + } + + rustTypes, err := rust.GenerateTypes(options.Extension, options.RustPackageName) + if err != nil { + return nil, err + } + + rustGuest, err := rust.GenerateGuest(options.Extension, hashString, options.RustPackageName) + if err != nil { + return nil, err + } + + cargofile, err := rust.GenerateCargofile(options.RustPackageName, options.RustPackageVersion) + if err != nil { + return nil, err + } + + rustFiles := []File{ + NewFile("types.rs", "types.rs", rustTypes), + NewFile("guest.rs", "guest.rs", rustGuest), + NewFile("Cargo.toml", "Cargo.toml", cargofile), + } + + return &GuestLocalPackage{ + GolangFiles: golangFiles, + RustFiles: rustFiles, + }, nil +} + +func GenerateHostLocal(options *Options) (*HostLocalPackage, error) { + hash, err := options.Extension.Hash() + if err != nil { + return nil, err + } + hashString := hex.EncodeToString(hash) + + golangTypes, err := golang.GenerateTypes(options.Extension, options.GolangPackageName) + if err != nil { + return nil, err + } + + golangHost, err := golang.GenerateHost(options.Extension, hashString, options.GolangPackageName) + if err != nil { + return nil, err + } + + golangInterfaces, err := golang.GenerateInterfaces(options.Extension, options.GolangPackageName) + if err != nil { + return nil, err + } + + modfile, err := golang.GenerateModfile(options.GolangPackageName) + if err != nil { + return nil, err + } + + golangFiles := []File{ + NewFile("types.go", "types.go", golangTypes), + NewFile("host.go", "host.go", golangHost), + NewFile("interfaces.go", "interfaces.go", golangInterfaces), + NewFile("go.mod", "go.mod", modfile), + } + + return &HostLocalPackage{ + GolangFiles: golangFiles, + }, nil +} diff --git a/extension/generator/golang/generated.txt b/extension/generator/golang/generated.txt new file mode 100644 index 00000000..fc3c0554 --- /dev/null +++ b/extension/generator/golang/generated.txt @@ -0,0 +1,270 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: types + +package types + +import ( + "errors" + "github.com/loopholelabs/polyglot" +) + +var ( + NilDecode = errors.New("cannot decode into a nil root struct") + InvalidEnum = errors.New("invalid enum value") +) + +type HttpConfig struct { + Timeout int32 +} + +func NewHttpConfig() *HttpConfig { + return &HttpConfig{ + + Timeout: 60, + } +} + +func (x *HttpConfig) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Int32(x.Timeout) + + } +} + +func DecodeHttpConfig(x *HttpConfig, b []byte) (*HttpConfig, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeHttpConfig(x, d) +} + +func _decodeHttpConfig(x *HttpConfig, d *polyglot.Decoder) (*HttpConfig, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewHttpConfig() + } + + x.Timeout, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +type HttpResponse struct { + Headers map[string]StringList + + StatusCode int32 + + Body []byte +} + +func NewHttpResponse() *HttpResponse { + return &HttpResponse{ + + Headers: make(map[string]StringList), + + StatusCode: 0, + + Body: make([]byte, 0, 0), + } +} + +func (x *HttpResponse) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Map(uint32(len(x.Headers)), polyglot.StringKind, polyglot.AnyKind) + for k, v := range x.Headers { + e.String(k) + v.Encode(b) + } + + e.Int32(x.StatusCode) + + e.Bytes(x.Body) + + } +} + +func DecodeHttpResponse(x *HttpResponse, b []byte) (*HttpResponse, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeHttpResponse(x, d) +} + +func _decodeHttpResponse(x *HttpResponse, d *polyglot.Decoder) (*HttpResponse, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewHttpResponse() + } + + mapSizeHeaders, err := d.Map(polyglot.StringKind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Headers)) != mapSizeHeaders { + x.Headers = make(map[string]StringList, mapSizeHeaders) + } + + for i := uint32(0); i < mapSizeHeaders; i++ { + k, err := d.String() + if err != nil { + return nil, err + } + v, err := _decodeStringList(nil, d) + if err != nil { + return nil, err + } + x.Headers[k] = *v + } + + x.StatusCode, err = d.Int32() + if err != nil { + return nil, err + } + + x.Body, err = d.Bytes(nil) + if err != nil { + return nil, err + } + + return x, nil +} + +type StringList struct { + Values []string +} + +func NewStringList() *StringList { + return &StringList{ + + Values: make([]string, 0, 0), + } +} + +func (x *StringList) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Slice(uint32(len(x.Values)), polyglot.StringKind) + for _, a := range x.Values { + e.String(a) + } + + } +} + +func DecodeStringList(x *StringList, b []byte) (*StringList, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeStringList(x, d) +} + +func _decodeStringList(x *StringList, d *polyglot.Decoder) (*StringList, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewStringList() + } + + sliceSizeValues, err := d.Slice(polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Values)) != sliceSizeValues { + x.Values = make([]string, sliceSizeValues) + } + + for i := uint32(0); i < sliceSizeValues; i++ { + x.Values[i], err = d.String() + if err != nil { + return nil, err + } + } + + return x, nil +} + +type ConnectionDetails struct { + Url string +} + +func NewConnectionDetails() *ConnectionDetails { + return &ConnectionDetails{ + + Url: "https://google.com", + } +} + +func (x *ConnectionDetails) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.Url) + + } +} + +func DecodeConnectionDetails(x *ConnectionDetails, b []byte) (*ConnectionDetails, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeConnectionDetails(x, d) +} + +func _decodeConnectionDetails(x *ConnectionDetails, d *polyglot.Decoder) (*ConnectionDetails, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewConnectionDetails() + } + + x.Url, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} diff --git a/extension/generator/golang/generator.go b/extension/generator/golang/generator.go new file mode 100644 index 00000000..6eaffd97 --- /dev/null +++ b/extension/generator/golang/generator.go @@ -0,0 +1,289 @@ +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package golang + +import ( + "bytes" + "go/format" + "text/template" + + "github.com/loopholelabs/scale/signature" + "github.com/loopholelabs/scale/signature/generator/golang" + scaleVersion "github.com/loopholelabs/scale/version" + + polyglotVersion "github.com/loopholelabs/polyglot/version" + + interfacesVersion "github.com/loopholelabs/scale-extension-interfaces/version" + "github.com/loopholelabs/scale/extension" + + "github.com/loopholelabs/scale/extension/generator/golang/templates" + "github.com/loopholelabs/scale/signature/generator/utils" +) + +const ( + defaultPackageName = "types" +) + +var generator *Generator + +func GenerateTypes(extensionSchema *extension.Schema, packageName string) ([]byte, error) { + return generator.GenerateTypes(extensionSchema, packageName) +} + +func GenerateInterfaces(extensionSchema *extension.Schema, packageName string) ([]byte, error) { + return generator.GenerateInterfaces(extensionSchema, packageName) +} + +func GenerateModfile(packageName string) ([]byte, error) { + return generator.GenerateModfile(packageName) +} + +func GenerateGuest(extensionSchema *extension.Schema, extensionHash string, packageName string) ([]byte, error) { + return generator.GenerateGuest(extensionSchema, extensionHash, packageName) +} + +func GenerateHost(extensionSchema *extension.Schema, extensionHash string, packageName string) ([]byte, error) { + return generator.GenerateHost(extensionSchema, extensionHash, packageName) +} + +func init() { + var err error + generator, err = New() + if err != nil { + panic(err) + } +} + +// Generator is the go generator +type Generator struct { + templ *template.Template + signature *golang.Generator +} + +// New creates a new go generator +func New() (*Generator, error) { + templ, err := template.New("").Funcs(templateFunctions()).ParseFS(templates.FS, "*.go.templ") + if err != nil { + return nil, err + } + + sig, err := golang.New() + if err != nil { + return nil, err + } + + return &Generator{ + templ: templ, + signature: sig, + }, nil +} + +// GenerateTypes generates the types for the extension +func (g *Generator) GenerateTypes(extensionSchema *extension.Schema, packageName string) ([]byte, error) { + signatureSchema := &signature.Schema{ + Version: extensionSchema.Version, + Enums: extensionSchema.Enums, + Models: extensionSchema.Models, + } + + signatureSchema.SetHasLengthValidator(extensionSchema.HasLengthValidator()) + signatureSchema.SetHasCaseModifier(extensionSchema.HasCaseModifier()) + signatureSchema.SetHasLimitValidator(extensionSchema.HasLimitValidator()) + signatureSchema.SetHasRegexValidator(extensionSchema.HasRegexValidator()) + + return g.signature.GenerateTypes(signatureSchema, packageName) +} + +// GenerateInterfaces generates the interfaces for the extension +func (g *Generator) GenerateInterfaces(extensionSchema *extension.Schema, packageName string) ([]byte, error) { + if packageName == "" { + packageName = defaultPackageName + } + + buf := new(bytes.Buffer) + err := g.templ.ExecuteTemplate(buf, "interfaces.go.templ", map[string]any{ + "extension_schema": extensionSchema, + "generator_version": scaleVersion.Version(), + "package_name": packageName, + }) + if err != nil { + return nil, err + } + + return format.Source(buf.Bytes()) +} + +// GenerateModfile generates the modfile for the signature +func (g *Generator) GenerateModfile(packageImportPath string) ([]byte, error) { + buf := new(bytes.Buffer) + err := g.templ.ExecuteTemplate(buf, "mod.go.templ", map[string]any{ + "polyglot_version": polyglotVersion.Version(), + "scale_extension_interfaces_version": interfacesVersion.Version(), + "package_import_path": packageImportPath, + }) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// GenerateGuest generates the guest bindings +func (g *Generator) GenerateGuest(extensionSchema *extension.Schema, extensionHash string, packageName string) ([]byte, error) { + if packageName == "" { + packageName = defaultPackageName + } + + buf := new(bytes.Buffer) + err := g.templ.ExecuteTemplate(buf, "guest.go.templ", map[string]any{ + "extension_hash": extensionHash, + "extension_schema": extensionSchema, + "generator_version": scaleVersion.Version(), + "package_name": packageName, + }) + if err != nil { + return nil, err + } + + return format.Source(buf.Bytes()) +} + +// GenerateHost generates the host bindings +func (g *Generator) GenerateHost(extensionSchema *extension.Schema, extensionHash string, packageName string) ([]byte, error) { + if packageName == "" { + packageName = defaultPackageName + } + + buf := new(bytes.Buffer) + err := g.templ.ExecuteTemplate(buf, "host.go.templ", map[string]any{ + "extension_hash": extensionHash, + "extension_schema": extensionSchema, + "generator_version": scaleVersion.Version(), + "package_name": packageName, + }) + if err != nil { + return nil, err + } + + return format.Source(buf.Bytes()) +} + +func templateFunctions() template.FuncMap { + return template.FuncMap{ + "IsInterface": isInterface, + "Primitive": primitive, + "IsPrimitive": extension.ValidPrimitiveType, + "PolyglotPrimitive": polyglotPrimitive, + "PolyglotPrimitiveEncode": polyglotPrimitiveEncode, + "PolyglotPrimitiveDecode": polyglotPrimitiveDecode, + "Deref": func(i *bool) bool { return *i }, + "LowerFirst": func(s string) string { return string(s[0]+32) + s[1:] }, + "Params": utils.Params, + } +} + +func isInterface(schema *extension.Schema, s string) bool { + for _, i := range schema.Interfaces { + if i.Name == s { + return true + } + } + return false +} + +func primitive(t string) string { + switch t { + case "string", "int32", "int64", "uint32", "uint64", "float32", "float64", "bool": + return t + case "bytes": + return "[]byte" + default: + return "" + } +} + +func polyglotPrimitive(t string) string { + switch t { + case "string": + return "polyglot.StringKind" + case "int32": + return "polyglot.Int32Kind" + case "int64": + return "polyglot.Int64Kind" + case "uint32": + return "polyglot.Uint32Kind" + case "uint64": + return "polyglot.Uint64Kind" + case "float32": + return "polyglot.Float32Kind" + case "float64": + return "polyglot.Float64Kind" + case "bool": + return "polyglot.BoolKind" + case "bytes": + return "polyglot.BytesKind" + default: + return "polyglot.AnyKind" + } +} + +func polyglotPrimitiveEncode(t string) string { + switch t { + case "string": + return "String" + case "int32": + return "Int32" + case "int64": + return "Int64" + case "uint32": + return "Uint32" + case "uint64": + return "Uint64" + case "float32": + return "Float32" + case "float64": + return "Float64" + case "bool": + return "Bool" + case "bytes": + return "Bytes" + default: + return "" + } +} + +func polyglotPrimitiveDecode(t string) string { + switch t { + case "string": + return "String" + case "int32": + return "Int32" + case "int64": + return "Int64" + case "uint32": + return "Uint32" + case "uint64": + return "Uint64" + case "float32": + return "Float32" + case "float64": + return "Float64" + case "bool": + return "Bool" + case "bytes": + return "Bytes" + default: + return "" + } +} diff --git a/extension/generator/golang/generator_test.go b/extension/generator/golang/generator_test.go new file mode 100644 index 00000000..13276382 --- /dev/null +++ b/extension/generator/golang/generator_test.go @@ -0,0 +1,77 @@ +//go:build !integration + +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package golang + +import ( + "encoding/hex" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/loopholelabs/scale/extension" +) + +func TestGenerator(t *testing.T) { + s := new(extension.Schema) + err := s.Decode([]byte(extension.MasterTestingSchema)) + require.NoError(t, err) + + packageName := "extfetch" + + interfaces, err := GenerateInterfaces(s, packageName) + require.NoError(t, err) + // os.WriteFile("./interfaces.txt", interfaces, 0644) + + expInterfaces, err := os.ReadFile("./interfaces.txt") + require.NoError(t, err) + require.Equal(t, string(expInterfaces), string(interfaces)) + + formatted, err := GenerateTypes(s, "types") + require.NoError(t, err) + // os.WriteFile("./generated.txt", formatted, 0644) + + expTypes, err := os.ReadFile("./generated.txt") + require.NoError(t, err) + require.Equal(t, string(expTypes), string(formatted)) + + sHash, err := s.Hash() + require.NoError(t, err) + + hash := hex.EncodeToString(sHash) + + host, err := GenerateHost(s, hash, packageName) + require.NoError(t, err) + // os.WriteFile("./host.txt", host, 0644) + expHost, err := os.ReadFile("./host.txt") + require.NoError(t, err) + require.Equal(t, string(expHost), string(host)) + + guest, err := GenerateGuest(s, hash, packageName) + require.NoError(t, err) + // os.WriteFile("./guest.txt", guest, 0644) + expGuest, err := os.ReadFile("./guest.txt") + require.NoError(t, err) + require.Equal(t, string(expGuest), string(guest)) + + mod, err := GenerateModfile(packageName) + require.NoError(t, err) + // os.WriteFile("./modfile.txt", mod, 0644) + expMod, err := os.ReadFile("./modfile.txt") + require.NoError(t, err) + require.Equal(t, string(expMod), string(mod)) + +} diff --git a/extension/generator/golang/guest.txt b/extension/generator/golang/guest.txt new file mode 100644 index 00000000..bc8e701c --- /dev/null +++ b/extension/generator/golang/guest.txt @@ -0,0 +1,114 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: extfetch + +package extfetch + +import ( + "github.com/loopholelabs/polyglot" + "unsafe" +) + +var ( + writeBuffer = polyglot.NewBuffer() + readBuffer []byte +) + +//export ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize +//go:linkname ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize +func ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize(size uint32) uint32 { + readBuffer = make([]byte, size) + //if uint32(cap(readBuffer)) < size { + // readBuffer = append(make([]byte, 0, uint32(len(readBuffer))+size), readBuffer...) + //} + //readBuffer = readBuffer[:size] + return uint32(uintptr(unsafe.Pointer(&readBuffer[0]))) +} + +// Define any interfaces we need here... +// Also define structs we can use to hold instanceId + +// Define concrete types with a hidden instanceId + +type _HttpConnector struct { + instanceId uint64 +} + +func (d *_HttpConnector) Fetch(params *ConnectionDetails) (HttpResponse, error) { + + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch(d.instanceId, off, l) + // IF the return type is a model, we should read the data from the read buffer. + + ret := &HttpResponse{} + r, err := DecodeHttpResponse(ret, readBuffer) + + if err != nil { + return HttpResponse{}, err + } + + return *r, err + +} + +//export ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch +//go:linkname ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch +func ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch(instance uint64, offset uint32, length uint32) uint64 + +// Define any global functions here... + +//export ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New +//go:linkname ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New +func ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New(instance uint64, offset uint32, length uint32) uint64 + +func New(params *HttpConfig) (HttpConnector, error) { + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + readBuffer = nil + v := ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New(0, off, l) + // IF the return type is an interface return ifc, which contains hidden instanceId. + + // Handle error from host. In this case there'll be an error in the readBuffer + if readBuffer != nil { + val, err := polyglot.GetDecoder(readBuffer).Error() + if err != nil { + panic(err) + } + return nil, val + } + + ret := &_HttpConnector{ + instanceId: v, + } + + return ret, nil + +} + +// Error serializes an error into the global writeBuffer and returns a pointer to the buffer and its size +// +// Users should not use this method. +func Error(err error) (uint32, uint32) { + writeBuffer.Reset() + polyglot.Encoder(writeBuffer).Error(err) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + return uint32(unsafePtr), uint32(writeBuffer.Len()) +} diff --git a/extension/generator/golang/host.txt b/extension/generator/golang/host.txt new file mode 100644 index 00000000..772e8f5a --- /dev/null +++ b/extension/generator/golang/host.txt @@ -0,0 +1,147 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: extfetch + +package extfetch + +import ( + "errors" + "sync" + "sync/atomic" + + "github.com/loopholelabs/polyglot" + extension "github.com/loopholelabs/scale-extension-interfaces" +) + +// Write an error to the scale function guest buffer. +func hostError(mem extension.ModuleMemory, resize extension.Resizer, err error) { + b := polyglot.NewBuffer() + polyglot.Encoder(b).Error(err) + + writeBuffer, err := resize("ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize", uint64(b.Len())) + + if err != nil { + panic(err) + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + panic(err) + } +} + +type hostExt struct { + functions map[string]extension.InstallableFunc + host *Host +} + +func (he *hostExt) Init() map[string]extension.InstallableFunc { + return he.functions +} + +func (he *hostExt) Reset() { + // Reset any instances that have been created. + + he.host.instances_HttpConnector = make(map[uint64]HttpConnector) + +} + +func New(impl Interface) extension.Extension { + hostWrapper := &Host{impl: impl} + + fns := make(map[string]extension.InstallableFunc) + + // Add global functions to the runtime + + fns["ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New"] = hostWrapper.host_ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New + + hostWrapper.instances_HttpConnector = make(map[uint64]HttpConnector) + + fns["ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch"] = hostWrapper.host_ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch + + return &hostExt{ + functions: fns, + host: hostWrapper, + } +} + +type Host struct { + impl Interface + + gid_HttpConnector uint64 + instancesLock_HttpConnector sync.Mutex + instances_HttpConnector map[uint64]HttpConnector +} + +// Global functions + +func (h *Host) host_ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &HttpConfig{} + cd, err := DecodeHttpConfig(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + // Call the implementation + r, err := h.impl.New(cd) + if err != nil { + hostError(mem, resize, err) + return + } + + id := atomic.AddUint64(&h.gid_HttpConnector, 1) + h.instancesLock_HttpConnector.Lock() + h.instances_HttpConnector[id] = r + h.instancesLock_HttpConnector.Unlock() + + // Return the ID + params[0] = id + +} + +func (h *Host) host_ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + h.instancesLock_HttpConnector.Lock() + r, ok := h.instances_HttpConnector[params[0]] + h.instancesLock_HttpConnector.Unlock() + if !ok { + hostError(mem, resize, errors.New("Instance ID not found!")) + return + } + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &ConnectionDetails{} + cd, err := DecodeConnectionDetails(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + resp, err := r.Fetch(cd) + if err != nil { + hostError(mem, resize, err) + return + } + + b := polyglot.NewBuffer() + resp.Encode(b) + + writeBuffer, err := resize("ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize", uint64(b.Len())) + + if err != nil { + hostError(mem, resize, err) + return + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + hostError(mem, resize, err) + return + } + +} diff --git a/extension/generator/golang/interfaces.txt b/extension/generator/golang/interfaces.txt new file mode 100644 index 00000000..b388b612 --- /dev/null +++ b/extension/generator/golang/interfaces.txt @@ -0,0 +1,13 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: extfetch + +package extfetch + +// Interface must be implemented by the host. +type Interface interface { + New(params *HttpConfig) (HttpConnector, error) +} + +type HttpConnector interface { + Fetch(*ConnectionDetails) (HttpResponse, error) +} diff --git a/extension/generator/golang/modfile.txt b/extension/generator/golang/modfile.txt new file mode 100644 index 00000000..e31c6312 --- /dev/null +++ b/extension/generator/golang/modfile.txt @@ -0,0 +1,8 @@ +module extfetch + +go 1.20 + +require ( + github.com/loopholelabs/polyglot v1.1.3 + github.com/loopholelabs/scale-extension-interfaces v0.1.0 +) \ No newline at end of file diff --git a/extension/generator/golang/templates/guest.go.templ b/extension/generator/golang/templates/guest.go.templ new file mode 100644 index 00000000..36011bbd --- /dev/null +++ b/extension/generator/golang/templates/guest.go.templ @@ -0,0 +1,164 @@ +// Code generated by scale-extension {{ .generator_version }}, DO NOT EDIT. +// output: {{ .package_name }} + +package {{ .package_name }} + +import ( + "github.com/loopholelabs/polyglot" + "unsafe" +) + +{{ $schema := .extension_schema }} +{{ $hash := .extension_hash }} + +var ( + writeBuffer = polyglot.NewBuffer() + readBuffer []byte +) + +//export ext_{{ $hash }}_Resize +//go:linkname ext_{{ $hash }}_Resize +func ext_{{ $hash }}_Resize(size uint32) uint32 { + readBuffer = make([]byte, size) + //if uint32(cap(readBuffer)) < size { + // readBuffer = append(make([]byte, 0, uint32(len(readBuffer))+size), readBuffer...) + //} + //readBuffer = readBuffer[:size] + return uint32(uintptr(unsafe.Pointer(&readBuffer[0]))) +} + +// Define any interfaces we need here... +// Also define structs we can use to hold instanceId + +{{ range $ifc := .extension_schema.Interfaces }} + +// Define concrete types with a hidden instanceId + +type _{{ $ifc.Name }} struct { + instanceId uint64 +} + +{{ range $fn := $ifc.Functions }} +func (d *_{{ $ifc.Name }}) {{ $fn.Name }}(params *{{ $fn.Params }}) ({{ $fn.Return }}, error) { + + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + + {{- if (IsInterface $schema $fn.Return) }} + readBuffer = nil + v := ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(d.instanceId, off, l) + // IF the return type is an interface return ifc, which contains hidden instanceId. + + // Handle error from host. In this case there'll be an error in the readBuffer + if (readBuffer!=nil) { + val, err := polyglot.GetDecoder(readBuffer).Error() + if err!=nil { + panic(err) + } + return &_{{ $fn.Return}}{}, val + } + + ret := &_{{ $fn.Return }}{ + instanceId: v, + } + + return ret, nil + {{ else }} + ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(d.instanceId, off, l) + // IF the return type is a model, we should read the data from the read buffer. + + ret := &{{ $fn.Return }}{} + r, err := Decode{{ $fn.Return }}(ret, readBuffer) + + if err!=nil { + return {{ $fn.Return }}{}, err + } + + return *r, err + {{ end }} +} + +//export ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }} +//go:linkname ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }} +func ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(instance uint64, offset uint32, length uint32) uint64 + +{{ end }} + +{{ end }} + +// Define any global functions here... + +{{ range $fn := .extension_schema.Functions }} + +//export ext_{{ $hash }}_{{ $fn.Name }} +//go:linkname ext_{{ $hash }}_{{ $fn.Name }} +func ext_{{ $hash }}_{{ $fn.Name }}(instance uint64, offset uint32, length uint32) uint64 + +func {{ $fn.Name }}(params *{{ $fn.Params }}) ({{ $fn.Return }}, error) { + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + + {{- if (IsInterface $schema $fn.Return) }} + readBuffer = nil + v := ext_{{ $hash }}_{{ $fn.Name }}(0, off, l) + // IF the return type is an interface return ifc, which contains hidden instanceId. + + // Handle error from host. In this case there'll be an error in the readBuffer + if (readBuffer!=nil) { + val, err := polyglot.GetDecoder(readBuffer).Error() + if err!=nil { + panic(err) + } + return nil, val + } + + ret := &_{{ $fn.Return }}{ + instanceId: v, + } + + return ret, nil + {{ else }} + ext_{{ $hash }}_{{ $fn.Name }}(0, off, l) + // IF the return type is a model, we should read the data from the read buffer. + + ret := &{{ $fn.Return }}{} + r, err := Decode{{ $fn.Return }}(ret, readBuffer) + + if err!=nil { + return {{ $fn.Return }}{}, err + } + + return *r, err + {{ end }} + +} + +{{ end }} + +// Error serializes an error into the global writeBuffer and returns a pointer to the buffer and its size +// +// Users should not use this method. +func Error(err error) (uint32, uint32) { + writeBuffer.Reset() + polyglot.Encoder(writeBuffer).Error(err) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + return uint32(unsafePtr), uint32(writeBuffer.Len()) +} diff --git a/extension/generator/golang/templates/host.go.templ b/extension/generator/golang/templates/host.go.templ new file mode 100644 index 00000000..139b07e1 --- /dev/null +++ b/extension/generator/golang/templates/host.go.templ @@ -0,0 +1,203 @@ +// Code generated by scale-extension {{ .generator_version }}, DO NOT EDIT. +// output: {{ .package_name }} + +package {{ .package_name }} + +import ( + "errors" + "sync/atomic" + "sync" + + "github.com/loopholelabs/polyglot" + extension "github.com/loopholelabs/scale-extension-interfaces" +) + +{{ $schema := .extension_schema }} +{{ $hash := .extension_hash }} + +// Write an error to the scale function guest buffer. +func hostError(mem extension.ModuleMemory, resize extension.Resizer, err error) { + b := polyglot.NewBuffer() + polyglot.Encoder(b).Error(err) + + writeBuffer, err := resize("ext_{{ $hash }}_Resize", uint64(b.Len())) + + if err != nil { + panic(err) + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + panic(err) + } +} + +type hostExt struct { + functions map[string]extension.InstallableFunc + host *Host +} + +func (he *hostExt) Init() map[string]extension.InstallableFunc { + return he.functions +} + +func (he *hostExt) Reset() { + // Reset any instances that have been created. + {{ range $ifc := .extension_schema.Interfaces }} + he.host.instances_{{ $ifc.Name }} = make(map[uint64]{{ $ifc.Name }}) + {{ end }} +} + +func New(impl Interface) extension.Extension { + hostWrapper := &Host{ impl: impl } + + fns := make(map[string]extension.InstallableFunc) + +// Add global functions to the runtime +{{ range $fn := .extension_schema.Functions }} + fns["ext_{{ $hash }}_{{ $fn.Name }}"] = hostWrapper.host_ext_{{ $hash }}_{{ $fn.Name }} +{{ end }} + +{{ range $ifc := .extension_schema.Interfaces }} + hostWrapper.instances_{{ $ifc.Name }} = make(map[uint64]{{ $ifc.Name }}) + + {{ range $fn := $ifc.Functions }} + + fns["ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}"] = hostWrapper.host_ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }} + + {{ end }} +{{ end }} + + return &hostExt{ + functions: fns, + host: hostWrapper, + } +} + +type Host struct { + impl Interface + {{ range $ifc := .extension_schema.Interfaces }} + gid_{{ $ifc.Name }} uint64 + instancesLock_{{ $ifc.Name }} sync.Mutex + instances_{{ $ifc.Name }} map[uint64]{{ $ifc.Name }} + {{ end }} +} + +// Global functions +{{ range $fn := .extension_schema.Functions }} + +func (h *Host) host_ext_{{ $hash }}_{{ $fn.Name}}(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &{{ $fn.Params }}{} + cd, err := Decode{{ $fn.Params }}(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + // Call the implementation + r, err := h.impl.{{ $fn.Name }}(cd) + if err!=nil { + hostError(mem, resize, err) + return + } + +{{- if (IsInterface $schema $fn.Return) }} + + id := atomic.AddUint64(&h.gid_{{ $fn.Return }}, 1) + h.instancesLock_{{ $fn.Return }}.Lock() + h.instances_{{ $fn.Return }}[id] = r + h.instancesLock_{{ $fn.Return }}.Unlock() + + // Return the ID + params[0] = id + +{{ else }} + + b := polyglot.NewBuffer() + r.Encode(b) + + writeBuffer, err := resize("ext_{{ $hash }}_Resize", uint64(b.Len())) + + if err != nil { + hostError(mem, resize, err) + return + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + hostError(mem, resize, err) + return + } + +{{ end }} +} + +{{ end }} + + +{{ range $ifc := .extension_schema.Interfaces }} + +{{ range $fn := $ifc.Functions }} + +func (h *Host) host_ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + h.instancesLock_{{ $ifc.Name }}.Lock() + r, ok := h.instances_{{ $ifc.Name }}[params[0]] + h.instancesLock_{{ $ifc.Name }}.Unlock() + if !ok { + hostError(mem, resize, errors.New("Instance ID not found!")) + return + } + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &{{ $fn.Params }}{} + cd, err := Decode{{ $fn.Params }}(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + resp, err := r.{{ $fn.Name }}(cd) + if err != nil { + hostError(mem, resize, err) + return + } + + +{{- if (IsInterface $schema $fn.Return) }} + + id := atomic.AddUint64(&h.gid_{{ $fn.Return }}, 1) + h.instancesLock_{{ $fn.Return }}.Lock() + h.instances_{{ $fn.Return }}[id] = resp + h.instancesLock_{{ $fn.Return }}.Unlock() + + // Return the ID + params[0] = id + +{{ else }} + + b := polyglot.NewBuffer() + resp.Encode(b) + + writeBuffer, err := resize("ext_{{ $hash }}_Resize", uint64(b.Len())) + + if err != nil { + hostError(mem, resize, err) + return + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + hostError(mem, resize, err) + return + } + +{{ end }} +} + + {{ end }} +{{ end }} \ No newline at end of file diff --git a/extension/generator/golang/templates/interfaces.go.templ b/extension/generator/golang/templates/interfaces.go.templ new file mode 100644 index 00000000..c0aca0ab --- /dev/null +++ b/extension/generator/golang/templates/interfaces.go.templ @@ -0,0 +1,19 @@ +// Code generated by scale-extension {{ .generator_version }}, DO NOT EDIT. +// output: {{ .package_name }} + +package {{ .package_name }} + +// Interface must be implemented by the host. +type Interface interface { + {{ range $fn := .extension_schema.Functions }} + {{ $fn.Name }}(params *{{ $fn.Params }}) ({{ $fn.Return }}, error) + {{ end }} +} + +{{ range $ifc := .extension_schema.Interfaces }} +type {{ $ifc.Name }} interface { + {{ range $fn := $ifc.Functions }} + {{ $fn.Name }}(*{{ $fn.Params }}) ({{ $fn.Return }}, error) + {{ end }} +} +{{ end }} diff --git a/extension/generator/golang/templates/mod.go.templ b/extension/generator/golang/templates/mod.go.templ new file mode 100644 index 00000000..85c10b0b --- /dev/null +++ b/extension/generator/golang/templates/mod.go.templ @@ -0,0 +1,8 @@ +module {{ .package_import_path }} + +go 1.20 + +require ( + github.com/loopholelabs/polyglot {{ .polyglot_version }} + github.com/loopholelabs/scale-extension-interfaces {{ .scale_extension_interfaces_version }} +) \ No newline at end of file diff --git a/extension/generator/golang/templates/templates.go b/extension/generator/golang/templates/templates.go new file mode 100644 index 00000000..fdfb581a --- /dev/null +++ b/extension/generator/golang/templates/templates.go @@ -0,0 +1,19 @@ +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package templates + +import "embed" + +//go:embed * +var FS embed.FS diff --git a/extension/generator/rust/generated.txt b/extension/generator/rust/generated.txt new file mode 100644 index 00000000..e9a141d6 --- /dev/null +++ b/extension/generator/rust/generated.txt @@ -0,0 +1,331 @@ +// Code generated by scale-extension 0.4.5, DO NOT EDIT. +// output: types + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] +use std::io::Cursor; +use polyglot_rs::{DecodingError, Encoder, Decoder, Kind}; +use num_enum::TryFromPrimitive; +use std::convert::TryFrom; +use std::collections::HashMap; +use regex::Regex; +pub trait Encode { + fn encode<'a>( + a: Option<&Self>, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> + where + Self: Sized; +} +trait EncodeSelf { + fn encode_self<'a, 'b>( + &'b self, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box>; +} +pub trait Decode { + fn decode( + b: &mut Cursor<&mut Vec>, + ) -> Result, Box> + where + Self: Sized; +} +#[derive(Clone, Debug, PartialEq)] +pub struct HttpConfig { + pub timeout: i32, +} +impl HttpConfig { + pub fn new() -> Self { + Self { timeout: 60 } + } +} +impl Encode for HttpConfig { + fn encode<'a>( + a: Option<&HttpConfig>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for HttpConfig { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_i32(self.timeout)?; + Ok(e) + } +} +impl EncodeSelf for Option<&HttpConfig> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for HttpConfig { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = HttpConfig::new(); + x.timeout = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct HttpResponse { + pub headers: HashMap, + pub status_code: i32, + pub body: Vec, +} +impl HttpResponse { + pub fn new() -> Self { + Self { + headers: HashMap::new(), + status_code: 0, + body: Vec::with_capacity(0), + } + } +} +impl Encode for HttpResponse { + fn encode<'a>( + a: Option<&HttpResponse>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for HttpResponse { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_map(self.headers.len(), Kind::String, Kind::Any)?; + for (k, v) in &self.headers { + e.encode_string(&k)?; + v.encode_self(e)?; + } + e.encode_i32(self.status_code)?; + e.encode_bytes(&self.body)?; + Ok(e) + } +} +impl EncodeSelf for Option<&HttpResponse> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for HttpResponse { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = HttpResponse::new(); + let size_headers = d.decode_map(Kind::String, Kind::Any)?; + for _ in 0..size_headers { + let k = d.decode_string()?; + let v = StringList::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.headers.insert(k, v); + } + x.status_code = d.decode_i32()?; + x.body = d.decode_bytes()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct StringList { + pub values: Vec, +} +impl StringList { + pub fn new() -> Self { + Self { + values: Vec::with_capacity(0), + } + } +} +impl Encode for StringList { + fn encode<'a>( + a: Option<&StringList>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for StringList { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_array(self.values.len(), Kind::String)?; + for a in &self.values { + e.encode_string(&a)?; + } + Ok(e) + } +} +impl EncodeSelf for Option<&StringList> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for StringList { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = StringList::new(); + let size_values = d.decode_array(Kind::String)?; + for _ in 0..size_values { + x.values.push(d.decode_string()?); + } + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ConnectionDetails { + pub url: String, +} +impl ConnectionDetails { + pub fn new() -> Self { + Self { + url: "https://google.com".to_string(), + } + } +} +impl Encode for ConnectionDetails { + fn encode<'a>( + a: Option<&ConnectionDetails>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ConnectionDetails { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.url)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ConnectionDetails> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ConnectionDetails { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ConnectionDetails::new(); + x.url = d.decode_string()?; + Ok(Some(x)) + } +} diff --git a/extension/generator/rust/generator.go b/extension/generator/rust/generator.go new file mode 100644 index 00000000..2f7bea5d --- /dev/null +++ b/extension/generator/rust/generator.go @@ -0,0 +1,282 @@ +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package rust + +import ( + "bytes" + "context" + "strings" + "text/template" + + "github.com/loopholelabs/scale/signature" + "github.com/loopholelabs/scale/signature/generator/rust" + + interfacesVersion "github.com/loopholelabs/scale-extension-interfaces/version" + + polyglotVersion "github.com/loopholelabs/polyglot/version" + + scaleVersion "github.com/loopholelabs/scale/version" + + polyglotUtils "github.com/loopholelabs/polyglot/utils" + + "github.com/loopholelabs/scale/extension" + "github.com/loopholelabs/scale/extension/generator/rust/templates" + "github.com/loopholelabs/scale/signature/generator/rust/format" + "github.com/loopholelabs/scale/signature/generator/utils" +) + +const ( + defaultPackageName = "types" +) + +var generator *Generator + +// GenerateTypes generates the types for the extension +func GenerateTypes(extensionSchema *extension.Schema, packageName string) ([]byte, error) { + return generator.GenerateTypes(extensionSchema, packageName) +} + +// GenerateCargofile generates the cargo.toml file for the extension +func GenerateCargofile(packageName string, packageVersion string) ([]byte, error) { + return generator.GenerateCargofile(packageName, packageVersion) +} + +func GenerateGuest(extensionSchema *extension.Schema, extensionHash string, packageName string) ([]byte, error) { + return generator.GenerateGuest(extensionSchema, extensionHash, packageName) +} + +func init() { + var err error + generator, err = New() + if err != nil { + panic(err) + } +} + +// Generator is the rust generator +type Generator struct { + templ *template.Template + signature *rust.Generator + formatter *format.Formatter +} + +// New creates a new rust generator +func New() (*Generator, error) { + templ, err := template.New("").Funcs(templateFunctions()).ParseFS(templates.FS, "*.rs.templ") + if err != nil { + return nil, err + } + + sig, err := rust.New() + if err != nil { + return nil, err + } + + formatter, err := format.New() + if err != nil { + return nil, err + } + + return &Generator{ + templ: templ, + signature: sig, + formatter: formatter, + }, nil +} + +// GenerateTypes generates the types for the extension +func (g *Generator) GenerateTypes(extensionSchema *extension.Schema, packageName string) ([]byte, error) { + signatureSchema := &signature.Schema{ + Version: extensionSchema.Version, + Enums: extensionSchema.Enums, + Models: extensionSchema.Models, + } + + signatureSchema.SetHasLengthValidator(extensionSchema.HasLengthValidator()) + signatureSchema.SetHasCaseModifier(extensionSchema.HasCaseModifier()) + signatureSchema.SetHasLimitValidator(extensionSchema.HasLimitValidator()) + signatureSchema.SetHasRegexValidator(extensionSchema.HasRegexValidator()) + + return g.signature.GenerateTypes(signatureSchema, packageName) +} + +// GenerateCargofile generates the cargofile for the extension +func (g *Generator) GenerateCargofile(packageName string, packageVersion string) ([]byte, error) { + buf := new(bytes.Buffer) + err := g.templ.ExecuteTemplate(buf, "cargo.rs.templ", map[string]any{ + "polyglot_version": strings.TrimPrefix(polyglotVersion.Version(), "v"), + "scale_signature_interfaces_version": strings.TrimPrefix(interfacesVersion.Version(), "v"), + "package_name": packageName, + "package_version": strings.TrimPrefix(packageVersion, "v"), + }) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +// GenerateGuest generates the guest bindings +func (g *Generator) GenerateGuest(extensionSchema *extension.Schema, extensionHash string, packageName string) ([]byte, error) { + if packageName == "" { + packageName = defaultPackageName + } + + buf := new(bytes.Buffer) + err := g.templ.ExecuteTemplate(buf, "guest.rs.templ", map[string]any{ + "extension_schema": extensionSchema, + "extension_hash": extensionHash, + }) + if err != nil { + return nil, err + } + + formatted, err := g.formatter.Format(context.Background(), buf.String()) + if err != nil { + return nil, err + } + buf.Reset() + err = g.templ.ExecuteTemplate(buf, "header.rs.templ", map[string]any{ + "generator_version": strings.TrimPrefix(scaleVersion.Version(), "v"), + "package_name": packageName, + }) + if err != nil { + return nil, err + } + return []byte(buf.String() + "\n\n" + formatted), nil +} + +func templateFunctions() template.FuncMap { + return template.FuncMap{ + "IsInterface": isInterface, + "Primitive": primitive, + "IsPrimitive": extension.ValidPrimitiveType, + "PolyglotPrimitive": polyglotPrimitive, + "PolyglotPrimitiveEncode": polyglotPrimitiveEncode, + "PolyglotPrimitiveDecode": polyglotPrimitiveDecode, + "Deref": func(i *bool) bool { return *i }, + "LowerFirst": func(s string) string { return string(s[0]+32) + s[1:] }, + "SnakeCase": polyglotUtils.SnakeCase, + "Params": utils.Params, + } +} + +func isInterface(schema *extension.Schema, s string) bool { + for _, i := range schema.Interfaces { + if i.Name == s { + return true + } + } + return false +} + +func primitive(t string) string { + switch t { + case "string": + return "String" + case "int32": + return "i32" + case "int64": + return "i64" + case "uint32": + return "u32" + case "uint64": + return "u64" + case "float32": + return "f32" + case "float64": + return "f64" + case "bool": + return "bool" + case "bytes": + return "Vec" + default: + return t + } +} + +func polyglotPrimitive(t string) string { + switch t { + case "string": + return "Kind::String" + case "int32": + return "Kind::I32" + case "int64": + return "Kind::I64" + case "uint32": + return "Kind::U32" + case "uint64": + return "Kind::U64" + case "float32": + return "Kind::F32" + case "float64": + return "Kind::F64" + case "bool": + return "Kind::Bool" + case "bytes": + return "Kind::Bytes" + default: + return "Kind::Any" + } +} + +func polyglotPrimitiveEncode(t string) string { + switch t { + case "string": + return "encode_string" + case "int32": + return "encode_i32" + case "int64": + return "encode_i64" + case "uint32": + return "encode_u32" + case "uint64": + return "encode_u64" + case "float32": + return "encode_f32" + case "float64": + return "encode_f64" + case "bool": + return "encode_bool" + case "bytes": + return "encode_bytes" + default: + return t + } +} + +func polyglotPrimitiveDecode(t string) string { + switch t { + case "string": + return "decode_string" + case "int32": + return "decode_i32" + case "int64": + return "decode_i64" + case "uint32": + return "decode_u32" + case "uint64": + return "decode_u64" + case "float32": + return "decode_f32" + case "float64": + return "decode_f64" + case "bool": + return "decode_bool" + case "bytes": + return "decode_bytes" + default: + return "" + } +} diff --git a/extension/generator/rust/generator_test.go b/extension/generator/rust/generator_test.go new file mode 100644 index 00000000..779c18a9 --- /dev/null +++ b/extension/generator/rust/generator_test.go @@ -0,0 +1,56 @@ +//go:build !integration && !generate + +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package rust + +import ( + "encoding/hex" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/loopholelabs/scale/extension" +) + +func TestGenerator(t *testing.T) { + s := new(extension.Schema) + err := s.Decode([]byte(extension.MasterTestingSchema)) + require.NoError(t, err) + + formatted, err := GenerateTypes(s, "types") + require.NoError(t, err) + + os.WriteFile("./generated.txt", formatted, 0644) + /* + master, err := os.ReadFile("./generated.txt") + require.NoError(t, err) + require.Equal(t, string(master), string(formatted)) + */ + t.Log(string(formatted)) + + sHash, err := s.Hash() + require.NoError(t, err) + + h := hex.EncodeToString(sHash) + + guest, err := GenerateGuest(s, h, "guest") + require.NoError(t, err) + os.WriteFile("./guest.txt", guest, 0644) + expGuest, err := os.ReadFile("./guest.txt") + require.NoError(t, err) + require.Equal(t, string(expGuest), string(guest)) + +} diff --git a/extension/generator/rust/guest.txt b/extension/generator/rust/guest.txt new file mode 100644 index 00000000..efc29a5f --- /dev/null +++ b/extension/generator/rust/guest.txt @@ -0,0 +1,183 @@ +// Code generated by scale-extension 0.4.5, DO NOT EDIT. +// output: guest + + + + + +pub mod types; +use crate::types::{Encode, Decode}; + +use std::io::Cursor; +use polyglot_rs::{Decoder, Encoder}; + +static HASH: &'static str = "0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe"; + +static mut READ_BUFFER: Vec = Vec::new(); +static mut WRITE_BUFFER: Vec = Vec::new(); + +// Interfaces + + + +// Interface for HttpConnector + +pub trait HttpConnector { + + + fn Fetch(&self, params: types::ConnectionDetails) -> Result, Box>; + + + +} + + + +// resize resizes the extensions READ_BUFFER to the given size and returns the pointer to the buffer +// +// Users should not use this method. +#[export_name = "ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize"] +#[no_mangle] +pub unsafe fn ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_Resize(size: u32) -> *const u8 { + READ_BUFFER.resize(size as usize, 0); + return READ_BUFFER.as_ptr(); +} + +// Define imports for instances + + + + +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch"] + fn _ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch(instance: u64, ptr: u32, size: u32) -> u64; +} + + + + +// All external interface functions defined. + +// Define any interfaces we need here... +// Also define structs we can use to hold instanceId + + + + +// Define concrete types with a hidden instanceId HttpConnector + +#[derive(Clone, Debug, PartialEq)] +pub struct _HttpConnector { + pub instanceId: u64, +} + +impl HttpConnector for _HttpConnector { + + +fn Fetch(&self, params: types::ConnectionDetails) -> Result, Box> { + + + unsafe { + + let mut cursor = Cursor::new(Vec::new()); + + types::ConnectionDetails::encode(Some(¶ms), &mut cursor); + + let vec = cursor.into_inner(); + + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + + // Now make the call to the host. + + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + _ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_HttpConnector_Fetch(self.instanceId, off, l); + // IF the return type is a model, we should read the data from the read buffer. + + let mut cursor = Cursor::new(&mut READ_BUFFER); + return types::HttpResponse::decode(&mut cursor) + + //return Ok(Some(c)) + + + } +} + + + +} + + + +// Define any global functions here... + + + +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New"] + fn _ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New(instance: u64, ptr: u32, size: u32) -> u64; +} +pub fn New(params: types::HttpConfig) -> Result, Box> { + + + unsafe { + + let mut cursor = Cursor::new(Vec::new()); + + types::HttpConfig::encode(Some(¶ms), &mut cursor); + + let vec = cursor.into_inner(); + + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + + // Now make the call to the host. + + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + READ_BUFFER.resize(0, 0); + let v = _ext_0673aeaed6f027b5bc7b4a79de1b4be4bc096366c1e406bf44face690c217cbe_New(0, off, l); + // IF the return type is an interface return ifc, which contains hidden instanceId. + + // Check for an error + if READ_BUFFER.len() > 0 { + // Read the error and return it... + let mut cursor = Cursor::new(&mut READ_BUFFER); + if let Ok(error) = cursor.decode_error() { + return Err(error); + } + } + + let c = _HttpConnector{ + instanceId: v, + }; + + return Ok(Some(c)); + + } +} + + + +// error serializes an error into the global WRITE_BUFFER and returns a pointer to the buffer and its size +// +// Users should not use this method. +pub unsafe fn error(error: Box) -> (u32, u32) { + let mut cursor = Cursor::new(Vec::new()); + return match cursor.encode_error(error) { + Ok(_) => { + let vec = cursor.into_inner(); + + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + + (WRITE_BUFFER.as_ptr() as u32, WRITE_BUFFER.len() as u32) + } + Err(_) => { + (0, 0) + } + }; +} diff --git a/extension/generator/rust/templates/cargo.rs.templ b/extension/generator/rust/templates/cargo.rs.templ new file mode 100644 index 00000000..efb7fa5f --- /dev/null +++ b/extension/generator/rust/templates/cargo.rs.templ @@ -0,0 +1,24 @@ +[package] +edition = "2021" +name = "{{ .package_name }}" +version = "{{ .package_version }}" + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 + +[lib] +path = "guest.rs" + +[dependencies.num_enum] +version = "0.7.0" + +[dependencies.regex] +version = "1.9.4" + +[dependencies.scale_signature_interfaces] +version = "{{ .scale_signature_interfaces_version }}" + +[dependencies.polyglot_rs] +version = "{{ .polyglot_version }}" diff --git a/extension/generator/rust/templates/guest.rs.templ b/extension/generator/rust/templates/guest.rs.templ new file mode 100644 index 00000000..b9377131 --- /dev/null +++ b/extension/generator/rust/templates/guest.rs.templ @@ -0,0 +1,213 @@ + +{{ $schema := .extension_schema }} +{{ $hash := .extension_hash }} + +pub mod types; +use crate::types::{Encode, Decode}; + +use std::io::Cursor; +use polyglot_rs::{Decoder, Encoder}; + +static HASH: &'static str = "{{ .extension_hash }}"; + +static mut READ_BUFFER: Vec = Vec::new(); +static mut WRITE_BUFFER: Vec = Vec::new(); + +// Interfaces + +{{ range $ifc := .extension_schema.Interfaces }} + +// Interface for {{ $ifc.Name }} + +pub trait {{ $ifc.Name }} { + +{{ range $fn := $ifc.Functions }} + +{{- if (IsInterface $schema $fn.Return) }} + fn {{ $fn.Name }}(&self, params: types::{{ $fn.Params }}) -> Result, Box>; +{{ else }} + fn {{ $fn.Name }}(&self, params: types::{{ $fn.Params }}) -> Result, Box>; +{{ end }} +{{ end }} + +} + +{{ end }} + +// resize resizes the extensions READ_BUFFER to the given size and returns the pointer to the buffer +// +// Users should not use this method. +#[export_name = "ext_{{ $hash }}_Resize"] +#[no_mangle] +pub unsafe fn ext_{{ $hash }}_Resize(size: u32) -> *const u8 { + READ_BUFFER.resize(size as usize, 0); + return READ_BUFFER.as_ptr(); +} + +// Define imports for instances + +{{ range $ifc := .extension_schema.Interfaces }} +{{ range $fn := $ifc.Functions }} + +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}"] + fn _ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(instance: u64, ptr: u32, size: u32) -> u64; +} + +{{ end }} +{{ end }} + +// All external interface functions defined. + +// Define any interfaces we need here... +// Also define structs we can use to hold instanceId + + +{{ range $ifc := .extension_schema.Interfaces }} + +// Define concrete types with a hidden instanceId {{ $ifc.Name }} + +#[derive(Clone, Debug, PartialEq)] +pub struct _{{ $ifc.Name }} { + pub instanceId: u64, +} + +impl {{ $ifc.Name }} for _{{ $ifc.Name }} { + +{{ range $fn := $ifc.Functions }} + +{{- if (IsInterface $schema $fn.Return) }} +fn {{ $fn.Name }}(&self, params: types::{{ $fn.Params }}) -> Result, Box> { +{{ else }} +fn {{ $fn.Name }}(&self, params: types::{{ $fn.Params }}) -> Result, Box> { +{{ end }} + + unsafe { + + let mut cursor = Cursor::new(Vec::new()); + + types::{{ $fn.Params }}::encode(Some(¶ms), &mut cursor); + + let vec = cursor.into_inner(); + + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + + // Now make the call to the host. + + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + + {{- if (IsInterface $schema $fn.Return) }} + let v = _ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(self.instanceId, off, l); + // IF the return type is an interface return ifc, which contains hidden instanceId. + + let c = _{{ $fn.Return }}{ + instanceId: v, + }; + + return Ok(Some(c)); + {{ else }} + _ext_{{ $hash }}_{{ $ifc.Name }}_{{ $fn.Name }}(self.instanceId, off, l); + // IF the return type is a model, we should read the data from the read buffer. + + let mut cursor = Cursor::new(&mut READ_BUFFER); + return types::{{ $fn.Return }}::decode(&mut cursor) + + //return Ok(Some(c)) + {{ end }} + + } +} + +{{ end }} + +} + +{{ end }} + +// Define any global functions here... + +{{ range $fn := .extension_schema.Functions }} + +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_{{ $hash }}_{{ $fn.Name }}"] + fn _ext_{{ $hash }}_{{ $fn.Name }}(instance: u64, ptr: u32, size: u32) -> u64; +} + +{{- if (IsInterface $schema $fn.Return) }} +pub fn {{ $fn.Name }}(params: types::{{ $fn.Params }}) -> Result, Box> { +{{ else }} +pub fn {{ $fn.Name }}(params: types::{{ $fn.Params }}) -> Result, Box> { +{{ end }} + + unsafe { + + let mut cursor = Cursor::new(Vec::new()); + + types::{{ $fn.Params }}::encode(Some(¶ms), &mut cursor); + + let vec = cursor.into_inner(); + + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + + // Now make the call to the host. + + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + + {{- if (IsInterface $schema $fn.Return) }} + READ_BUFFER.resize(0, 0); + let v = _ext_{{ $hash }}_{{ $fn.Name }}(0, off, l); + // IF the return type is an interface return ifc, which contains hidden instanceId. + + // Check for an error + if READ_BUFFER.len() > 0 { + // Read the error and return it... + let mut cursor = Cursor::new(&mut READ_BUFFER); + if let Ok(error) = cursor.decode_error() { + return Err(error); + } + } + + let c = _{{ $fn.Return }}{ + instanceId: v, + }; + + return Ok(Some(c)); + {{ else }} + _ext_{{ $hash }}_{{ $fn.Name }}(0, off, l); + // IF the return type is a model, we should read the data from the read buffer. + + let mut cursor = Cursor::new(&mut READ_BUFFER); + return types::{{ $fn.Return }}::decode(&mut cursor) + + //return Ok(Some(c)) + {{ end }} + } +} + +{{ end }} + +// error serializes an error into the global WRITE_BUFFER and returns a pointer to the buffer and its size +// +// Users should not use this method. +pub unsafe fn error(error: Box) -> (u32, u32) { + let mut cursor = Cursor::new(Vec::new()); + return match cursor.encode_error(error) { + Ok(_) => { + let vec = cursor.into_inner(); + + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + + (WRITE_BUFFER.as_ptr() as u32, WRITE_BUFFER.len() as u32) + } + Err(_) => { + (0, 0) + } + }; +} diff --git a/extension/generator/rust/templates/header.rs.templ b/extension/generator/rust/templates/header.rs.templ new file mode 100644 index 00000000..1c34c88c --- /dev/null +++ b/extension/generator/rust/templates/header.rs.templ @@ -0,0 +1,2 @@ +// Code generated by scale-extension {{ .generator_version }}, DO NOT EDIT. +// output: {{ .package_name }} \ No newline at end of file diff --git a/extension/generator/rust/templates/templates.go b/extension/generator/rust/templates/templates.go new file mode 100644 index 00000000..fdfb581a --- /dev/null +++ b/extension/generator/rust/templates/templates.go @@ -0,0 +1,19 @@ +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package templates + +import "embed" + +//go:embed * +var FS embed.FS diff --git a/extension/info.go b/extension/info.go new file mode 100644 index 00000000..029535b9 --- /dev/null +++ b/extension/info.go @@ -0,0 +1,8 @@ +package extension + +type Info struct { + Name string + Path string + Version string + Package string +} diff --git a/go.mod b/go.mod index 6e5acfcb..ce535126 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/kr/pretty v0.3.1 // indirect + github.com/loopholelabs/scale-extension-interfaces v0.0.0-20230920094333-3a483b301bf4 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/zclconf/go-cty v1.14.1 // indirect diff --git a/go.sum b/go.sum index f7fa8f82..6869df9e 100644 --- a/go.sum +++ b/go.sum @@ -28,6 +28,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= github.com/loopholelabs/polyglot v1.1.3 h1:WUTcSZ2TQ1lv7CZ4I9nHFBUjf0hKJN+Yfz1rZZJuTP0= github.com/loopholelabs/polyglot v1.1.3/go.mod h1:EA88BEkIluKHAWxhyOV88xXz68YkRdo9IzZ+1dj+7Ao= +github.com/loopholelabs/scale-extension-interfaces v0.0.0-20230920094333-3a483b301bf4 h1:leEQ1uJgTcyKdJojndhZRBAbOxcUz3u5Ol05Kz6tedQ= +github.com/loopholelabs/scale-extension-interfaces v0.0.0-20230920094333-3a483b301bf4/go.mod h1:/qjvg9RglZaRhw3cE+dj6AaZRYHCOR+ohuZX8MSxD8E= github.com/loopholelabs/scale-signature-interfaces v0.1.7 h1:aOJJZpCKn/Q5Q0Gj+/Q6c7/iABEbojjbCzIqw7Mxyi0= github.com/loopholelabs/scale-signature-interfaces v0.1.7/go.mod h1:3XLMjJjBf5lYxMtNKk+2XAWye4UyrkvUBJ9L6x2QCAk= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= diff --git a/instance.go b/instance.go index 11083116..778c6aa3 100644 --- a/instance.go +++ b/instance.go @@ -80,6 +80,8 @@ func newInstance[T interfaces.Signature](ctx context.Context, runtime *Scale[T], } func (i *Instance[T]) Run(ctx context.Context, signature T) error { + i.runtime.resetExtensions() + m, err := i.head.getModule(signature) if err != nil { return fmt.Errorf("failed to get module for function '%s': %w", i.head.template.identifier, err) diff --git a/integration/generate_ext_test.go b/integration/generate_ext_test.go new file mode 100644 index 00000000..fd4672ec --- /dev/null +++ b/integration/generate_ext_test.go @@ -0,0 +1,104 @@ +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/loopholelabs/scale/extension" + "github.com/loopholelabs/scale/extension/generator" +) + +const extensionSchema = ` version = "v1alpha" + +function New { + params = "stringval" + return = "Example" +} + +interface Example { + function Hello { + params = "stringval" + return = "stringval" + } +} + +function World { + params = "stringval" + return = "stringval" +} + +model stringval { + string value { + default = "" + } +} +` + +func TestGenerateExtensionTestingSchema(t *testing.T) { + wd, err := os.Getwd() + require.NoError(t, err) + + s := new(extension.Schema) + err = s.Decode([]byte(extensionSchema)) + require.NoError(t, err) + + guest, err := generator.GenerateGuestLocal(&generator.Options{ + Extension: s, + + GolangPackageImportPath: "extension", + GolangPackageName: "local_inttest_latest_guest", + + RustPackageName: "local_inttest_latest_guest", + RustPackageVersion: "v0.1.0", + + TypescriptPackageName: "local_inttest_latest_guest", + TypescriptPackageVersion: "v0.1.0", + }) + require.NoError(t, err) + + golangExtensionDir := wd + "/golang_ext_tests/extension" + for _, file := range guest.GolangFiles { + err = os.WriteFile(golangExtensionDir+"/"+file.Name(), file.Data(), 0644) + require.NoError(t, err) + } + + rustExtensionDir := wd + "/rust_ext_tests/extension" + for _, file := range guest.RustFiles { + err = os.WriteFile(rustExtensionDir+"/"+file.Name(), file.Data(), 0644) + require.NoError(t, err) + } + + host, err := generator.GenerateHostLocal(&generator.Options{ + Extension: s, + + GolangPackageImportPath: "extension", + GolangPackageName: "local_inttest_latest_guest", + + TypescriptPackageName: "local-example-latest-host", + TypescriptPackageVersion: "v0.1.0", + }) + require.NoError(t, err) + + golangExtensionDir = wd + "/golang_ext_tests/host_extension" + for _, file := range host.GolangFiles { + if file.Name() != "go.mod" { + err = os.WriteFile(golangExtensionDir+"/"+file.Name(), file.Data(), 0644) + require.NoError(t, err) + } + } +} diff --git a/integration/golang_ext_tests/extension/go.mod b/integration/golang_ext_tests/extension/go.mod new file mode 100644 index 00000000..435a5477 --- /dev/null +++ b/integration/golang_ext_tests/extension/go.mod @@ -0,0 +1,5 @@ +module local_inttest_latest_guest + +go 1.20 + +require github.com/loopholelabs/polyglot v1.1.3 diff --git a/integration/golang_ext_tests/extension/go.sum b/integration/golang_ext_tests/extension/go.sum new file mode 100644 index 00000000..8364bc2b --- /dev/null +++ b/integration/golang_ext_tests/extension/go.sum @@ -0,0 +1,6 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/loopholelabs/polyglot v1.1.3 h1:WUTcSZ2TQ1lv7CZ4I9nHFBUjf0hKJN+Yfz1rZZJuTP0= +github.com/loopholelabs/polyglot v1.1.3/go.mod h1:EA88BEkIluKHAWxhyOV88xXz68YkRdo9IzZ+1dj+7Ao= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/integration/golang_ext_tests/extension/guest.go b/integration/golang_ext_tests/extension/guest.go new file mode 100644 index 00000000..f3c7d658 --- /dev/null +++ b/integration/golang_ext_tests/extension/guest.go @@ -0,0 +1,143 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +package local_inttest_latest_guest + +import ( + "github.com/loopholelabs/polyglot" + "unsafe" +) + +var ( + writeBuffer = polyglot.NewBuffer() + readBuffer []byte +) + +//export ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize +//go:linkname ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize +func ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize(size uint32) uint32 { + readBuffer = make([]byte, size) + //if uint32(cap(readBuffer)) < size { + // readBuffer = append(make([]byte, 0, uint32(len(readBuffer))+size), readBuffer...) + //} + //readBuffer = readBuffer[:size] + return uint32(uintptr(unsafe.Pointer(&readBuffer[0]))) +} + +// Define any interfaces we need here... +// Also define structs we can use to hold instanceId + +// Define concrete types with a hidden instanceId + +type _Example struct { + instanceId uint64 +} + +func (d *_Example) Hello(params *Stringval) (Stringval, error) { + + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello(d.instanceId, off, l) + // IF the return type is a model, we should read the data from the read buffer. + + ret := &Stringval{} + r, err := DecodeStringval(ret, readBuffer) + + if err != nil { + return Stringval{}, err + } + + return *r, err + +} + +//export ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello +//go:linkname ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello +func ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello(instance uint64, offset uint32, length uint32) uint64 + +// Define any global functions here... + +//export ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New +//go:linkname ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New +func ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New(instance uint64, offset uint32, length uint32) uint64 + +func New(params *Stringval) (Example, error) { + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + readBuffer = nil + v := ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New(0, off, l) + // IF the return type is an interface return ifc, which contains hidden instanceId. + + // Handle error from host. In this case there'll be an error in the readBuffer + if readBuffer != nil { + val, err := polyglot.GetDecoder(readBuffer).Error() + if err != nil { + panic(err) + } + return nil, val + } + + ret := &_Example{ + instanceId: v, + } + + return ret, nil + +} + +//export ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World +//go:linkname ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World +func ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World(instance uint64, offset uint32, length uint32) uint64 + +func World(params *Stringval) (Stringval, error) { + // First we take the params, serialize them. + writeBuffer.Reset() + params.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + off := uint32(unsafePtr) + l := uint32(writeBuffer.Len()) + + // Now make the call to the host. + ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World(0, off, l) + // IF the return type is a model, we should read the data from the read buffer. + + ret := &Stringval{} + r, err := DecodeStringval(ret, readBuffer) + + if err != nil { + return Stringval{}, err + } + + return *r, err + +} + +// Error serializes an error into the global writeBuffer and returns a pointer to the buffer and its size +// +// Users should not use this method. +func Error(err error) (uint32, uint32) { + writeBuffer.Reset() + polyglot.Encoder(writeBuffer).Error(err) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + return uint32(unsafePtr), uint32(writeBuffer.Len()) +} diff --git a/integration/golang_ext_tests/extension/interfaces.go b/integration/golang_ext_tests/extension/interfaces.go new file mode 100644 index 00000000..64c4f55c --- /dev/null +++ b/integration/golang_ext_tests/extension/interfaces.go @@ -0,0 +1,15 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +package local_inttest_latest_guest + +// Interface must be implemented by the host. +type Interface interface { + New(params *Stringval) (Example, error) + + World(params *Stringval) (Stringval, error) +} + +type Example interface { + Hello(*Stringval) (Stringval, error) +} diff --git a/integration/golang_ext_tests/extension/types.go b/integration/golang_ext_tests/extension/types.go new file mode 100644 index 00000000..93a867cc --- /dev/null +++ b/integration/golang_ext_tests/extension/types.go @@ -0,0 +1,64 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +package local_inttest_latest_guest + +import ( + "errors" + "github.com/loopholelabs/polyglot" +) + +var ( + NilDecode = errors.New("cannot decode into a nil root struct") + InvalidEnum = errors.New("invalid enum value") +) + +type Stringval struct { + Value string +} + +func NewStringval() *Stringval { + return &Stringval{ + + Value: "", + } +} + +func (x *Stringval) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.Value) + + } +} + +func DecodeStringval(x *Stringval, b []byte) (*Stringval, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeStringval(x, d) +} + +func _decodeStringval(x *Stringval, d *polyglot.Decoder) (*Stringval, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewStringval() + } + + x.Value, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} diff --git a/integration/golang_ext_tests/function/example.go b/integration/golang_ext_tests/function/example.go new file mode 100644 index 00000000..99923e33 --- /dev/null +++ b/integration/golang_ext_tests/function/example.go @@ -0,0 +1,45 @@ +/* + Copyright 2023 Loophole Labs + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package example + +import ( + extension "extension" + "fmt" + "signature" +) + +func Example(ctx *signature.ModelWithAllFieldTypes) (*signature.ModelWithAllFieldTypes, error) { + fmt.Printf("This is a Golang Function, which calls an extension.") + + v, err := extension.New(&extension.Stringval{Value: ""}) + if err != nil { + return nil, err + } + hello, err := v.Hello(&extension.Stringval{Value: ""}) + if err != nil { + return nil, err + } + world, err := extension.World(&extension.Stringval{Value: ""}) + if err != nil { + return nil, err + } + + if ctx != nil { + ctx.StringField = fmt.Sprintf("This is a Golang Function. Extension New().Hello()=%s World()=%s", hello.Value, world.Value) + } + return signature.Next(ctx) +} diff --git a/integration/golang_ext_tests/function/go.mod b/integration/golang_ext_tests/function/go.mod new file mode 100644 index 00000000..1ba5f8ef --- /dev/null +++ b/integration/golang_ext_tests/function/go.mod @@ -0,0 +1,13 @@ +module example + +go 1.20 + +replace signature => ../signature + +replace extension => ../extension + +require signature v0.1.0 + +require extension v0.1.0 + +require github.com/loopholelabs/polyglot v1.1.3 // indirect diff --git a/integration/golang_ext_tests/function/go.sum b/integration/golang_ext_tests/function/go.sum new file mode 100644 index 00000000..8364bc2b --- /dev/null +++ b/integration/golang_ext_tests/function/go.sum @@ -0,0 +1,6 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/loopholelabs/polyglot v1.1.3 h1:WUTcSZ2TQ1lv7CZ4I9nHFBUjf0hKJN+Yfz1rZZJuTP0= +github.com/loopholelabs/polyglot v1.1.3/go.mod h1:EA88BEkIluKHAWxhyOV88xXz68YkRdo9IzZ+1dj+7Ao= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/integration/golang_ext_tests/generated/generated.go b/integration/golang_ext_tests/generated/generated.go new file mode 100644 index 00000000..ea77888b --- /dev/null +++ b/integration/golang_ext_tests/generated/generated.go @@ -0,0 +1,78 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: generated + +package generated + +import ( + "errors" + "github.com/loopholelabs/polyglot" +) + +var ( + NilDecode = errors.New("cannot decode into a nil root struct") + InvalidEnum = errors.New("invalid enum value") +) + +type Context struct { + A int32 + B int32 + C int32 +} + +func NewContext() *Context { + return &Context{ + + A: 0, + B: 0, + C: 0, + } +} + +func (x *Context) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Int32(x.A) + e.Int32(x.B) + e.Int32(x.C) + + } +} + +func DecodeContext(x *Context, b []byte) (*Context, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeContext(x, d) +} + +func _decodeContext(x *Context, d *polyglot.Decoder) (*Context, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewContext() + } + + x.A, err = d.Int32() + if err != nil { + return nil, err + } + x.B, err = d.Int32() + if err != nil { + return nil, err + } + x.C, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} diff --git a/integration/golang_ext_tests/host_extension/host.go b/integration/golang_ext_tests/host_extension/host.go new file mode 100644 index 00000000..920d971f --- /dev/null +++ b/integration/golang_ext_tests/host_extension/host.go @@ -0,0 +1,186 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +package local_inttest_latest_guest + +import ( + "errors" + "sync" + "sync/atomic" + + "github.com/loopholelabs/polyglot" + extension "github.com/loopholelabs/scale-extension-interfaces" +) + +// Write an error to the scale function guest buffer. +func hostError(mem extension.ModuleMemory, resize extension.Resizer, err error) { + b := polyglot.NewBuffer() + polyglot.Encoder(b).Error(err) + + writeBuffer, err := resize("ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize", uint64(b.Len())) + + if err != nil { + panic(err) + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + panic(err) + } +} + +type hostExt struct { + functions map[string]extension.InstallableFunc + host *Host +} + +func (he *hostExt) Init() map[string]extension.InstallableFunc { + return he.functions +} + +func (he *hostExt) Reset() { + // Reset any instances that have been created. + + he.host.instances_Example = make(map[uint64]Example) + +} + +func New(impl Interface) extension.Extension { + hostWrapper := &Host{impl: impl} + + fns := make(map[string]extension.InstallableFunc) + + // Add global functions to the runtime + + fns["ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New"] = hostWrapper.host_ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New + + fns["ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World"] = hostWrapper.host_ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World + + hostWrapper.instances_Example = make(map[uint64]Example) + + fns["ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello"] = hostWrapper.host_ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello + + return &hostExt{ + functions: fns, + host: hostWrapper, + } +} + +type Host struct { + impl Interface + + gid_Example uint64 + instancesLock_Example sync.Mutex + instances_Example map[uint64]Example +} + +// Global functions + +func (h *Host) host_ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &Stringval{} + cd, err := DecodeStringval(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + // Call the implementation + r, err := h.impl.New(cd) + if err != nil { + hostError(mem, resize, err) + return + } + + id := atomic.AddUint64(&h.gid_Example, 1) + h.instancesLock_Example.Lock() + h.instances_Example[id] = r + h.instancesLock_Example.Unlock() + + // Return the ID + params[0] = id + +} + +func (h *Host) host_ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &Stringval{} + cd, err := DecodeStringval(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + // Call the implementation + r, err := h.impl.World(cd) + if err != nil { + hostError(mem, resize, err) + return + } + + b := polyglot.NewBuffer() + r.Encode(b) + + writeBuffer, err := resize("ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize", uint64(b.Len())) + + if err != nil { + hostError(mem, resize, err) + return + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + hostError(mem, resize, err) + return + } + +} + +func (h *Host) host_ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello(mem extension.ModuleMemory, resize extension.Resizer, params []uint64) { + h.instancesLock_Example.Lock() + r, ok := h.instances_Example[params[0]] + h.instancesLock_Example.Unlock() + if !ok { + hostError(mem, resize, errors.New("Instance ID not found!")) + return + } + + ptr := uint32(params[1]) + length := uint32(params[2]) + data, _ := mem.Read(ptr, length) + + cd := &Stringval{} + cd, err := DecodeStringval(cd, data) + if err != nil { + hostError(mem, resize, err) + return + } + + resp, err := r.Hello(cd) + if err != nil { + hostError(mem, resize, err) + return + } + + b := polyglot.NewBuffer() + resp.Encode(b) + + writeBuffer, err := resize("ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize", uint64(b.Len())) + + if err != nil { + hostError(mem, resize, err) + return + } + + if !mem.Write(uint32(writeBuffer), b.Bytes()) { + hostError(mem, resize, err) + return + } + +} diff --git a/integration/golang_ext_tests/host_extension/interfaces.go b/integration/golang_ext_tests/host_extension/interfaces.go new file mode 100644 index 00000000..64c4f55c --- /dev/null +++ b/integration/golang_ext_tests/host_extension/interfaces.go @@ -0,0 +1,15 @@ +// Code generated by scale-extension v0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +package local_inttest_latest_guest + +// Interface must be implemented by the host. +type Interface interface { + New(params *Stringval) (Example, error) + + World(params *Stringval) (Stringval, error) +} + +type Example interface { + Hello(*Stringval) (Stringval, error) +} diff --git a/integration/golang_ext_tests/host_extension/types.go b/integration/golang_ext_tests/host_extension/types.go new file mode 100644 index 00000000..93a867cc --- /dev/null +++ b/integration/golang_ext_tests/host_extension/types.go @@ -0,0 +1,64 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +package local_inttest_latest_guest + +import ( + "errors" + "github.com/loopholelabs/polyglot" +) + +var ( + NilDecode = errors.New("cannot decode into a nil root struct") + InvalidEnum = errors.New("invalid enum value") +) + +type Stringval struct { + Value string +} + +func NewStringval() *Stringval { + return &Stringval{ + + Value: "", + } +} + +func (x *Stringval) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.Value) + + } +} + +func DecodeStringval(x *Stringval, b []byte) (*Stringval, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeStringval(x, d) +} + +func _decodeStringval(x *Stringval, d *polyglot.Decoder) (*Stringval, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewStringval() + } + + x.Value, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} diff --git a/integration/golang_ext_tests/host_signature/host.go b/integration/golang_ext_tests/host_signature/host.go new file mode 100644 index 00000000..1e56f80d --- /dev/null +++ b/integration/golang_ext_tests/host_signature/host.go @@ -0,0 +1,66 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: signature + +package signature + +import ( + "github.com/loopholelabs/polyglot" + interfaces "github.com/loopholelabs/scale-signature-interfaces" +) + +const hash = "3a592aa345d412faa2e6285ee048ca2ab5aa64b0caa2f9ca67b2c1e0792101e5" + +var _ interfaces.Signature = (*Signature)(nil) + +// Signature is the host representation of the signature +// +// Users should not use this type directly, but instead pass the New() function +// to the Scale Runtime +type Signature struct { + Context *ModelWithAllFieldTypes + buf *polyglot.Buffer +} + +// New returns a new signature and tells the Scale Runtime how to use it +// +// This function should be passed into the scale runtime config as an argument +func New() *Signature { + return &Signature{ + Context: NewModelWithAllFieldTypes(), + buf: polyglot.NewBuffer(), + } +} + +// Read reads the context from the given byte slice and returns an error if one occurred +// +// This method is meant to be used by the Scale Runtime to deserialize the Signature +func (x *Signature) Read(b []byte) error { + var err error + x.Context, err = DecodeModelWithAllFieldTypes(x.Context, b) + return err +} + +// Write writes the signature into a byte slice and returns it +// +// This method is meant to be used by the Scale Runtime to serialize the Signature +func (x *Signature) Write() []byte { + x.buf.Reset() + x.Context.Encode(x.buf) + return x.buf.Bytes() +} + +// Error writes the signature into a byte slice and returns it +// +// This method is meant to be used by the Scale Runtime to return an error +func (x *Signature) Error(err error) []byte { + x.buf.Reset() + polyglot.Encoder(x.buf).Error(err) + return x.buf.Bytes() +} + +// Hash returns the hash of the signature +// +// This method is meant to be used by the Scale Runtime to validate Signature and Function compatibility +func (x *Signature) Hash() string { + return hash +} diff --git a/integration/golang_ext_tests/host_signature/types.go b/integration/golang_ext_tests/host_signature/types.go new file mode 100644 index 00000000..d501e529 --- /dev/null +++ b/integration/golang_ext_tests/host_signature/types.go @@ -0,0 +1,1874 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: signature + +package signature + +import ( + "errors" + "github.com/loopholelabs/polyglot" +) + +var ( + NilDecode = errors.New("cannot decode into a nil root struct") + InvalidEnum = errors.New("invalid enum value") +) + +type GenericEnum uint32 + +const ( + GenericEnumFirstValue GenericEnum = 0 + + GenericEnumSecondValue GenericEnum = 1 + + GenericEnumDefaultValue GenericEnum = 2 +) + +func decodeGenericEnum(d *polyglot.Decoder) (GenericEnum, error) { + enumValue, err := d.Uint32() + if err != nil { + return 0, err + } + switch GenericEnum(enumValue) { + case GenericEnumFirstValue: + return GenericEnumFirstValue, nil + case GenericEnumSecondValue: + return GenericEnumSecondValue, nil + case GenericEnumDefaultValue: + return GenericEnumDefaultValue, nil + default: + return 0, InvalidEnum + } +} + +type EmptyModel struct { +} + +func NewEmptyModel() *EmptyModel { + return &EmptyModel{} +} + +func (x *EmptyModel) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + } +} + +func DecodeEmptyModel(x *EmptyModel, b []byte) (*EmptyModel, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeEmptyModel(x, d) +} + +func _decodeEmptyModel(x *EmptyModel, d *polyglot.Decoder) (*EmptyModel, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewEmptyModel() + } + + return x, nil +} + +// EmptyModelWithDescription: Test Description +type EmptyModelWithDescription struct { +} + +func NewEmptyModelWithDescription() *EmptyModelWithDescription { + return &EmptyModelWithDescription{} +} + +func (x *EmptyModelWithDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + } +} + +func DecodeEmptyModelWithDescription(x *EmptyModelWithDescription, b []byte) (*EmptyModelWithDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeEmptyModelWithDescription(x, d) +} + +func _decodeEmptyModelWithDescription(x *EmptyModelWithDescription, d *polyglot.Decoder) (*EmptyModelWithDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewEmptyModelWithDescription() + } + + return x, nil +} + +type ModelWithSingleStringField struct { + StringField string +} + +func NewModelWithSingleStringField() *ModelWithSingleStringField { + return &ModelWithSingleStringField{ + + StringField: "DefaultValue", + } +} + +func (x *ModelWithSingleStringField) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + } +} + +func DecodeModelWithSingleStringField(x *ModelWithSingleStringField, b []byte) (*ModelWithSingleStringField, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleStringField(x, d) +} + +func _decodeModelWithSingleStringField(x *ModelWithSingleStringField, d *polyglot.Decoder) (*ModelWithSingleStringField, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleStringField() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithSingleStringFieldAndDescription: Test Description +type ModelWithSingleStringFieldAndDescription struct { + StringField string +} + +func NewModelWithSingleStringFieldAndDescription() *ModelWithSingleStringFieldAndDescription { + return &ModelWithSingleStringFieldAndDescription{ + + StringField: "DefaultValue", + } +} + +func (x *ModelWithSingleStringFieldAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + } +} + +func DecodeModelWithSingleStringFieldAndDescription(x *ModelWithSingleStringFieldAndDescription, b []byte) (*ModelWithSingleStringFieldAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleStringFieldAndDescription(x, d) +} + +func _decodeModelWithSingleStringFieldAndDescription(x *ModelWithSingleStringFieldAndDescription, d *polyglot.Decoder) (*ModelWithSingleStringFieldAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleStringFieldAndDescription() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithSingleInt32Field struct { + Int32Field int32 +} + +func NewModelWithSingleInt32Field() *ModelWithSingleInt32Field { + return &ModelWithSingleInt32Field{ + + Int32Field: 32, + } +} + +func (x *ModelWithSingleInt32Field) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithSingleInt32Field(x *ModelWithSingleInt32Field, b []byte) (*ModelWithSingleInt32Field, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleInt32Field(x, d) +} + +func _decodeModelWithSingleInt32Field(x *ModelWithSingleInt32Field, d *polyglot.Decoder) (*ModelWithSingleInt32Field, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleInt32Field() + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithSingleInt32FieldAndDescription: Test Description +type ModelWithSingleInt32FieldAndDescription struct { + Int32Field int32 +} + +func NewModelWithSingleInt32FieldAndDescription() *ModelWithSingleInt32FieldAndDescription { + return &ModelWithSingleInt32FieldAndDescription{ + + Int32Field: 32, + } +} + +func (x *ModelWithSingleInt32FieldAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithSingleInt32FieldAndDescription(x *ModelWithSingleInt32FieldAndDescription, b []byte) (*ModelWithSingleInt32FieldAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleInt32FieldAndDescription(x, d) +} + +func _decodeModelWithSingleInt32FieldAndDescription(x *ModelWithSingleInt32FieldAndDescription, d *polyglot.Decoder) (*ModelWithSingleInt32FieldAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleInt32FieldAndDescription() + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithMultipleFields struct { + StringField string + + Int32Field int32 +} + +func NewModelWithMultipleFields() *ModelWithMultipleFields { + return &ModelWithMultipleFields{ + + StringField: "DefaultValue", + + Int32Field: 32, + } +} + +func (x *ModelWithMultipleFields) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithMultipleFields(x *ModelWithMultipleFields, b []byte) (*ModelWithMultipleFields, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFields(x, d) +} + +func _decodeModelWithMultipleFields(x *ModelWithMultipleFields, d *polyglot.Decoder) (*ModelWithMultipleFields, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFields() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithMultipleFieldsAndDescription: Test Description +type ModelWithMultipleFieldsAndDescription struct { + StringField string + + Int32Field int32 +} + +func NewModelWithMultipleFieldsAndDescription() *ModelWithMultipleFieldsAndDescription { + return &ModelWithMultipleFieldsAndDescription{ + + StringField: "DefaultValue", + + Int32Field: 32, + } +} + +func (x *ModelWithMultipleFieldsAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithMultipleFieldsAndDescription(x *ModelWithMultipleFieldsAndDescription, b []byte) (*ModelWithMultipleFieldsAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFieldsAndDescription(x, d) +} + +func _decodeModelWithMultipleFieldsAndDescription(x *ModelWithMultipleFieldsAndDescription, d *polyglot.Decoder) (*ModelWithMultipleFieldsAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFieldsAndDescription() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithEnum struct { + EnumField GenericEnum +} + +func NewModelWithEnum() *ModelWithEnum { + return &ModelWithEnum{ + + EnumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnum) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.EnumField)) + + } +} + +func DecodeModelWithEnum(x *ModelWithEnum, b []byte) (*ModelWithEnum, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnum(x, d) +} + +func _decodeModelWithEnum(x *ModelWithEnum, d *polyglot.Decoder) (*ModelWithEnum, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnum() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + return x, nil +} + +// ModelWithEnumAndDescription: Test Description +type ModelWithEnumAndDescription struct { + EnumField GenericEnum +} + +func NewModelWithEnumAndDescription() *ModelWithEnumAndDescription { + return &ModelWithEnumAndDescription{ + + EnumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnumAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.EnumField)) + + } +} + +func DecodeModelWithEnumAndDescription(x *ModelWithEnumAndDescription, b []byte) (*ModelWithEnumAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnumAndDescription(x, d) +} + +func _decodeModelWithEnumAndDescription(x *ModelWithEnumAndDescription, d *polyglot.Decoder) (*ModelWithEnumAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnumAndDescription() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + return x, nil +} + +type ModelWithEnumAccessor struct { + EnumField GenericEnum +} + +func NewModelWithEnumAccessor() *ModelWithEnumAccessor { + return &ModelWithEnumAccessor{ + + EnumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnumAccessor) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.EnumField)) + + } +} + +func DecodeModelWithEnumAccessor(x *ModelWithEnumAccessor, b []byte) (*ModelWithEnumAccessor, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnumAccessor(x, d) +} + +func _decodeModelWithEnumAccessor(x *ModelWithEnumAccessor, d *polyglot.Decoder) (*ModelWithEnumAccessor, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnumAccessor() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + return x, nil +} + +// ModelWithEnumAccessorAndDescription: Test Description +type ModelWithEnumAccessorAndDescription struct { + EnumField GenericEnum +} + +func NewModelWithEnumAccessorAndDescription() *ModelWithEnumAccessorAndDescription { + return &ModelWithEnumAccessorAndDescription{ + + EnumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnumAccessorAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.EnumField)) + + } +} + +func DecodeModelWithEnumAccessorAndDescription(x *ModelWithEnumAccessorAndDescription, b []byte) (*ModelWithEnumAccessorAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnumAccessorAndDescription(x, d) +} + +func _decodeModelWithEnumAccessorAndDescription(x *ModelWithEnumAccessorAndDescription, d *polyglot.Decoder) (*ModelWithEnumAccessorAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnumAccessorAndDescription() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + return x, nil +} + +type ModelWithMultipleFieldsAccessor struct { + StringField string + + Int32Field int32 +} + +func NewModelWithMultipleFieldsAccessor() *ModelWithMultipleFieldsAccessor { + return &ModelWithMultipleFieldsAccessor{ + + StringField: "DefaultValue", + + Int32Field: 32, + } +} + +func (x *ModelWithMultipleFieldsAccessor) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithMultipleFieldsAccessor(x *ModelWithMultipleFieldsAccessor, b []byte) (*ModelWithMultipleFieldsAccessor, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFieldsAccessor(x, d) +} + +func _decodeModelWithMultipleFieldsAccessor(x *ModelWithMultipleFieldsAccessor, d *polyglot.Decoder) (*ModelWithMultipleFieldsAccessor, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFieldsAccessor() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithMultipleFieldsAccessorAndDescription: Test Description +type ModelWithMultipleFieldsAccessorAndDescription struct { + StringField string + + Int32Field int32 +} + +func NewModelWithMultipleFieldsAccessorAndDescription() *ModelWithMultipleFieldsAccessorAndDescription { + return &ModelWithMultipleFieldsAccessorAndDescription{ + + StringField: "DefaultValue", + + Int32Field: 32, + } +} + +func (x *ModelWithMultipleFieldsAccessorAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithMultipleFieldsAccessorAndDescription(x *ModelWithMultipleFieldsAccessorAndDescription, b []byte) (*ModelWithMultipleFieldsAccessorAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFieldsAccessorAndDescription(x, d) +} + +func _decodeModelWithMultipleFieldsAccessorAndDescription(x *ModelWithMultipleFieldsAccessorAndDescription, d *polyglot.Decoder) (*ModelWithMultipleFieldsAccessorAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFieldsAccessorAndDescription() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithEmbeddedModels struct { + EmbeddedEmptyModel *EmptyModel + + EmbeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModels() *ModelWithEmbeddedModels { + return &ModelWithEmbeddedModels{ + + EmbeddedEmptyModel: NewEmptyModel(), + + EmbeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0, 64), + } +} + +func (x *ModelWithEmbeddedModels) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.EmbeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.EmbeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModels(x *ModelWithEmbeddedModels, b []byte) (*ModelWithEmbeddedModels, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModels(x, d) +} + +func _decodeModelWithEmbeddedModels(x *ModelWithEmbeddedModels, d *polyglot.Decoder) (*ModelWithEmbeddedModels, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModels() + } + + x.EmbeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor { + x.EmbeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.EmbeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +// ModelWithEmbeddedModelsAndDescription: Test Description +type ModelWithEmbeddedModelsAndDescription struct { + EmbeddedEmptyModel *EmptyModel + + EmbeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModelsAndDescription() *ModelWithEmbeddedModelsAndDescription { + return &ModelWithEmbeddedModelsAndDescription{ + + EmbeddedEmptyModel: NewEmptyModel(), + + EmbeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0, 0), + } +} + +func (x *ModelWithEmbeddedModelsAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.EmbeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.EmbeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModelsAndDescription(x *ModelWithEmbeddedModelsAndDescription, b []byte) (*ModelWithEmbeddedModelsAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModelsAndDescription(x, d) +} + +func _decodeModelWithEmbeddedModelsAndDescription(x *ModelWithEmbeddedModelsAndDescription, d *polyglot.Decoder) (*ModelWithEmbeddedModelsAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModelsAndDescription() + } + + x.EmbeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor { + x.EmbeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.EmbeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +type ModelWithEmbeddedModelsAccessor struct { + EmbeddedEmptyModel *EmptyModel + + EmbeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModelsAccessor() *ModelWithEmbeddedModelsAccessor { + return &ModelWithEmbeddedModelsAccessor{ + + EmbeddedEmptyModel: NewEmptyModel(), + + EmbeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0, 0), + } +} + +func (x *ModelWithEmbeddedModelsAccessor) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.EmbeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.EmbeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModelsAccessor(x *ModelWithEmbeddedModelsAccessor, b []byte) (*ModelWithEmbeddedModelsAccessor, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModelsAccessor(x, d) +} + +func _decodeModelWithEmbeddedModelsAccessor(x *ModelWithEmbeddedModelsAccessor, d *polyglot.Decoder) (*ModelWithEmbeddedModelsAccessor, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModelsAccessor() + } + + x.EmbeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor { + x.EmbeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.EmbeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +// ModelWithEmbeddedModelsAccessorAndDescription: Test Description +type ModelWithEmbeddedModelsAccessorAndDescription struct { + EmbeddedEmptyModel *EmptyModel + + EmbeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModelsAccessorAndDescription() *ModelWithEmbeddedModelsAccessorAndDescription { + return &ModelWithEmbeddedModelsAccessorAndDescription{ + + EmbeddedEmptyModel: NewEmptyModel(), + + EmbeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0, 0), + } +} + +func (x *ModelWithEmbeddedModelsAccessorAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.EmbeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.EmbeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModelsAccessorAndDescription(x *ModelWithEmbeddedModelsAccessorAndDescription, b []byte) (*ModelWithEmbeddedModelsAccessorAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModelsAccessorAndDescription(x, d) +} + +func _decodeModelWithEmbeddedModelsAccessorAndDescription(x *ModelWithEmbeddedModelsAccessorAndDescription, d *polyglot.Decoder) (*ModelWithEmbeddedModelsAccessorAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModelsAccessorAndDescription() + } + + x.EmbeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor { + x.EmbeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.EmbeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +type ModelWithAllFieldTypes struct { + ModelField *EmptyModel + + ModelArrayField []EmptyModel + + StringField string + + StringArrayField []string + + StringMapField map[string]string + + StringMapFieldEmbedded map[string]EmptyModel + + Int32Field int32 + + Int32ArrayField []int32 + + Int32MapField map[int32]int32 + + Int32MapFieldEmbedded map[int32]EmptyModel + + Int64Field int64 + + Int64ArrayField []int64 + + Int64MapField map[int64]int64 + + Int64MapFieldEmbedded map[int64]EmptyModel + + Uint32Field uint32 + + Uint32ArrayField []uint32 + + Uint32MapField map[uint32]uint32 + + Uint32MapFieldEmbedded map[uint32]EmptyModel + + Uint64Field uint64 + + Uint64ArrayField []uint64 + + Uint64MapField map[uint64]uint64 + + Uint64MapFieldEmbedded map[uint64]EmptyModel + + Float32Field float32 + + Float32ArrayField []float32 + + Float64Field float64 + + Float64ArrayField []float64 + + EnumField GenericEnum + + EnumArrayField []GenericEnum + + EnumMapField map[GenericEnum]string + + EnumMapFieldEmbedded map[GenericEnum]EmptyModel + + BytesField []byte + + BytesArrayField [][]byte + + BoolField bool + + BoolArrayField []bool +} + +func NewModelWithAllFieldTypes() *ModelWithAllFieldTypes { + return &ModelWithAllFieldTypes{ + + ModelField: NewEmptyModel(), + + ModelArrayField: make([]EmptyModel, 0, 0), + + StringField: "DefaultValue", + + StringArrayField: make([]string, 0, 0), + + StringMapField: make(map[string]string), + + StringMapFieldEmbedded: make(map[string]EmptyModel), + + Int32Field: 32, + + Int32ArrayField: make([]int32, 0, 0), + + Int32MapField: make(map[int32]int32), + + Int32MapFieldEmbedded: make(map[int32]EmptyModel), + + Int64Field: 64, + + Int64ArrayField: make([]int64, 0, 0), + + Int64MapField: make(map[int64]int64), + + Int64MapFieldEmbedded: make(map[int64]EmptyModel), + + Uint32Field: 32, + + Uint32ArrayField: make([]uint32, 0, 0), + + Uint32MapField: make(map[uint32]uint32), + + Uint32MapFieldEmbedded: make(map[uint32]EmptyModel), + + Uint64Field: 64, + + Uint64ArrayField: make([]uint64, 0, 0), + + Uint64MapField: make(map[uint64]uint64), + + Uint64MapFieldEmbedded: make(map[uint64]EmptyModel), + + Float32Field: 32.32, + + Float32ArrayField: make([]float32, 0, 0), + + Float64Field: 64.64, + + Float64ArrayField: make([]float64, 0, 0), + + EnumField: GenericEnumDefaultValue, + + EnumArrayField: make([]GenericEnum, 0, 0), + + EnumMapField: make(map[GenericEnum]string), + + EnumMapFieldEmbedded: make(map[GenericEnum]EmptyModel), + + BytesField: make([]byte, 0, 512), + + BytesArrayField: make([][]byte, 0, 0), + + BoolField: true, + + BoolArrayField: make([]bool, 0, 0), + } +} + +func (x *ModelWithAllFieldTypes) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.ModelField.Encode(b) + + e.Slice(uint32(len(x.ModelArrayField)), polyglot.AnyKind) + for _, a := range x.ModelArrayField { + a.Encode(b) + } + + e.String(x.StringField) + + e.Slice(uint32(len(x.StringArrayField)), polyglot.StringKind) + for _, a := range x.StringArrayField { + e.String(a) + } + + e.Map(uint32(len(x.StringMapField)), polyglot.StringKind, polyglot.StringKind) + for k, v := range x.StringMapField { + e.String(k) + e.String(v) + } + + e.Map(uint32(len(x.StringMapFieldEmbedded)), polyglot.StringKind, polyglot.AnyKind) + for k, v := range x.StringMapFieldEmbedded { + e.String(k) + v.Encode(b) + } + + e.Int32(x.Int32Field) + + e.Slice(uint32(len(x.Int32ArrayField)), polyglot.Int32Kind) + for _, a := range x.Int32ArrayField { + e.Int32(a) + } + + e.Map(uint32(len(x.Int32MapField)), polyglot.Int32Kind, polyglot.Int32Kind) + for k, v := range x.Int32MapField { + e.Int32(k) + e.Int32(v) + } + + e.Map(uint32(len(x.Int32MapFieldEmbedded)), polyglot.Int32Kind, polyglot.AnyKind) + for k, v := range x.Int32MapFieldEmbedded { + e.Int32(k) + v.Encode(b) + } + + e.Int64(x.Int64Field) + + e.Slice(uint32(len(x.Int64ArrayField)), polyglot.Int64Kind) + for _, a := range x.Int64ArrayField { + e.Int64(a) + } + + e.Map(uint32(len(x.Int64MapField)), polyglot.Int64Kind, polyglot.Int64Kind) + for k, v := range x.Int64MapField { + e.Int64(k) + e.Int64(v) + } + + e.Map(uint32(len(x.Int64MapFieldEmbedded)), polyglot.Int64Kind, polyglot.AnyKind) + for k, v := range x.Int64MapFieldEmbedded { + e.Int64(k) + v.Encode(b) + } + + e.Uint32(x.Uint32Field) + + e.Slice(uint32(len(x.Uint32ArrayField)), polyglot.Uint32Kind) + for _, a := range x.Uint32ArrayField { + e.Uint32(a) + } + + e.Map(uint32(len(x.Uint32MapField)), polyglot.Uint32Kind, polyglot.Uint32Kind) + for k, v := range x.Uint32MapField { + e.Uint32(k) + e.Uint32(v) + } + + e.Map(uint32(len(x.Uint32MapFieldEmbedded)), polyglot.Uint32Kind, polyglot.AnyKind) + for k, v := range x.Uint32MapFieldEmbedded { + e.Uint32(k) + v.Encode(b) + } + + e.Uint64(x.Uint64Field) + + e.Slice(uint32(len(x.Uint64ArrayField)), polyglot.Uint64Kind) + for _, a := range x.Uint64ArrayField { + e.Uint64(a) + } + + e.Map(uint32(len(x.Uint64MapField)), polyglot.Uint64Kind, polyglot.Uint64Kind) + for k, v := range x.Uint64MapField { + e.Uint64(k) + e.Uint64(v) + } + + e.Map(uint32(len(x.Uint64MapFieldEmbedded)), polyglot.Uint64Kind, polyglot.AnyKind) + for k, v := range x.Uint64MapFieldEmbedded { + e.Uint64(k) + v.Encode(b) + } + + e.Float32(x.Float32Field) + + e.Slice(uint32(len(x.Float32ArrayField)), polyglot.Float32Kind) + for _, a := range x.Float32ArrayField { + e.Float32(a) + } + + e.Float64(x.Float64Field) + + e.Slice(uint32(len(x.Float64ArrayField)), polyglot.Float64Kind) + for _, a := range x.Float64ArrayField { + e.Float64(a) + } + + e.Uint32(uint32(x.EnumField)) + + e.Slice(uint32(len(x.EnumArrayField)), polyglot.Uint32Kind) + for _, a := range x.EnumArrayField { + e.Uint32(uint32(a)) + } + + e.Map(uint32(len(x.EnumMapField)), polyglot.Uint32Kind, polyglot.StringKind) + for k, v := range x.EnumMapField { + e.Uint32(uint32(k)) + e.String(v) + } + + e.Map(uint32(len(x.EnumMapFieldEmbedded)), polyglot.Uint32Kind, polyglot.AnyKind) + for k, v := range x.EnumMapFieldEmbedded { + e.Uint32(uint32(k)) + v.Encode(b) + } + + e.Bytes(x.BytesField) + + e.Slice(uint32(len(x.BytesArrayField)), polyglot.BytesKind) + for _, a := range x.BytesArrayField { + e.Bytes(a) + } + + e.Bool(x.BoolField) + + e.Slice(uint32(len(x.BoolArrayField)), polyglot.BoolKind) + for _, a := range x.BoolArrayField { + e.Bool(a) + } + + } +} + +func DecodeModelWithAllFieldTypes(x *ModelWithAllFieldTypes, b []byte) (*ModelWithAllFieldTypes, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithAllFieldTypes(x, d) +} + +func _decodeModelWithAllFieldTypes(x *ModelWithAllFieldTypes, d *polyglot.Decoder) (*ModelWithAllFieldTypes, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithAllFieldTypes() + } + + x.ModelField, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeModelArrayField, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.ModelArrayField)) != sliceSizeModelArrayField { + x.ModelArrayField = make([]EmptyModel, sliceSizeModelArrayField) + } + for i := uint32(0); i < sliceSizeModelArrayField; i++ { + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.ModelArrayField[i] = *v + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + sliceSizeStringArrayField, err := d.Slice(polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.StringArrayField)) != sliceSizeStringArrayField { + x.StringArrayField = make([]string, sliceSizeStringArrayField) + } + + for i := uint32(0); i < sliceSizeStringArrayField; i++ { + x.StringArrayField[i], err = d.String() + if err != nil { + return nil, err + } + } + + mapSizeStringMapField, err := d.Map(polyglot.StringKind, polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.StringMapField)) != mapSizeStringMapField { + x.StringMapField = make(map[string]string, mapSizeStringMapField) + } + + for i := uint32(0); i < mapSizeStringMapField; i++ { + k, err := d.String() + if err != nil { + return nil, err + } + x.StringMapField[k], err = d.String() + if err != nil { + return nil, err + } + } + + mapSizeStringMapFieldEmbedded, err := d.Map(polyglot.StringKind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.StringMapFieldEmbedded)) != mapSizeStringMapFieldEmbedded { + x.StringMapFieldEmbedded = make(map[string]EmptyModel, mapSizeStringMapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeStringMapFieldEmbedded; i++ { + k, err := d.String() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.StringMapFieldEmbedded[k] = *v + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + sliceSizeInt32ArrayField, err := d.Slice(polyglot.Int32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int32ArrayField)) != sliceSizeInt32ArrayField { + x.Int32ArrayField = make([]int32, sliceSizeInt32ArrayField) + } + + for i := uint32(0); i < sliceSizeInt32ArrayField; i++ { + x.Int32ArrayField[i], err = d.Int32() + if err != nil { + return nil, err + } + } + + mapSizeInt32MapField, err := d.Map(polyglot.Int32Kind, polyglot.Int32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int32MapField)) != mapSizeInt32MapField { + x.Int32MapField = make(map[int32]int32, mapSizeInt32MapField) + } + + for i := uint32(0); i < mapSizeInt32MapField; i++ { + k, err := d.Int32() + if err != nil { + return nil, err + } + x.Int32MapField[k], err = d.Int32() + if err != nil { + return nil, err + } + } + + mapSizeInt32MapFieldEmbedded, err := d.Map(polyglot.Int32Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int32MapFieldEmbedded)) != mapSizeInt32MapFieldEmbedded { + x.Int32MapFieldEmbedded = make(map[int32]EmptyModel, mapSizeInt32MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeInt32MapFieldEmbedded; i++ { + k, err := d.Int32() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Int32MapFieldEmbedded[k] = *v + } + + x.Int64Field, err = d.Int64() + if err != nil { + return nil, err + } + + sliceSizeInt64ArrayField, err := d.Slice(polyglot.Int64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int64ArrayField)) != sliceSizeInt64ArrayField { + x.Int64ArrayField = make([]int64, sliceSizeInt64ArrayField) + } + + for i := uint32(0); i < sliceSizeInt64ArrayField; i++ { + x.Int64ArrayField[i], err = d.Int64() + if err != nil { + return nil, err + } + } + + mapSizeInt64MapField, err := d.Map(polyglot.Int64Kind, polyglot.Int64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int64MapField)) != mapSizeInt64MapField { + x.Int64MapField = make(map[int64]int64, mapSizeInt64MapField) + } + + for i := uint32(0); i < mapSizeInt64MapField; i++ { + k, err := d.Int64() + if err != nil { + return nil, err + } + x.Int64MapField[k], err = d.Int64() + if err != nil { + return nil, err + } + } + + mapSizeInt64MapFieldEmbedded, err := d.Map(polyglot.Int64Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int64MapFieldEmbedded)) != mapSizeInt64MapFieldEmbedded { + x.Int64MapFieldEmbedded = make(map[int64]EmptyModel, mapSizeInt64MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeInt64MapFieldEmbedded; i++ { + k, err := d.Int64() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Int64MapFieldEmbedded[k] = *v + } + + x.Uint32Field, err = d.Uint32() + if err != nil { + return nil, err + } + + sliceSizeUint32ArrayField, err := d.Slice(polyglot.Uint32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint32ArrayField)) != sliceSizeUint32ArrayField { + x.Uint32ArrayField = make([]uint32, sliceSizeUint32ArrayField) + } + + for i := uint32(0); i < sliceSizeUint32ArrayField; i++ { + x.Uint32ArrayField[i], err = d.Uint32() + if err != nil { + return nil, err + } + } + + mapSizeUint32MapField, err := d.Map(polyglot.Uint32Kind, polyglot.Uint32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint32MapField)) != mapSizeUint32MapField { + x.Uint32MapField = make(map[uint32]uint32, mapSizeUint32MapField) + } + + for i := uint32(0); i < mapSizeUint32MapField; i++ { + k, err := d.Uint32() + if err != nil { + return nil, err + } + x.Uint32MapField[k], err = d.Uint32() + if err != nil { + return nil, err + } + } + + mapSizeUint32MapFieldEmbedded, err := d.Map(polyglot.Uint32Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint32MapFieldEmbedded)) != mapSizeUint32MapFieldEmbedded { + x.Uint32MapFieldEmbedded = make(map[uint32]EmptyModel, mapSizeUint32MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeUint32MapFieldEmbedded; i++ { + k, err := d.Uint32() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Uint32MapFieldEmbedded[k] = *v + } + + x.Uint64Field, err = d.Uint64() + if err != nil { + return nil, err + } + + sliceSizeUint64ArrayField, err := d.Slice(polyglot.Uint64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint64ArrayField)) != sliceSizeUint64ArrayField { + x.Uint64ArrayField = make([]uint64, sliceSizeUint64ArrayField) + } + + for i := uint32(0); i < sliceSizeUint64ArrayField; i++ { + x.Uint64ArrayField[i], err = d.Uint64() + if err != nil { + return nil, err + } + } + + mapSizeUint64MapField, err := d.Map(polyglot.Uint64Kind, polyglot.Uint64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint64MapField)) != mapSizeUint64MapField { + x.Uint64MapField = make(map[uint64]uint64, mapSizeUint64MapField) + } + + for i := uint32(0); i < mapSizeUint64MapField; i++ { + k, err := d.Uint64() + if err != nil { + return nil, err + } + x.Uint64MapField[k], err = d.Uint64() + if err != nil { + return nil, err + } + } + + mapSizeUint64MapFieldEmbedded, err := d.Map(polyglot.Uint64Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint64MapFieldEmbedded)) != mapSizeUint64MapFieldEmbedded { + x.Uint64MapFieldEmbedded = make(map[uint64]EmptyModel, mapSizeUint64MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeUint64MapFieldEmbedded; i++ { + k, err := d.Uint64() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Uint64MapFieldEmbedded[k] = *v + } + + x.Float32Field, err = d.Float32() + if err != nil { + return nil, err + } + + sliceSizeFloat32ArrayField, err := d.Slice(polyglot.Float32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Float32ArrayField)) != sliceSizeFloat32ArrayField { + x.Float32ArrayField = make([]float32, sliceSizeFloat32ArrayField) + } + + for i := uint32(0); i < sliceSizeFloat32ArrayField; i++ { + x.Float32ArrayField[i], err = d.Float32() + if err != nil { + return nil, err + } + } + + x.Float64Field, err = d.Float64() + if err != nil { + return nil, err + } + + sliceSizeFloat64ArrayField, err := d.Slice(polyglot.Float64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Float64ArrayField)) != sliceSizeFloat64ArrayField { + x.Float64ArrayField = make([]float64, sliceSizeFloat64ArrayField) + } + + for i := uint32(0); i < sliceSizeFloat64ArrayField; i++ { + x.Float64ArrayField[i], err = d.Float64() + if err != nil { + return nil, err + } + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + sliceSizeEnumArrayField, err := d.Slice(polyglot.Uint32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.EnumArrayField)) != sliceSizeEnumArrayField { + x.EnumArrayField = make([]GenericEnum, sliceSizeEnumArrayField) + } + + for i := uint32(0); i < sliceSizeEnumArrayField; i++ { + val, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumArrayField[i] = val + } + + mapSizeEnumMapField, err := d.Map(polyglot.Uint32Kind, polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.EnumMapField)) != mapSizeEnumMapField { + x.EnumMapField = make(map[GenericEnum]string, mapSizeEnumMapField) + } + + for i := uint32(0); i < mapSizeEnumMapField; i++ { + k, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumMapField[k], err = d.String() + if err != nil { + return nil, err + } + } + + mapSizeEnumMapFieldEmbedded, err := d.Map(polyglot.Uint32Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.EnumMapFieldEmbedded)) != mapSizeEnumMapFieldEmbedded { + x.EnumMapFieldEmbedded = make(map[GenericEnum]EmptyModel, mapSizeEnumMapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeEnumMapFieldEmbedded; i++ { + k, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.EnumMapFieldEmbedded[k] = *v + } + + x.BytesField, err = d.Bytes(nil) + if err != nil { + return nil, err + } + + sliceSizeBytesArrayField, err := d.Slice(polyglot.BytesKind) + if err != nil { + return nil, err + } + + if uint32(len(x.BytesArrayField)) != sliceSizeBytesArrayField { + x.BytesArrayField = make([][]byte, sliceSizeBytesArrayField) + } + + for i := uint32(0); i < sliceSizeBytesArrayField; i++ { + x.BytesArrayField[i], err = d.Bytes(nil) + if err != nil { + return nil, err + } + } + + x.BoolField, err = d.Bool() + if err != nil { + return nil, err + } + + sliceSizeBoolArrayField, err := d.Slice(polyglot.BoolKind) + if err != nil { + return nil, err + } + + if uint32(len(x.BoolArrayField)) != sliceSizeBoolArrayField { + x.BoolArrayField = make([]bool, sliceSizeBoolArrayField) + } + + for i := uint32(0); i < sliceSizeBoolArrayField; i++ { + x.BoolArrayField[i], err = d.Bool() + if err != nil { + return nil, err + } + } + + return x, nil +} diff --git a/integration/golang_ext_tests/signature/go.mod b/integration/golang_ext_tests/signature/go.mod new file mode 100644 index 00000000..06addd8f --- /dev/null +++ b/integration/golang_ext_tests/signature/go.mod @@ -0,0 +1,8 @@ +module signature + +go 1.20 + +require ( + github.com/loopholelabs/polyglot v1.1.3 + github.com/loopholelabs/scale-signature-interfaces v0.1.7 +) \ No newline at end of file diff --git a/integration/golang_ext_tests/signature/go.sum b/integration/golang_ext_tests/signature/go.sum new file mode 100644 index 00000000..0754633d --- /dev/null +++ b/integration/golang_ext_tests/signature/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/loopholelabs/polyglot v1.1.3 h1:WUTcSZ2TQ1lv7CZ4I9nHFBUjf0hKJN+Yfz1rZZJuTP0= +github.com/loopholelabs/polyglot v1.1.3/go.mod h1:EA88BEkIluKHAWxhyOV88xXz68YkRdo9IzZ+1dj+7Ao= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/integration/golang_ext_tests/signature/guest.go b/integration/golang_ext_tests/signature/guest.go new file mode 100644 index 00000000..0f3f8524 --- /dev/null +++ b/integration/golang_ext_tests/signature/guest.go @@ -0,0 +1,80 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: signature + +package signature + +import ( + "github.com/loopholelabs/polyglot" + "unsafe" +) + +const hash = "3a592aa345d412faa2e6285ee048ca2ab5aa64b0caa2f9ca67b2c1e0792101e5" + +var ( + writeBuffer = polyglot.NewBuffer() + readBuffer []byte +) + +// Write serializes the signature into the global writeBuffer and returns the pointer to the buffer and its size +// +// Users should not use this method. +func Write(ctx *ModelWithAllFieldTypes) (uint32, uint32) { + writeBuffer.Reset() + ctx.Encode(writeBuffer) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + return uint32(unsafePtr), uint32(writeBuffer.Len()) +} + +// Read deserializes signature from the global readBuffer +// +// Users should not use this method. +func Read(ctx *ModelWithAllFieldTypes) (*ModelWithAllFieldTypes, error) { + return DecodeModelWithAllFieldTypes(ctx, readBuffer) +} + +// Error serializes an error into the global writeBuffer and returns a pointer to the buffer and its size +// +// Users should not use this method. +func Error(err error) (uint32, uint32) { + writeBuffer.Reset() + polyglot.Encoder(writeBuffer).Error(err) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + return uint32(unsafePtr), uint32(writeBuffer.Len()) +} + +// Resize resizes the global readBuffer to the given size and returns the pointer to the buffer +// +// Users should not use this method. +func Resize(size uint32) uint32 { + if uint32(cap(readBuffer)) < size { + readBuffer = append(make([]byte, 0, uint32(len(readBuffer))+size), readBuffer...) + } + readBuffer = readBuffer[:size] + return uint32(uintptr(unsafe.Pointer(&readBuffer[0]))) +} + +// Hash returns the hash of the Scale Signature +// +// Users should not use this method. +func Hash() (uint32, uint32) { + writeBuffer.Reset() + polyglot.Encoder(writeBuffer).String(hash) + underlying := writeBuffer.Bytes() + ptr := &underlying[0] + unsafePtr := uintptr(unsafe.Pointer(ptr)) + return uint32(unsafePtr), uint32(writeBuffer.Len()) +} + +// Next calls the next function in the Scale Function Chain +func Next(ctx *ModelWithAllFieldTypes) (*ModelWithAllFieldTypes, error) { + next(Write(ctx)) + return Read(ctx) +} + +//go:export next +//go:linkname next +func next(offset uint32, length uint32) diff --git a/integration/golang_ext_tests/signature/signature_test.go b/integration/golang_ext_tests/signature/signature_test.go new file mode 100644 index 00000000..06c07b3f --- /dev/null +++ b/integration/golang_ext_tests/signature/signature_test.go @@ -0,0 +1,603 @@ +//go:build integration && golang + +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package signature + +import ( + "github.com/loopholelabs/polyglot" + "github.com/stretchr/testify/require" + "os" + "strings" + "testing" +) + +func TestOutput(t *testing.T) { + buf := polyglot.NewBuffer() + + var nilModel *EmptyModel + nilModel.Encode(buf) + err := os.WriteFile("../../test_data/nil_model.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + emptyModel := NewEmptyModel() + emptyModel.Encode(buf) + err = os.WriteFile("../../test_data/empty_model.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + emptyModelWithDescription := NewEmptyModelWithDescription() + emptyModelWithDescription.Encode(buf) + err = os.WriteFile("../../test_data/empty_model_with_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithSingleStringField := NewModelWithSingleStringField() + require.Equal(t, "DefaultValue", modelWithSingleStringField.StringField) + modelWithSingleStringField.StringField = "hello world" + modelWithSingleStringField.Encode(buf) + err = os.WriteFile("../../test_data/model_with_single_string_field.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithSingleStringFieldAndDescription := NewModelWithSingleStringFieldAndDescription() + require.Equal(t, "DefaultValue", modelWithSingleStringFieldAndDescription.StringField) + modelWithSingleStringFieldAndDescription.StringField = "hello world" + modelWithSingleStringFieldAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_single_string_field_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithSingleInt32Field := NewModelWithSingleInt32Field() + require.Equal(t, int32(32), modelWithSingleInt32Field.Int32Field) + modelWithSingleInt32Field.Int32Field = 42 + modelWithSingleInt32Field.Encode(buf) + err = os.WriteFile("../../test_data/model_with_single_int32_field.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithSingleInt32FieldAndDescription := NewModelWithSingleInt32FieldAndDescription() + require.Equal(t, int32(32), modelWithSingleInt32FieldAndDescription.Int32Field) + modelWithSingleInt32FieldAndDescription.Int32Field = 42 + modelWithSingleInt32FieldAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_single_int32_field_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithMultipleFields := NewModelWithMultipleFields() + require.Equal(t, "DefaultValue", modelWithMultipleFields.StringField) + require.Equal(t, int32(32), modelWithMultipleFields.Int32Field) + modelWithMultipleFields.StringField = "hello world" + modelWithMultipleFields.Int32Field = 42 + modelWithMultipleFields.Encode(buf) + err = os.WriteFile("../../test_data/model_with_multiple_fields.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithMultipleFieldsAndDescription := NewModelWithMultipleFieldsAndDescription() + require.Equal(t, "DefaultValue", modelWithMultipleFieldsAndDescription.StringField) + require.Equal(t, int32(32), modelWithMultipleFieldsAndDescription.Int32Field) + modelWithMultipleFieldsAndDescription.StringField = "hello world" + modelWithMultipleFieldsAndDescription.Int32Field = 42 + modelWithMultipleFieldsAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_multiple_fields_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEnum := NewModelWithEnum() + require.Equal(t, GenericEnumDefaultValue, modelWithEnum.EnumField) + modelWithEnum.EnumField = GenericEnumSecondValue + modelWithEnum.Encode(buf) + err = os.WriteFile("../../test_data/model_with_enum.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEnumAndDescription := NewModelWithEnumAndDescription() + require.Equal(t, GenericEnumDefaultValue, modelWithEnumAndDescription.EnumField) + modelWithEnumAndDescription.EnumField = GenericEnumSecondValue + modelWithEnumAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_enum_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEnumAccessor := NewModelWithEnumAccessor() + defaultEnumValue, err := modelWithEnumAccessor.GetEnumField() + require.NoError(t, err) + require.Equal(t, GenericEnumDefaultValue, defaultEnumValue) + err = modelWithEnumAccessor.SetEnumField(GenericEnumSecondValue) + require.NoError(t, err) + modelWithEnumAccessor.Encode(buf) + err = os.WriteFile("../../test_data/model_with_enum_accessor.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEnumAccessorAndDescription := NewModelWithEnumAccessorAndDescription() + defaultEnumValue, err = modelWithEnumAccessorAndDescription.GetEnumField() + require.NoError(t, err) + require.Equal(t, GenericEnumDefaultValue, defaultEnumValue) + err = modelWithEnumAccessorAndDescription.SetEnumField(GenericEnumSecondValue) + require.NoError(t, err) + modelWithEnumAccessorAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_enum_accessor_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithMultipleFieldsAccessor := NewModelWithMultipleFieldsAccessor() + stringValue, err := modelWithMultipleFieldsAccessor.GetStringField() + require.NoError(t, err) + require.Equal(t, "DefaultValue", stringValue) + err = modelWithMultipleFieldsAccessor.SetStringField("hello world") + require.ErrorContains(t, err, "value must match ^[a-zA-Z0-9]*$") + err = modelWithMultipleFieldsAccessor.SetStringField("") + require.ErrorContains(t, err, "length must be between 1 and 20") + err = modelWithMultipleFieldsAccessor.SetStringField("hello") + require.NoError(t, err) + stringValue, err = modelWithMultipleFieldsAccessor.GetStringField() + require.NoError(t, err) + require.Equal(t, strings.ToUpper("hello"), stringValue) + int32Value, err := modelWithMultipleFieldsAccessor.GetInt32Field() + require.NoError(t, err) + require.Equal(t, int32(32), int32Value) + err = modelWithMultipleFieldsAccessor.SetInt32Field(-1) + require.ErrorContains(t, err, "value must be between 0 and 100") + err = modelWithMultipleFieldsAccessor.SetInt32Field(101) + require.ErrorContains(t, err, "value must be between 0 and 100") + err = modelWithMultipleFieldsAccessor.SetInt32Field(42) + require.NoError(t, err) + modelWithMultipleFieldsAccessor.Encode(buf) + err = os.WriteFile("../../test_data/model_with_multiple_fields_accessor.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithMultipleFieldsAccessorAndDescription := NewModelWithMultipleFieldsAccessorAndDescription() + stringValue, err = modelWithMultipleFieldsAccessorAndDescription.GetStringField() + require.NoError(t, err) + require.Equal(t, "DefaultValue", stringValue) + err = modelWithMultipleFieldsAccessorAndDescription.SetStringField("hello world") + require.NoError(t, err) + int32Value, err = modelWithMultipleFieldsAccessorAndDescription.GetInt32Field() + require.NoError(t, err) + require.Equal(t, int32(32), int32Value) + err = modelWithMultipleFieldsAccessorAndDescription.SetInt32Field(42) + require.NoError(t, err) + modelWithMultipleFieldsAccessorAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_multiple_fields_accessor_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEmbeddedModels := NewModelWithEmbeddedModels() + require.NotNil(t, modelWithEmbeddedModels.EmbeddedEmptyModel) + require.NotNil(t, modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, 64, cap(modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.Equal(t, 0, len(modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor) + modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor = append(modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor, *modelWithMultipleFieldsAccessor) + modelWithEmbeddedModels.Encode(buf) + err = os.WriteFile("../../test_data/model_with_embedded_models.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEmbeddedModelsAndDescription := NewModelWithEmbeddedModelsAndDescription() + require.NotNil(t, modelWithEmbeddedModelsAndDescription.EmbeddedEmptyModel) + require.NotNil(t, modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, 0, cap(modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.Equal(t, 0, len(modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor) + modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor = append(modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor, *modelWithMultipleFieldsAccessor) + modelWithEmbeddedModelsAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_embedded_models_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEmbeddedModelsAccessor := NewModelWithEmbeddedModelsAccessor() + embeddedModel, err := modelWithEmbeddedModelsAccessor.GetEmbeddedEmptyModel() + require.NoError(t, err) + require.NotNil(t, embeddedModel) + embeddedModelArray, err := modelWithEmbeddedModelsAccessor.GetEmbeddedModelArrayWithMultipleFieldsAccessor() + require.NoError(t, err) + require.NotNil(t, embeddedModelArray) + require.Equal(t, 0, cap(embeddedModelArray)) + require.Equal(t, 0, len(embeddedModelArray)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, embeddedModelArray) + err = modelWithEmbeddedModelsAccessor.SetEmbeddedModelArrayWithMultipleFieldsAccessor([]ModelWithMultipleFieldsAccessor{*modelWithMultipleFieldsAccessor}) + require.NoError(t, err) + modelWithEmbeddedModelsAccessor.Encode(buf) + err = os.WriteFile("../../test_data/model_with_embedded_models_accessor.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithEmbeddedModelsAccessorAndDescription := NewModelWithEmbeddedModelsAccessorAndDescription() + embeddedModel, err = modelWithEmbeddedModelsAccessorAndDescription.GetEmbeddedEmptyModel() + require.NoError(t, err) + require.NotNil(t, embeddedModel) + embeddedModelArray, err = modelWithEmbeddedModelsAccessorAndDescription.GetEmbeddedModelArrayWithMultipleFieldsAccessor() + require.NoError(t, err) + require.NotNil(t, embeddedModelArray) + require.Equal(t, 0, cap(embeddedModelArray)) + require.Equal(t, 0, len(embeddedModelArray)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, embeddedModelArray) + err = modelWithEmbeddedModelsAccessorAndDescription.SetEmbeddedModelArrayWithMultipleFieldsAccessor([]ModelWithMultipleFieldsAccessor{*modelWithMultipleFieldsAccessor}) + require.NoError(t, err) + modelWithEmbeddedModelsAccessorAndDescription.Encode(buf) + err = os.WriteFile("../../test_data/model_with_embedded_models_accessor_and_description.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() + + modelWithAllFieldTypes := NewModelWithAllFieldTypes() + + require.Equal(t, "DefaultValue", modelWithAllFieldTypes.StringField) + modelWithAllFieldTypes.StringField = "hello world" + require.Equal(t, 0, cap(modelWithAllFieldTypes.StringArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.StringArrayField)) + require.IsType(t, []string{}, modelWithAllFieldTypes.StringArrayField) + modelWithAllFieldTypes.StringArrayField = append(modelWithAllFieldTypes.StringArrayField, "hello", "world") + require.Equal(t, 0, len(modelWithAllFieldTypes.StringMapField)) + require.IsType(t, map[string]string{}, modelWithAllFieldTypes.StringMapField) + modelWithAllFieldTypes.StringMapField["hello"] = "world" + require.Equal(t, 0, len(modelWithAllFieldTypes.StringMapFieldEmbedded)) + require.IsType(t, map[string]EmptyModel{}, modelWithAllFieldTypes.StringMapFieldEmbedded) + modelWithAllFieldTypes.StringMapFieldEmbedded["hello"] = *emptyModel + + require.Equal(t, int32(32), modelWithAllFieldTypes.Int32Field) + modelWithAllFieldTypes.Int32Field = 42 + require.Equal(t, 0, cap(modelWithAllFieldTypes.Int32ArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.Int32ArrayField)) + require.IsType(t, []int32{}, modelWithAllFieldTypes.Int32ArrayField) + modelWithAllFieldTypes.Int32ArrayField = append(modelWithAllFieldTypes.Int32ArrayField, 42, 84) + require.Equal(t, 0, len(modelWithAllFieldTypes.Int32MapField)) + require.IsType(t, map[int32]int32{}, modelWithAllFieldTypes.Int32MapField) + modelWithAllFieldTypes.Int32MapField[42] = 84 + require.Equal(t, 0, len(modelWithAllFieldTypes.Int32MapFieldEmbedded)) + require.IsType(t, map[int32]EmptyModel{}, modelWithAllFieldTypes.Int32MapFieldEmbedded) + modelWithAllFieldTypes.Int32MapFieldEmbedded[42] = *emptyModel + + require.Equal(t, int64(64), modelWithAllFieldTypes.Int64Field) + modelWithAllFieldTypes.Int64Field = 100 + require.Equal(t, 0, cap(modelWithAllFieldTypes.Int64ArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.Int64ArrayField)) + require.IsType(t, []int64{}, modelWithAllFieldTypes.Int64ArrayField) + modelWithAllFieldTypes.Int64ArrayField = append(modelWithAllFieldTypes.Int64ArrayField, 100, 200) + require.Equal(t, 0, len(modelWithAllFieldTypes.Int64MapField)) + require.IsType(t, map[int64]int64{}, modelWithAllFieldTypes.Int64MapField) + modelWithAllFieldTypes.Int64MapField[100] = 200 + require.Equal(t, 0, len(modelWithAllFieldTypes.Int64MapFieldEmbedded)) + require.IsType(t, map[int64]EmptyModel{}, modelWithAllFieldTypes.Int64MapFieldEmbedded) + modelWithAllFieldTypes.Int64MapFieldEmbedded[100] = *emptyModel + + require.Equal(t, uint32(32), modelWithAllFieldTypes.Uint32Field) + modelWithAllFieldTypes.Uint32Field = 42 + require.Equal(t, 0, cap(modelWithAllFieldTypes.Uint32ArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.Uint32ArrayField)) + require.IsType(t, []uint32{}, modelWithAllFieldTypes.Uint32ArrayField) + modelWithAllFieldTypes.Uint32ArrayField = append(modelWithAllFieldTypes.Uint32ArrayField, 42, 84) + require.Equal(t, 0, len(modelWithAllFieldTypes.Uint32MapField)) + require.IsType(t, map[uint32]uint32{}, modelWithAllFieldTypes.Uint32MapField) + modelWithAllFieldTypes.Uint32MapField[42] = 84 + require.Equal(t, 0, len(modelWithAllFieldTypes.Uint32MapFieldEmbedded)) + require.IsType(t, map[uint32]EmptyModel{}, modelWithAllFieldTypes.Uint32MapFieldEmbedded) + modelWithAllFieldTypes.Uint32MapFieldEmbedded[42] = *emptyModel + + require.Equal(t, uint64(64), modelWithAllFieldTypes.Uint64Field) + modelWithAllFieldTypes.Uint64Field = 100 + require.Equal(t, 0, cap(modelWithAllFieldTypes.Uint64ArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.Uint64ArrayField)) + require.IsType(t, []uint64{}, modelWithAllFieldTypes.Uint64ArrayField) + modelWithAllFieldTypes.Uint64ArrayField = append(modelWithAllFieldTypes.Uint64ArrayField, 100, 200) + require.Equal(t, 0, len(modelWithAllFieldTypes.Uint64MapField)) + require.IsType(t, map[uint64]uint64{}, modelWithAllFieldTypes.Uint64MapField) + modelWithAllFieldTypes.Uint64MapField[100] = 200 + require.Equal(t, 0, len(modelWithAllFieldTypes.Uint64MapFieldEmbedded)) + require.IsType(t, map[uint64]EmptyModel{}, modelWithAllFieldTypes.Uint64MapFieldEmbedded) + modelWithAllFieldTypes.Uint64MapFieldEmbedded[100] = *emptyModel + + require.Equal(t, float32(32.32), modelWithAllFieldTypes.Float32Field) + modelWithAllFieldTypes.Float32Field = 42.0 + require.Equal(t, 0, cap(modelWithAllFieldTypes.Float32ArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.Float32ArrayField)) + require.IsType(t, []float32{}, modelWithAllFieldTypes.Float32ArrayField) + modelWithAllFieldTypes.Float32ArrayField = append(modelWithAllFieldTypes.Float32ArrayField, 42.0, 84.0) + + require.Equal(t, float64(64.64), modelWithAllFieldTypes.Float64Field) + modelWithAllFieldTypes.Float64Field = 100.0 + require.Equal(t, 0, cap(modelWithAllFieldTypes.Float64ArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.Float64ArrayField)) + require.IsType(t, []float64{}, modelWithAllFieldTypes.Float64ArrayField) + modelWithAllFieldTypes.Float64ArrayField = append(modelWithAllFieldTypes.Float64ArrayField, 100.0, 200.0) + + require.Equal(t, true, modelWithAllFieldTypes.BoolField) + modelWithAllFieldTypes.BoolField = false + require.Equal(t, 0, cap(modelWithAllFieldTypes.BoolArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.BoolArrayField)) + require.IsType(t, []bool{}, modelWithAllFieldTypes.BoolArrayField) + modelWithAllFieldTypes.BoolArrayField = append(modelWithAllFieldTypes.BoolArrayField, true, false) + + require.Equal(t, 512, cap(modelWithAllFieldTypes.BytesField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.BytesField)) + require.IsType(t, []byte{}, modelWithAllFieldTypes.BytesField) + modelWithAllFieldTypes.BytesField = append(modelWithAllFieldTypes.BytesField, []byte{42, 84}...) + require.Equal(t, 0, len(modelWithAllFieldTypes.BytesArrayField)) + require.IsType(t, [][]byte{}, modelWithAllFieldTypes.BytesArrayField) + modelWithAllFieldTypes.BytesArrayField = append(modelWithAllFieldTypes.BytesArrayField, []byte{42, 84}, []byte{84, 42}) + + require.Equal(t, GenericEnumDefaultValue, modelWithAllFieldTypes.EnumField) + modelWithAllFieldTypes.EnumField = GenericEnumSecondValue + require.Equal(t, 0, cap(modelWithAllFieldTypes.EnumArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.EnumArrayField)) + require.IsType(t, []GenericEnum{}, modelWithAllFieldTypes.EnumArrayField) + modelWithAllFieldTypes.EnumArrayField = append(modelWithAllFieldTypes.EnumArrayField, GenericEnumFirstValue, GenericEnumSecondValue) + require.Equal(t, 0, len(modelWithAllFieldTypes.EnumMapField)) + require.IsType(t, map[GenericEnum]string{}, modelWithAllFieldTypes.EnumMapField) + modelWithAllFieldTypes.EnumMapField[GenericEnumFirstValue] = "hello world" + require.Equal(t, 0, len(modelWithAllFieldTypes.EnumMapFieldEmbedded)) + require.IsType(t, map[GenericEnum]EmptyModel{}, modelWithAllFieldTypes.EnumMapFieldEmbedded) + modelWithAllFieldTypes.EnumMapFieldEmbedded[GenericEnumFirstValue] = *emptyModel + + require.NotNil(t, modelWithAllFieldTypes.ModelField) + require.Equal(t, 0, cap(modelWithAllFieldTypes.ModelArrayField)) + require.Equal(t, 0, len(modelWithAllFieldTypes.ModelArrayField)) + require.IsType(t, []EmptyModel{}, modelWithAllFieldTypes.ModelArrayField) + modelWithAllFieldTypes.ModelArrayField = append(modelWithAllFieldTypes.ModelArrayField, *emptyModel, *emptyModel) + + modelWithAllFieldTypes.Encode(buf) + err = os.WriteFile("../../test_data/model_with_all_field_types.bin", buf.Bytes(), 0644) + require.NoError(t, err) + buf.Reset() +} + +func TestInput(t *testing.T) { + nilModelData, err := os.ReadFile("../../test_data/nil_model.bin") + require.NoError(t, err) + nilModel, err := DecodeEmptyModel(nil, nilModelData) + require.NoError(t, err) + require.Nil(t, nilModel) + + emptyModelData, err := os.ReadFile("../../test_data/empty_model.bin") + require.NoError(t, err) + emptyModel, err := DecodeEmptyModel(nil, emptyModelData) + require.NoError(t, err) + require.NotNil(t, emptyModel) + + emptyModelWithDescriptionData, err := os.ReadFile("../../test_data/empty_model_with_description.bin") + require.NoError(t, err) + emptyModelWithDescription, err := DecodeEmptyModelWithDescription(nil, emptyModelWithDescriptionData) + require.NoError(t, err) + require.NotNil(t, emptyModelWithDescription) + + modelWithSingleStringFieldData, err := os.ReadFile("../../test_data/model_with_single_string_field.bin") + require.NoError(t, err) + modelWithSingleStringField, err := DecodeModelWithSingleStringField(nil, modelWithSingleStringFieldData) + require.NoError(t, err) + require.NotNil(t, modelWithSingleStringField) + require.Equal(t, "hello world", modelWithSingleStringField.StringField) + + modelWithSingleStringFieldAndDescriptionData, err := os.ReadFile("../../test_data/model_with_single_string_field_and_description.bin") + require.NoError(t, err) + modelWithSingleStringFieldAndDescription, err := DecodeModelWithSingleStringFieldAndDescription(nil, modelWithSingleStringFieldAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithSingleStringFieldAndDescription) + require.Equal(t, "hello world", modelWithSingleStringFieldAndDescription.StringField) + + modelWithSingleInt32FieldData, err := os.ReadFile("../../test_data/model_with_single_int32_field.bin") + require.NoError(t, err) + modelWithSingleInt32Field, err := DecodeModelWithSingleInt32Field(nil, modelWithSingleInt32FieldData) + require.NoError(t, err) + require.NotNil(t, modelWithSingleInt32Field) + require.Equal(t, int32(42), modelWithSingleInt32Field.Int32Field) + + modelWithSingleInt32FieldAndDescriptionData, err := os.ReadFile("../../test_data/model_with_single_int32_field_and_description.bin") + require.NoError(t, err) + modelWithSingleInt32FieldAndDescription, err := DecodeModelWithSingleInt32FieldAndDescription(nil, modelWithSingleInt32FieldAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithSingleInt32FieldAndDescription) + require.Equal(t, int32(42), modelWithSingleInt32FieldAndDescription.Int32Field) + + modelWithMultipleFieldsData, err := os.ReadFile("../../test_data/model_with_multiple_fields.bin") + require.NoError(t, err) + modelWithMultipleFields, err := DecodeModelWithMultipleFields(nil, modelWithMultipleFieldsData) + require.NoError(t, err) + require.NotNil(t, modelWithMultipleFields) + require.Equal(t, "hello world", modelWithMultipleFields.StringField) + require.Equal(t, int32(42), modelWithMultipleFields.Int32Field) + + modelWithMultipleFieldsAndDescriptionData, err := os.ReadFile("../../test_data/model_with_multiple_fields_and_description.bin") + require.NoError(t, err) + modelWithMultipleFieldsAndDescription, err := DecodeModelWithMultipleFieldsAndDescription(nil, modelWithMultipleFieldsAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithMultipleFieldsAndDescription) + require.Equal(t, "hello world", modelWithMultipleFieldsAndDescription.StringField) + require.Equal(t, int32(42), modelWithMultipleFieldsAndDescription.Int32Field) + + modelWithEnumData, err := os.ReadFile("../../test_data/model_with_enum.bin") + require.NoError(t, err) + modelWithEnum, err := DecodeModelWithEnum(nil, modelWithEnumData) + require.NoError(t, err) + require.NotNil(t, modelWithEnum) + require.Equal(t, GenericEnumSecondValue, modelWithEnum.EnumField) + + modelWithEnumAndDescriptionData, err := os.ReadFile("../../test_data/model_with_enum_and_description.bin") + require.NoError(t, err) + modelWithEnumAndDescription, err := DecodeModelWithEnumAndDescription(nil, modelWithEnumAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithEnumAndDescription) + require.Equal(t, GenericEnumSecondValue, modelWithEnumAndDescription.EnumField) + + modelWithEnumAccessorData, err := os.ReadFile("../../test_data/model_with_enum_accessor.bin") + require.NoError(t, err) + modelWithEnumAccessor, err := DecodeModelWithEnumAccessor(nil, modelWithEnumAccessorData) + require.NoError(t, err) + require.NotNil(t, modelWithEnumAccessor) + enumValue, err := modelWithEnumAccessor.GetEnumField() + require.NoError(t, err) + require.Equal(t, GenericEnumSecondValue, enumValue) + + modelWithEnumAccessorAndDescriptionData, err := os.ReadFile("../../test_data/model_with_enum_accessor_and_description.bin") + require.NoError(t, err) + modelWithEnumAccessorAndDescription, err := DecodeModelWithEnumAccessorAndDescription(nil, modelWithEnumAccessorAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithEnumAccessorAndDescription) + enumValue, err = modelWithEnumAccessorAndDescription.GetEnumField() + require.NoError(t, err) + require.Equal(t, GenericEnumSecondValue, enumValue) + + modelWithMultipleFieldsAccessorData, err := os.ReadFile("../../test_data/model_with_multiple_fields_accessor.bin") + require.NoError(t, err) + modelWithMultipleFieldsAccessor, err := DecodeModelWithMultipleFieldsAccessor(nil, modelWithMultipleFieldsAccessorData) + require.NoError(t, err) + require.NotNil(t, modelWithMultipleFieldsAccessor) + stringFieldValue, err := modelWithMultipleFieldsAccessor.GetStringField() + require.NoError(t, err) + require.Equal(t, "HELLO", stringFieldValue) + int32FieldValue, err := modelWithMultipleFieldsAccessor.GetInt32Field() + require.NoError(t, err) + require.Equal(t, int32(42), int32FieldValue) + + modelWithMultipleFieldsAccessorAndDescriptionData, err := os.ReadFile("../../test_data/model_with_multiple_fields_accessor_and_description.bin") + require.NoError(t, err) + modelWithMultipleFieldsAccessorAndDescription, err := DecodeModelWithMultipleFieldsAccessorAndDescription(nil, modelWithMultipleFieldsAccessorAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithMultipleFieldsAccessorAndDescription) + stringFieldValue, err = modelWithMultipleFieldsAccessorAndDescription.GetStringField() + require.NoError(t, err) + require.Equal(t, "hello world", stringFieldValue) + int32FieldValue, err = modelWithMultipleFieldsAccessorAndDescription.GetInt32Field() + require.NoError(t, err) + require.Equal(t, int32(42), int32FieldValue) + + modelWithEmbeddedModelsData, err := os.ReadFile("../../test_data/model_with_embedded_models.bin") + require.NoError(t, err) + modelWithEmbeddedModels, err := DecodeModelWithEmbeddedModels(nil, modelWithEmbeddedModelsData) + require.NoError(t, err) + require.NotNil(t, modelWithEmbeddedModels) + require.NotNil(t, modelWithEmbeddedModels.EmbeddedEmptyModel) + require.NotNil(t, modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, 1, cap(modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.Equal(t, 1, len(modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, *modelWithMultipleFieldsAccessor, modelWithEmbeddedModels.EmbeddedModelArrayWithMultipleFieldsAccessor[0]) + + modelWithEmbeddedModelsAndDescriptionData, err := os.ReadFile("../../test_data/model_with_embedded_models_and_description.bin") + require.NoError(t, err) + modelWithEmbeddedModelsAndDescription, err := DecodeModelWithEmbeddedModelsAndDescription(nil, modelWithEmbeddedModelsAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithEmbeddedModelsAndDescription) + require.NotNil(t, modelWithEmbeddedModelsAndDescription.EmbeddedEmptyModel) + require.NotNil(t, modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, 1, cap(modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.Equal(t, 1, len(modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, *modelWithMultipleFieldsAccessor, modelWithEmbeddedModelsAndDescription.EmbeddedModelArrayWithMultipleFieldsAccessor[0]) + + modelWithEmbeddedModelsAccessorData, err := os.ReadFile("../../test_data/model_with_embedded_models_accessor.bin") + require.NoError(t, err) + modelWithEmbeddedModelsAccessor, err := DecodeModelWithEmbeddedModelsAccessor(nil, modelWithEmbeddedModelsAccessorData) + require.NoError(t, err) + require.NotNil(t, modelWithEmbeddedModelsAccessor) + embeddedEmptyModel, err := modelWithEmbeddedModelsAccessor.GetEmbeddedEmptyModel() + require.NoError(t, err) + require.NotNil(t, embeddedEmptyModel) + embeddedModelArrayWithMultipleFieldsAccessor, err := modelWithEmbeddedModelsAccessor.GetEmbeddedModelArrayWithMultipleFieldsAccessor() + require.NoError(t, err) + require.Equal(t, 1, cap(embeddedModelArrayWithMultipleFieldsAccessor)) + require.Equal(t, 1, len(embeddedModelArrayWithMultipleFieldsAccessor)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, embeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, *modelWithMultipleFieldsAccessor, embeddedModelArrayWithMultipleFieldsAccessor[0]) + + modelWithEmbeddedModelsAccessorAndDescriptionData, err := os.ReadFile("../../test_data/model_with_embedded_models_accessor_and_description.bin") + require.NoError(t, err) + modelWithEmbeddedModelsAccessorAndDescription, err := DecodeModelWithEmbeddedModelsAccessorAndDescription(nil, modelWithEmbeddedModelsAccessorAndDescriptionData) + require.NoError(t, err) + require.NotNil(t, modelWithEmbeddedModelsAccessorAndDescription) + embeddedEmptyModel, err = modelWithEmbeddedModelsAccessorAndDescription.GetEmbeddedEmptyModel() + require.NoError(t, err) + require.NotNil(t, embeddedEmptyModel) + embeddedModelArrayWithMultipleFieldsAccessor, err = modelWithEmbeddedModelsAccessorAndDescription.GetEmbeddedModelArrayWithMultipleFieldsAccessor() + require.NoError(t, err) + require.Equal(t, 1, cap(embeddedModelArrayWithMultipleFieldsAccessor)) + require.Equal(t, 1, len(embeddedModelArrayWithMultipleFieldsAccessor)) + require.IsType(t, []ModelWithMultipleFieldsAccessor{}, embeddedModelArrayWithMultipleFieldsAccessor) + require.Equal(t, *modelWithMultipleFieldsAccessor, embeddedModelArrayWithMultipleFieldsAccessor[0]) + + modelWithAllFieldTypesData, err := os.ReadFile("../../test_data/model_with_all_field_types.bin") + require.NoError(t, err) + modelWithAllFieldTypes, err := DecodeModelWithAllFieldTypes(nil, modelWithAllFieldTypesData) + require.NoError(t, err) + require.NotNil(t, modelWithAllFieldTypes) + + require.Equal(t, "hello world", modelWithAllFieldTypes.StringField) + require.Equal(t, 2, len(modelWithAllFieldTypes.StringArrayField)) + require.Equal(t, "hello", modelWithAllFieldTypes.StringArrayField[0]) + require.Equal(t, "world", modelWithAllFieldTypes.StringArrayField[1]) + require.Equal(t, "world", modelWithAllFieldTypes.StringMapField["hello"]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.StringMapFieldEmbedded["hello"]) + + require.Equal(t, int32(42), modelWithAllFieldTypes.Int32Field) + require.Equal(t, 2, len(modelWithAllFieldTypes.Int32ArrayField)) + require.Equal(t, int32(42), modelWithAllFieldTypes.Int32ArrayField[0]) + require.Equal(t, int32(84), modelWithAllFieldTypes.Int32ArrayField[1]) + require.Equal(t, int32(84), modelWithAllFieldTypes.Int32MapField[42]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.Int32MapFieldEmbedded[42]) + + require.Equal(t, int64(100), modelWithAllFieldTypes.Int64Field) + require.Equal(t, 2, len(modelWithAllFieldTypes.Int64ArrayField)) + require.Equal(t, int64(100), modelWithAllFieldTypes.Int64ArrayField[0]) + require.Equal(t, int64(200), modelWithAllFieldTypes.Int64ArrayField[1]) + require.Equal(t, int64(200), modelWithAllFieldTypes.Int64MapField[100]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.Int64MapFieldEmbedded[100]) + + require.Equal(t, uint32(42), modelWithAllFieldTypes.Uint32Field) + require.Equal(t, 2, len(modelWithAllFieldTypes.Uint32ArrayField)) + require.Equal(t, uint32(42), modelWithAllFieldTypes.Uint32ArrayField[0]) + require.Equal(t, uint32(84), modelWithAllFieldTypes.Uint32ArrayField[1]) + require.Equal(t, uint32(84), modelWithAllFieldTypes.Uint32MapField[42]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.Uint32MapFieldEmbedded[42]) + + require.Equal(t, uint64(100), modelWithAllFieldTypes.Uint64Field) + require.Equal(t, 2, len(modelWithAllFieldTypes.Uint64ArrayField)) + require.Equal(t, uint64(100), modelWithAllFieldTypes.Uint64ArrayField[0]) + require.Equal(t, uint64(200), modelWithAllFieldTypes.Uint64ArrayField[1]) + require.Equal(t, uint64(200), modelWithAllFieldTypes.Uint64MapField[100]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.Uint64MapFieldEmbedded[100]) + + require.Equal(t, float32(42.0), modelWithAllFieldTypes.Float32Field) + require.Equal(t, 2, len(modelWithAllFieldTypes.Float32ArrayField)) + require.Equal(t, float32(42.0), modelWithAllFieldTypes.Float32ArrayField[0]) + require.Equal(t, float32(84.0), modelWithAllFieldTypes.Float32ArrayField[1]) + + require.Equal(t, float64(100.0), modelWithAllFieldTypes.Float64Field) + require.Equal(t, 2, len(modelWithAllFieldTypes.Float64ArrayField)) + require.Equal(t, float64(100.0), modelWithAllFieldTypes.Float64ArrayField[0]) + require.Equal(t, float64(200.0), modelWithAllFieldTypes.Float64ArrayField[1]) + + require.Equal(t, false, modelWithAllFieldTypes.BoolField) + require.Equal(t, 2, len(modelWithAllFieldTypes.BoolArrayField)) + require.Equal(t, true, modelWithAllFieldTypes.BoolArrayField[0]) + require.Equal(t, false, modelWithAllFieldTypes.BoolArrayField[1]) + + require.Equal(t, []byte{42, 84}, modelWithAllFieldTypes.BytesField) + require.Equal(t, 2, len(modelWithAllFieldTypes.BytesArrayField)) + require.Equal(t, []byte{42, 84}, modelWithAllFieldTypes.BytesArrayField[0]) + require.Equal(t, []byte{84, 42}, modelWithAllFieldTypes.BytesArrayField[1]) + + require.Equal(t, GenericEnumSecondValue, modelWithAllFieldTypes.EnumField) + require.Equal(t, 2, len(modelWithAllFieldTypes.EnumArrayField)) + require.Equal(t, GenericEnumFirstValue, modelWithAllFieldTypes.EnumArrayField[0]) + require.Equal(t, GenericEnumSecondValue, modelWithAllFieldTypes.EnumArrayField[1]) + require.Equal(t, "hello world", modelWithAllFieldTypes.EnumMapField[GenericEnumFirstValue]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.EnumMapFieldEmbedded[GenericEnumFirstValue]) + + require.Equal(t, 2, len(modelWithAllFieldTypes.ModelArrayField)) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.ModelArrayField[0]) + require.Equal(t, *emptyModel, modelWithAllFieldTypes.ModelArrayField[1]) +} diff --git a/integration/golang_ext_tests/signature/types.go b/integration/golang_ext_tests/signature/types.go new file mode 100644 index 00000000..c8a7fefc --- /dev/null +++ b/integration/golang_ext_tests/signature/types.go @@ -0,0 +1,1983 @@ +// Code generated by scale-signature v0.4.5, DO NOT EDIT. +// output: signature + +package signature + +import ( + "errors" + "fmt" + "github.com/loopholelabs/polyglot" + "regexp" + "strings" +) + +var ( + NilDecode = errors.New("cannot decode into a nil root struct") + InvalidEnum = errors.New("invalid enum value") +) + +type GenericEnum uint32 + +const ( + GenericEnumFirstValue GenericEnum = 0 + + GenericEnumSecondValue GenericEnum = 1 + + GenericEnumDefaultValue GenericEnum = 2 +) + +func decodeGenericEnum(d *polyglot.Decoder) (GenericEnum, error) { + enumValue, err := d.Uint32() + if err != nil { + return 0, err + } + switch GenericEnum(enumValue) { + case GenericEnumFirstValue: + return GenericEnumFirstValue, nil + case GenericEnumSecondValue: + return GenericEnumSecondValue, nil + case GenericEnumDefaultValue: + return GenericEnumDefaultValue, nil + default: + return 0, InvalidEnum + } +} + +type EmptyModel struct { +} + +func NewEmptyModel() *EmptyModel { + return &EmptyModel{} +} + +func (x *EmptyModel) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + } +} + +func DecodeEmptyModel(x *EmptyModel, b []byte) (*EmptyModel, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeEmptyModel(x, d) +} + +func _decodeEmptyModel(x *EmptyModel, d *polyglot.Decoder) (*EmptyModel, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewEmptyModel() + } + + return x, nil +} + +// EmptyModelWithDescription: Test Description +type EmptyModelWithDescription struct { +} + +func NewEmptyModelWithDescription() *EmptyModelWithDescription { + return &EmptyModelWithDescription{} +} + +func (x *EmptyModelWithDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + } +} + +func DecodeEmptyModelWithDescription(x *EmptyModelWithDescription, b []byte) (*EmptyModelWithDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeEmptyModelWithDescription(x, d) +} + +func _decodeEmptyModelWithDescription(x *EmptyModelWithDescription, d *polyglot.Decoder) (*EmptyModelWithDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewEmptyModelWithDescription() + } + + return x, nil +} + +type ModelWithSingleStringField struct { + StringField string +} + +func NewModelWithSingleStringField() *ModelWithSingleStringField { + return &ModelWithSingleStringField{ + + StringField: "DefaultValue", + } +} + +func (x *ModelWithSingleStringField) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + } +} + +func DecodeModelWithSingleStringField(x *ModelWithSingleStringField, b []byte) (*ModelWithSingleStringField, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleStringField(x, d) +} + +func _decodeModelWithSingleStringField(x *ModelWithSingleStringField, d *polyglot.Decoder) (*ModelWithSingleStringField, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleStringField() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithSingleStringFieldAndDescription: Test Description +type ModelWithSingleStringFieldAndDescription struct { + StringField string +} + +func NewModelWithSingleStringFieldAndDescription() *ModelWithSingleStringFieldAndDescription { + return &ModelWithSingleStringFieldAndDescription{ + + StringField: "DefaultValue", + } +} + +func (x *ModelWithSingleStringFieldAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + } +} + +func DecodeModelWithSingleStringFieldAndDescription(x *ModelWithSingleStringFieldAndDescription, b []byte) (*ModelWithSingleStringFieldAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleStringFieldAndDescription(x, d) +} + +func _decodeModelWithSingleStringFieldAndDescription(x *ModelWithSingleStringFieldAndDescription, d *polyglot.Decoder) (*ModelWithSingleStringFieldAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleStringFieldAndDescription() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithSingleInt32Field struct { + Int32Field int32 +} + +func NewModelWithSingleInt32Field() *ModelWithSingleInt32Field { + return &ModelWithSingleInt32Field{ + + Int32Field: 32, + } +} + +func (x *ModelWithSingleInt32Field) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithSingleInt32Field(x *ModelWithSingleInt32Field, b []byte) (*ModelWithSingleInt32Field, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleInt32Field(x, d) +} + +func _decodeModelWithSingleInt32Field(x *ModelWithSingleInt32Field, d *polyglot.Decoder) (*ModelWithSingleInt32Field, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleInt32Field() + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithSingleInt32FieldAndDescription: Test Description +type ModelWithSingleInt32FieldAndDescription struct { + Int32Field int32 +} + +func NewModelWithSingleInt32FieldAndDescription() *ModelWithSingleInt32FieldAndDescription { + return &ModelWithSingleInt32FieldAndDescription{ + + Int32Field: 32, + } +} + +func (x *ModelWithSingleInt32FieldAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithSingleInt32FieldAndDescription(x *ModelWithSingleInt32FieldAndDescription, b []byte) (*ModelWithSingleInt32FieldAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithSingleInt32FieldAndDescription(x, d) +} + +func _decodeModelWithSingleInt32FieldAndDescription(x *ModelWithSingleInt32FieldAndDescription, d *polyglot.Decoder) (*ModelWithSingleInt32FieldAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithSingleInt32FieldAndDescription() + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithMultipleFields struct { + StringField string + + Int32Field int32 +} + +func NewModelWithMultipleFields() *ModelWithMultipleFields { + return &ModelWithMultipleFields{ + + StringField: "DefaultValue", + + Int32Field: 32, + } +} + +func (x *ModelWithMultipleFields) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithMultipleFields(x *ModelWithMultipleFields, b []byte) (*ModelWithMultipleFields, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFields(x, d) +} + +func _decodeModelWithMultipleFields(x *ModelWithMultipleFields, d *polyglot.Decoder) (*ModelWithMultipleFields, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFields() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +// ModelWithMultipleFieldsAndDescription: Test Description +type ModelWithMultipleFieldsAndDescription struct { + StringField string + + Int32Field int32 +} + +func NewModelWithMultipleFieldsAndDescription() *ModelWithMultipleFieldsAndDescription { + return &ModelWithMultipleFieldsAndDescription{ + + StringField: "DefaultValue", + + Int32Field: 32, + } +} + +func (x *ModelWithMultipleFieldsAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.StringField) + + e.Int32(x.Int32Field) + + } +} + +func DecodeModelWithMultipleFieldsAndDescription(x *ModelWithMultipleFieldsAndDescription, b []byte) (*ModelWithMultipleFieldsAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFieldsAndDescription(x, d) +} + +func _decodeModelWithMultipleFieldsAndDescription(x *ModelWithMultipleFieldsAndDescription, d *polyglot.Decoder) (*ModelWithMultipleFieldsAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFieldsAndDescription() + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +type ModelWithEnum struct { + EnumField GenericEnum +} + +func NewModelWithEnum() *ModelWithEnum { + return &ModelWithEnum{ + + EnumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnum) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.EnumField)) + + } +} + +func DecodeModelWithEnum(x *ModelWithEnum, b []byte) (*ModelWithEnum, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnum(x, d) +} + +func _decodeModelWithEnum(x *ModelWithEnum, d *polyglot.Decoder) (*ModelWithEnum, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnum() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + return x, nil +} + +// ModelWithEnumAndDescription: Test Description +type ModelWithEnumAndDescription struct { + EnumField GenericEnum +} + +func NewModelWithEnumAndDescription() *ModelWithEnumAndDescription { + return &ModelWithEnumAndDescription{ + + EnumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnumAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.EnumField)) + + } +} + +func DecodeModelWithEnumAndDescription(x *ModelWithEnumAndDescription, b []byte) (*ModelWithEnumAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnumAndDescription(x, d) +} + +func _decodeModelWithEnumAndDescription(x *ModelWithEnumAndDescription, d *polyglot.Decoder) (*ModelWithEnumAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnumAndDescription() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + return x, nil +} + +type ModelWithEnumAccessor struct { + enumField GenericEnum +} + +func NewModelWithEnumAccessor() *ModelWithEnumAccessor { + return &ModelWithEnumAccessor{ + + enumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnumAccessor) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.enumField)) + + } +} + +func DecodeModelWithEnumAccessor(x *ModelWithEnumAccessor, b []byte) (*ModelWithEnumAccessor, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnumAccessor(x, d) +} + +func _decodeModelWithEnumAccessor(x *ModelWithEnumAccessor, d *polyglot.Decoder) (*ModelWithEnumAccessor, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnumAccessor() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.enumField = result + + return x, nil +} + +func (x *ModelWithEnumAccessor) GetEnumField() (GenericEnum, error) { + return x.enumField, nil +} + +func (x *ModelWithEnumAccessor) SetEnumField(v GenericEnum) error { + x.enumField = v + return nil +} + +// ModelWithEnumAccessorAndDescription: Test Description +type ModelWithEnumAccessorAndDescription struct { + enumField GenericEnum +} + +func NewModelWithEnumAccessorAndDescription() *ModelWithEnumAccessorAndDescription { + return &ModelWithEnumAccessorAndDescription{ + + enumField: GenericEnumDefaultValue, + } +} + +func (x *ModelWithEnumAccessorAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.Uint32(uint32(x.enumField)) + + } +} + +func DecodeModelWithEnumAccessorAndDescription(x *ModelWithEnumAccessorAndDescription, b []byte) (*ModelWithEnumAccessorAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEnumAccessorAndDescription(x, d) +} + +func _decodeModelWithEnumAccessorAndDescription(x *ModelWithEnumAccessorAndDescription, d *polyglot.Decoder) (*ModelWithEnumAccessorAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEnumAccessorAndDescription() + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.enumField = result + + return x, nil +} + +func (x *ModelWithEnumAccessorAndDescription) GetEnumField() (GenericEnum, error) { + return x.enumField, nil +} + +func (x *ModelWithEnumAccessorAndDescription) SetEnumField(v GenericEnum) error { + x.enumField = v + return nil +} + +type ModelWithMultipleFieldsAccessor struct { + stringField string + + int32Field int32 +} + +func NewModelWithMultipleFieldsAccessor() *ModelWithMultipleFieldsAccessor { + return &ModelWithMultipleFieldsAccessor{ + + stringField: "DefaultValue", + + int32Field: 32, + } +} + +func (x *ModelWithMultipleFieldsAccessor) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.stringField) + + e.Int32(x.int32Field) + + } +} + +func DecodeModelWithMultipleFieldsAccessor(x *ModelWithMultipleFieldsAccessor, b []byte) (*ModelWithMultipleFieldsAccessor, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFieldsAccessor(x, d) +} + +func _decodeModelWithMultipleFieldsAccessor(x *ModelWithMultipleFieldsAccessor, d *polyglot.Decoder) (*ModelWithMultipleFieldsAccessor, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFieldsAccessor() + } + + x.stringField, err = d.String() + if err != nil { + return nil, err + } + + x.int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +func (x *ModelWithMultipleFieldsAccessor) GetStringField() (string, error) { + return x.stringField, nil +} + +func (x *ModelWithMultipleFieldsAccessor) SetStringField(v string) error { + if matched, err := regexp.MatchString(`^[a-zA-Z0-9]*$`, v); err != nil || !matched { + return fmt.Errorf("value must match ^[a-zA-Z0-9]*$") + } + + if len(v) > 20 || len(v) < 1 { + return fmt.Errorf("length must be between 1 and 20") + } + + v = strings.ToUpper(v) + + x.stringField = v + return nil +} + +func (x *ModelWithMultipleFieldsAccessor) GetInt32Field() (int32, error) { + return x.int32Field, nil +} + +func (x *ModelWithMultipleFieldsAccessor) SetInt32Field(v int32) error { + if v > 100 || v < 0 { + return fmt.Errorf("value must be between 0 and 100") + } + + x.int32Field = v + return nil +} + +// ModelWithMultipleFieldsAccessorAndDescription: Test Description +type ModelWithMultipleFieldsAccessorAndDescription struct { + stringField string + + int32Field int32 +} + +func NewModelWithMultipleFieldsAccessorAndDescription() *ModelWithMultipleFieldsAccessorAndDescription { + return &ModelWithMultipleFieldsAccessorAndDescription{ + + stringField: "DefaultValue", + + int32Field: 32, + } +} + +func (x *ModelWithMultipleFieldsAccessorAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + e.String(x.stringField) + + e.Int32(x.int32Field) + + } +} + +func DecodeModelWithMultipleFieldsAccessorAndDescription(x *ModelWithMultipleFieldsAccessorAndDescription, b []byte) (*ModelWithMultipleFieldsAccessorAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithMultipleFieldsAccessorAndDescription(x, d) +} + +func _decodeModelWithMultipleFieldsAccessorAndDescription(x *ModelWithMultipleFieldsAccessorAndDescription, d *polyglot.Decoder) (*ModelWithMultipleFieldsAccessorAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithMultipleFieldsAccessorAndDescription() + } + + x.stringField, err = d.String() + if err != nil { + return nil, err + } + + x.int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + return x, nil +} + +func (x *ModelWithMultipleFieldsAccessorAndDescription) GetStringField() (string, error) { + return x.stringField, nil +} + +func (x *ModelWithMultipleFieldsAccessorAndDescription) SetStringField(v string) error { + + x.stringField = v + return nil +} + +func (x *ModelWithMultipleFieldsAccessorAndDescription) GetInt32Field() (int32, error) { + return x.int32Field, nil +} + +func (x *ModelWithMultipleFieldsAccessorAndDescription) SetInt32Field(v int32) error { + + x.int32Field = v + return nil +} + +type ModelWithEmbeddedModels struct { + EmbeddedEmptyModel *EmptyModel + + EmbeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModels() *ModelWithEmbeddedModels { + return &ModelWithEmbeddedModels{ + + EmbeddedEmptyModel: NewEmptyModel(), + + EmbeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0, 64), + } +} + +func (x *ModelWithEmbeddedModels) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.EmbeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.EmbeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModels(x *ModelWithEmbeddedModels, b []byte) (*ModelWithEmbeddedModels, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModels(x, d) +} + +func _decodeModelWithEmbeddedModels(x *ModelWithEmbeddedModels, d *polyglot.Decoder) (*ModelWithEmbeddedModels, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModels() + } + + x.EmbeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor { + x.EmbeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.EmbeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +// ModelWithEmbeddedModelsAndDescription: Test Description +type ModelWithEmbeddedModelsAndDescription struct { + EmbeddedEmptyModel *EmptyModel + + EmbeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModelsAndDescription() *ModelWithEmbeddedModelsAndDescription { + return &ModelWithEmbeddedModelsAndDescription{ + + EmbeddedEmptyModel: NewEmptyModel(), + + EmbeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0, 0), + } +} + +func (x *ModelWithEmbeddedModelsAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.EmbeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.EmbeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModelsAndDescription(x *ModelWithEmbeddedModelsAndDescription, b []byte) (*ModelWithEmbeddedModelsAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModelsAndDescription(x, d) +} + +func _decodeModelWithEmbeddedModelsAndDescription(x *ModelWithEmbeddedModelsAndDescription, d *polyglot.Decoder) (*ModelWithEmbeddedModelsAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModelsAndDescription() + } + + x.EmbeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.EmbeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor { + x.EmbeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeEmbeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.EmbeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +type ModelWithEmbeddedModelsAccessor struct { + embeddedEmptyModel *EmptyModel + + embeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModelsAccessor() *ModelWithEmbeddedModelsAccessor { + return &ModelWithEmbeddedModelsAccessor{ + + embeddedEmptyModel: NewEmptyModel(), + + embeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0), + } +} + +func (x *ModelWithEmbeddedModelsAccessor) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.embeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.embeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.embeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModelsAccessor(x *ModelWithEmbeddedModelsAccessor, b []byte) (*ModelWithEmbeddedModelsAccessor, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModelsAccessor(x, d) +} + +func _decodeModelWithEmbeddedModelsAccessor(x *ModelWithEmbeddedModelsAccessor, d *polyglot.Decoder) (*ModelWithEmbeddedModelsAccessor, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModelsAccessor() + } + + x.embeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeembeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.embeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeembeddedModelArrayWithMultipleFieldsAccessor { + x.embeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeembeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeembeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.embeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +func (x *ModelWithEmbeddedModelsAccessor) GetEmbeddedEmptyModel() (*EmptyModel, error) { + return x.embeddedEmptyModel, nil +} + +func (x *ModelWithEmbeddedModelsAccessor) SetEmbeddedEmptyModel(v *EmptyModel) error { + x.embeddedEmptyModel = v + return nil +} + +func (x *ModelWithEmbeddedModelsAccessor) GetEmbeddedModelArrayWithMultipleFieldsAccessor() ([]ModelWithMultipleFieldsAccessor, error) { + return x.embeddedModelArrayWithMultipleFieldsAccessor, nil +} + +func (x *ModelWithEmbeddedModelsAccessor) SetEmbeddedModelArrayWithMultipleFieldsAccessor(v []ModelWithMultipleFieldsAccessor) error { + x.embeddedModelArrayWithMultipleFieldsAccessor = v + return nil +} + +// ModelWithEmbeddedModelsAccessorAndDescription: Test Description +type ModelWithEmbeddedModelsAccessorAndDescription struct { + embeddedEmptyModel *EmptyModel + + embeddedModelArrayWithMultipleFieldsAccessor []ModelWithMultipleFieldsAccessor +} + +func NewModelWithEmbeddedModelsAccessorAndDescription() *ModelWithEmbeddedModelsAccessorAndDescription { + return &ModelWithEmbeddedModelsAccessorAndDescription{ + + embeddedEmptyModel: NewEmptyModel(), + + embeddedModelArrayWithMultipleFieldsAccessor: make([]ModelWithMultipleFieldsAccessor, 0), + } +} + +func (x *ModelWithEmbeddedModelsAccessorAndDescription) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.embeddedEmptyModel.Encode(b) + + e.Slice(uint32(len(x.embeddedModelArrayWithMultipleFieldsAccessor)), polyglot.AnyKind) + for _, a := range x.embeddedModelArrayWithMultipleFieldsAccessor { + a.Encode(b) + } + + } +} + +func DecodeModelWithEmbeddedModelsAccessorAndDescription(x *ModelWithEmbeddedModelsAccessorAndDescription, b []byte) (*ModelWithEmbeddedModelsAccessorAndDescription, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithEmbeddedModelsAccessorAndDescription(x, d) +} + +func _decodeModelWithEmbeddedModelsAccessorAndDescription(x *ModelWithEmbeddedModelsAccessorAndDescription, d *polyglot.Decoder) (*ModelWithEmbeddedModelsAccessorAndDescription, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithEmbeddedModelsAccessorAndDescription() + } + + x.embeddedEmptyModel, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeembeddedModelArrayWithMultipleFieldsAccessor, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.embeddedModelArrayWithMultipleFieldsAccessor)) != sliceSizeembeddedModelArrayWithMultipleFieldsAccessor { + x.embeddedModelArrayWithMultipleFieldsAccessor = make([]ModelWithMultipleFieldsAccessor, sliceSizeembeddedModelArrayWithMultipleFieldsAccessor) + } + for i := uint32(0); i < sliceSizeembeddedModelArrayWithMultipleFieldsAccessor; i++ { + v, err := _decodeModelWithMultipleFieldsAccessor(nil, d) + if err != nil { + return nil, err + } + x.embeddedModelArrayWithMultipleFieldsAccessor[i] = *v + } + + return x, nil +} + +func (x *ModelWithEmbeddedModelsAccessorAndDescription) GetEmbeddedEmptyModel() (*EmptyModel, error) { + return x.embeddedEmptyModel, nil +} + +func (x *ModelWithEmbeddedModelsAccessorAndDescription) SetEmbeddedEmptyModel(v *EmptyModel) error { + x.embeddedEmptyModel = v + return nil +} + +func (x *ModelWithEmbeddedModelsAccessorAndDescription) GetEmbeddedModelArrayWithMultipleFieldsAccessor() ([]ModelWithMultipleFieldsAccessor, error) { + return x.embeddedModelArrayWithMultipleFieldsAccessor, nil +} + +func (x *ModelWithEmbeddedModelsAccessorAndDescription) SetEmbeddedModelArrayWithMultipleFieldsAccessor(v []ModelWithMultipleFieldsAccessor) error { + x.embeddedModelArrayWithMultipleFieldsAccessor = v + return nil +} + +type ModelWithAllFieldTypes struct { + ModelField *EmptyModel + + ModelArrayField []EmptyModel + + StringField string + + StringArrayField []string + + StringMapField map[string]string + + StringMapFieldEmbedded map[string]EmptyModel + + Int32Field int32 + + Int32ArrayField []int32 + + Int32MapField map[int32]int32 + + Int32MapFieldEmbedded map[int32]EmptyModel + + Int64Field int64 + + Int64ArrayField []int64 + + Int64MapField map[int64]int64 + + Int64MapFieldEmbedded map[int64]EmptyModel + + Uint32Field uint32 + + Uint32ArrayField []uint32 + + Uint32MapField map[uint32]uint32 + + Uint32MapFieldEmbedded map[uint32]EmptyModel + + Uint64Field uint64 + + Uint64ArrayField []uint64 + + Uint64MapField map[uint64]uint64 + + Uint64MapFieldEmbedded map[uint64]EmptyModel + + Float32Field float32 + + Float32ArrayField []float32 + + Float64Field float64 + + Float64ArrayField []float64 + + EnumField GenericEnum + + EnumArrayField []GenericEnum + + EnumMapField map[GenericEnum]string + + EnumMapFieldEmbedded map[GenericEnum]EmptyModel + + BytesField []byte + + BytesArrayField [][]byte + + BoolField bool + + BoolArrayField []bool +} + +func NewModelWithAllFieldTypes() *ModelWithAllFieldTypes { + return &ModelWithAllFieldTypes{ + + ModelField: NewEmptyModel(), + + ModelArrayField: make([]EmptyModel, 0, 0), + + StringField: "DefaultValue", + + StringArrayField: make([]string, 0, 0), + + StringMapField: make(map[string]string), + + StringMapFieldEmbedded: make(map[string]EmptyModel), + + Int32Field: 32, + + Int32ArrayField: make([]int32, 0, 0), + + Int32MapField: make(map[int32]int32), + + Int32MapFieldEmbedded: make(map[int32]EmptyModel), + + Int64Field: 64, + + Int64ArrayField: make([]int64, 0, 0), + + Int64MapField: make(map[int64]int64), + + Int64MapFieldEmbedded: make(map[int64]EmptyModel), + + Uint32Field: 32, + + Uint32ArrayField: make([]uint32, 0, 0), + + Uint32MapField: make(map[uint32]uint32), + + Uint32MapFieldEmbedded: make(map[uint32]EmptyModel), + + Uint64Field: 64, + + Uint64ArrayField: make([]uint64, 0, 0), + + Uint64MapField: make(map[uint64]uint64), + + Uint64MapFieldEmbedded: make(map[uint64]EmptyModel), + + Float32Field: 32.32, + + Float32ArrayField: make([]float32, 0, 0), + + Float64Field: 64.64, + + Float64ArrayField: make([]float64, 0, 0), + + EnumField: GenericEnumDefaultValue, + + EnumArrayField: make([]GenericEnum, 0, 0), + + EnumMapField: make(map[GenericEnum]string), + + EnumMapFieldEmbedded: make(map[GenericEnum]EmptyModel), + + BytesField: make([]byte, 0, 512), + + BytesArrayField: make([][]byte, 0, 0), + + BoolField: true, + + BoolArrayField: make([]bool, 0, 0), + } +} + +func (x *ModelWithAllFieldTypes) Encode(b *polyglot.Buffer) { + e := polyglot.Encoder(b) + if x == nil { + e.Nil() + } else { + + x.ModelField.Encode(b) + + e.Slice(uint32(len(x.ModelArrayField)), polyglot.AnyKind) + for _, a := range x.ModelArrayField { + a.Encode(b) + } + + e.String(x.StringField) + + e.Slice(uint32(len(x.StringArrayField)), polyglot.StringKind) + for _, a := range x.StringArrayField { + e.String(a) + } + + e.Map(uint32(len(x.StringMapField)), polyglot.StringKind, polyglot.StringKind) + for k, v := range x.StringMapField { + e.String(k) + e.String(v) + } + + e.Map(uint32(len(x.StringMapFieldEmbedded)), polyglot.StringKind, polyglot.AnyKind) + for k, v := range x.StringMapFieldEmbedded { + e.String(k) + v.Encode(b) + } + + e.Int32(x.Int32Field) + + e.Slice(uint32(len(x.Int32ArrayField)), polyglot.Int32Kind) + for _, a := range x.Int32ArrayField { + e.Int32(a) + } + + e.Map(uint32(len(x.Int32MapField)), polyglot.Int32Kind, polyglot.Int32Kind) + for k, v := range x.Int32MapField { + e.Int32(k) + e.Int32(v) + } + + e.Map(uint32(len(x.Int32MapFieldEmbedded)), polyglot.Int32Kind, polyglot.AnyKind) + for k, v := range x.Int32MapFieldEmbedded { + e.Int32(k) + v.Encode(b) + } + + e.Int64(x.Int64Field) + + e.Slice(uint32(len(x.Int64ArrayField)), polyglot.Int64Kind) + for _, a := range x.Int64ArrayField { + e.Int64(a) + } + + e.Map(uint32(len(x.Int64MapField)), polyglot.Int64Kind, polyglot.Int64Kind) + for k, v := range x.Int64MapField { + e.Int64(k) + e.Int64(v) + } + + e.Map(uint32(len(x.Int64MapFieldEmbedded)), polyglot.Int64Kind, polyglot.AnyKind) + for k, v := range x.Int64MapFieldEmbedded { + e.Int64(k) + v.Encode(b) + } + + e.Uint32(x.Uint32Field) + + e.Slice(uint32(len(x.Uint32ArrayField)), polyglot.Uint32Kind) + for _, a := range x.Uint32ArrayField { + e.Uint32(a) + } + + e.Map(uint32(len(x.Uint32MapField)), polyglot.Uint32Kind, polyglot.Uint32Kind) + for k, v := range x.Uint32MapField { + e.Uint32(k) + e.Uint32(v) + } + + e.Map(uint32(len(x.Uint32MapFieldEmbedded)), polyglot.Uint32Kind, polyglot.AnyKind) + for k, v := range x.Uint32MapFieldEmbedded { + e.Uint32(k) + v.Encode(b) + } + + e.Uint64(x.Uint64Field) + + e.Slice(uint32(len(x.Uint64ArrayField)), polyglot.Uint64Kind) + for _, a := range x.Uint64ArrayField { + e.Uint64(a) + } + + e.Map(uint32(len(x.Uint64MapField)), polyglot.Uint64Kind, polyglot.Uint64Kind) + for k, v := range x.Uint64MapField { + e.Uint64(k) + e.Uint64(v) + } + + e.Map(uint32(len(x.Uint64MapFieldEmbedded)), polyglot.Uint64Kind, polyglot.AnyKind) + for k, v := range x.Uint64MapFieldEmbedded { + e.Uint64(k) + v.Encode(b) + } + + e.Float32(x.Float32Field) + + e.Slice(uint32(len(x.Float32ArrayField)), polyglot.Float32Kind) + for _, a := range x.Float32ArrayField { + e.Float32(a) + } + + e.Float64(x.Float64Field) + + e.Slice(uint32(len(x.Float64ArrayField)), polyglot.Float64Kind) + for _, a := range x.Float64ArrayField { + e.Float64(a) + } + + e.Uint32(uint32(x.EnumField)) + + e.Slice(uint32(len(x.EnumArrayField)), polyglot.Uint32Kind) + for _, a := range x.EnumArrayField { + e.Uint32(uint32(a)) + } + + e.Map(uint32(len(x.EnumMapField)), polyglot.Uint32Kind, polyglot.StringKind) + for k, v := range x.EnumMapField { + e.Uint32(uint32(k)) + e.String(v) + } + + e.Map(uint32(len(x.EnumMapFieldEmbedded)), polyglot.Uint32Kind, polyglot.AnyKind) + for k, v := range x.EnumMapFieldEmbedded { + e.Uint32(uint32(k)) + v.Encode(b) + } + + e.Bytes(x.BytesField) + + e.Slice(uint32(len(x.BytesArrayField)), polyglot.BytesKind) + for _, a := range x.BytesArrayField { + e.Bytes(a) + } + + e.Bool(x.BoolField) + + e.Slice(uint32(len(x.BoolArrayField)), polyglot.BoolKind) + for _, a := range x.BoolArrayField { + e.Bool(a) + } + + } +} + +func DecodeModelWithAllFieldTypes(x *ModelWithAllFieldTypes, b []byte) (*ModelWithAllFieldTypes, error) { + d := polyglot.GetDecoder(b) + defer d.Return() + return _decodeModelWithAllFieldTypes(x, d) +} + +func _decodeModelWithAllFieldTypes(x *ModelWithAllFieldTypes, d *polyglot.Decoder) (*ModelWithAllFieldTypes, error) { + if d.Nil() { + return nil, nil + } + + err, _ := d.Error() + if err != nil { + return nil, err + } + + if x == nil { + x = NewModelWithAllFieldTypes() + } + + x.ModelField, err = _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + + sliceSizeModelArrayField, err := d.Slice(polyglot.AnyKind) + if err != nil { + return nil, err + } + if uint32(len(x.ModelArrayField)) != sliceSizeModelArrayField { + x.ModelArrayField = make([]EmptyModel, sliceSizeModelArrayField) + } + for i := uint32(0); i < sliceSizeModelArrayField; i++ { + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.ModelArrayField[i] = *v + } + + x.StringField, err = d.String() + if err != nil { + return nil, err + } + + sliceSizeStringArrayField, err := d.Slice(polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.StringArrayField)) != sliceSizeStringArrayField { + x.StringArrayField = make([]string, sliceSizeStringArrayField) + } + + for i := uint32(0); i < sliceSizeStringArrayField; i++ { + x.StringArrayField[i], err = d.String() + if err != nil { + return nil, err + } + } + + mapSizeStringMapField, err := d.Map(polyglot.StringKind, polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.StringMapField)) != mapSizeStringMapField { + x.StringMapField = make(map[string]string, mapSizeStringMapField) + } + + for i := uint32(0); i < mapSizeStringMapField; i++ { + k, err := d.String() + if err != nil { + return nil, err + } + x.StringMapField[k], err = d.String() + if err != nil { + return nil, err + } + } + + mapSizeStringMapFieldEmbedded, err := d.Map(polyglot.StringKind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.StringMapFieldEmbedded)) != mapSizeStringMapFieldEmbedded { + x.StringMapFieldEmbedded = make(map[string]EmptyModel, mapSizeStringMapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeStringMapFieldEmbedded; i++ { + k, err := d.String() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.StringMapFieldEmbedded[k] = *v + } + + x.Int32Field, err = d.Int32() + if err != nil { + return nil, err + } + + sliceSizeInt32ArrayField, err := d.Slice(polyglot.Int32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int32ArrayField)) != sliceSizeInt32ArrayField { + x.Int32ArrayField = make([]int32, sliceSizeInt32ArrayField) + } + + for i := uint32(0); i < sliceSizeInt32ArrayField; i++ { + x.Int32ArrayField[i], err = d.Int32() + if err != nil { + return nil, err + } + } + + mapSizeInt32MapField, err := d.Map(polyglot.Int32Kind, polyglot.Int32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int32MapField)) != mapSizeInt32MapField { + x.Int32MapField = make(map[int32]int32, mapSizeInt32MapField) + } + + for i := uint32(0); i < mapSizeInt32MapField; i++ { + k, err := d.Int32() + if err != nil { + return nil, err + } + x.Int32MapField[k], err = d.Int32() + if err != nil { + return nil, err + } + } + + mapSizeInt32MapFieldEmbedded, err := d.Map(polyglot.Int32Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int32MapFieldEmbedded)) != mapSizeInt32MapFieldEmbedded { + x.Int32MapFieldEmbedded = make(map[int32]EmptyModel, mapSizeInt32MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeInt32MapFieldEmbedded; i++ { + k, err := d.Int32() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Int32MapFieldEmbedded[k] = *v + } + + x.Int64Field, err = d.Int64() + if err != nil { + return nil, err + } + + sliceSizeInt64ArrayField, err := d.Slice(polyglot.Int64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int64ArrayField)) != sliceSizeInt64ArrayField { + x.Int64ArrayField = make([]int64, sliceSizeInt64ArrayField) + } + + for i := uint32(0); i < sliceSizeInt64ArrayField; i++ { + x.Int64ArrayField[i], err = d.Int64() + if err != nil { + return nil, err + } + } + + mapSizeInt64MapField, err := d.Map(polyglot.Int64Kind, polyglot.Int64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int64MapField)) != mapSizeInt64MapField { + x.Int64MapField = make(map[int64]int64, mapSizeInt64MapField) + } + + for i := uint32(0); i < mapSizeInt64MapField; i++ { + k, err := d.Int64() + if err != nil { + return nil, err + } + x.Int64MapField[k], err = d.Int64() + if err != nil { + return nil, err + } + } + + mapSizeInt64MapFieldEmbedded, err := d.Map(polyglot.Int64Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Int64MapFieldEmbedded)) != mapSizeInt64MapFieldEmbedded { + x.Int64MapFieldEmbedded = make(map[int64]EmptyModel, mapSizeInt64MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeInt64MapFieldEmbedded; i++ { + k, err := d.Int64() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Int64MapFieldEmbedded[k] = *v + } + + x.Uint32Field, err = d.Uint32() + if err != nil { + return nil, err + } + + sliceSizeUint32ArrayField, err := d.Slice(polyglot.Uint32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint32ArrayField)) != sliceSizeUint32ArrayField { + x.Uint32ArrayField = make([]uint32, sliceSizeUint32ArrayField) + } + + for i := uint32(0); i < sliceSizeUint32ArrayField; i++ { + x.Uint32ArrayField[i], err = d.Uint32() + if err != nil { + return nil, err + } + } + + mapSizeUint32MapField, err := d.Map(polyglot.Uint32Kind, polyglot.Uint32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint32MapField)) != mapSizeUint32MapField { + x.Uint32MapField = make(map[uint32]uint32, mapSizeUint32MapField) + } + + for i := uint32(0); i < mapSizeUint32MapField; i++ { + k, err := d.Uint32() + if err != nil { + return nil, err + } + x.Uint32MapField[k], err = d.Uint32() + if err != nil { + return nil, err + } + } + + mapSizeUint32MapFieldEmbedded, err := d.Map(polyglot.Uint32Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint32MapFieldEmbedded)) != mapSizeUint32MapFieldEmbedded { + x.Uint32MapFieldEmbedded = make(map[uint32]EmptyModel, mapSizeUint32MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeUint32MapFieldEmbedded; i++ { + k, err := d.Uint32() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Uint32MapFieldEmbedded[k] = *v + } + + x.Uint64Field, err = d.Uint64() + if err != nil { + return nil, err + } + + sliceSizeUint64ArrayField, err := d.Slice(polyglot.Uint64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint64ArrayField)) != sliceSizeUint64ArrayField { + x.Uint64ArrayField = make([]uint64, sliceSizeUint64ArrayField) + } + + for i := uint32(0); i < sliceSizeUint64ArrayField; i++ { + x.Uint64ArrayField[i], err = d.Uint64() + if err != nil { + return nil, err + } + } + + mapSizeUint64MapField, err := d.Map(polyglot.Uint64Kind, polyglot.Uint64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint64MapField)) != mapSizeUint64MapField { + x.Uint64MapField = make(map[uint64]uint64, mapSizeUint64MapField) + } + + for i := uint32(0); i < mapSizeUint64MapField; i++ { + k, err := d.Uint64() + if err != nil { + return nil, err + } + x.Uint64MapField[k], err = d.Uint64() + if err != nil { + return nil, err + } + } + + mapSizeUint64MapFieldEmbedded, err := d.Map(polyglot.Uint64Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.Uint64MapFieldEmbedded)) != mapSizeUint64MapFieldEmbedded { + x.Uint64MapFieldEmbedded = make(map[uint64]EmptyModel, mapSizeUint64MapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeUint64MapFieldEmbedded; i++ { + k, err := d.Uint64() + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.Uint64MapFieldEmbedded[k] = *v + } + + x.Float32Field, err = d.Float32() + if err != nil { + return nil, err + } + + sliceSizeFloat32ArrayField, err := d.Slice(polyglot.Float32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Float32ArrayField)) != sliceSizeFloat32ArrayField { + x.Float32ArrayField = make([]float32, sliceSizeFloat32ArrayField) + } + + for i := uint32(0); i < sliceSizeFloat32ArrayField; i++ { + x.Float32ArrayField[i], err = d.Float32() + if err != nil { + return nil, err + } + } + + x.Float64Field, err = d.Float64() + if err != nil { + return nil, err + } + + sliceSizeFloat64ArrayField, err := d.Slice(polyglot.Float64Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.Float64ArrayField)) != sliceSizeFloat64ArrayField { + x.Float64ArrayField = make([]float64, sliceSizeFloat64ArrayField) + } + + for i := uint32(0); i < sliceSizeFloat64ArrayField; i++ { + x.Float64ArrayField[i], err = d.Float64() + if err != nil { + return nil, err + } + } + + result, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumField = result + + sliceSizeEnumArrayField, err := d.Slice(polyglot.Uint32Kind) + if err != nil { + return nil, err + } + + if uint32(len(x.EnumArrayField)) != sliceSizeEnumArrayField { + x.EnumArrayField = make([]GenericEnum, sliceSizeEnumArrayField) + } + + for i := uint32(0); i < sliceSizeEnumArrayField; i++ { + val, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumArrayField[i] = val + } + + mapSizeEnumMapField, err := d.Map(polyglot.Uint32Kind, polyglot.StringKind) + if err != nil { + return nil, err + } + + if uint32(len(x.EnumMapField)) != mapSizeEnumMapField { + x.EnumMapField = make(map[GenericEnum]string, mapSizeEnumMapField) + } + + for i := uint32(0); i < mapSizeEnumMapField; i++ { + k, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + x.EnumMapField[k], err = d.String() + if err != nil { + return nil, err + } + } + + mapSizeEnumMapFieldEmbedded, err := d.Map(polyglot.Uint32Kind, polyglot.AnyKind) + if err != nil { + return nil, err + } + + if uint32(len(x.EnumMapFieldEmbedded)) != mapSizeEnumMapFieldEmbedded { + x.EnumMapFieldEmbedded = make(map[GenericEnum]EmptyModel, mapSizeEnumMapFieldEmbedded) + } + + for i := uint32(0); i < mapSizeEnumMapFieldEmbedded; i++ { + k, err := decodeGenericEnum(d) + if err != nil { + return nil, err + } + v, err := _decodeEmptyModel(nil, d) + if err != nil { + return nil, err + } + x.EnumMapFieldEmbedded[k] = *v + } + + x.BytesField, err = d.Bytes(nil) + if err != nil { + return nil, err + } + + sliceSizeBytesArrayField, err := d.Slice(polyglot.BytesKind) + if err != nil { + return nil, err + } + + if uint32(len(x.BytesArrayField)) != sliceSizeBytesArrayField { + x.BytesArrayField = make([][]byte, sliceSizeBytesArrayField) + } + + for i := uint32(0); i < sliceSizeBytesArrayField; i++ { + x.BytesArrayField[i], err = d.Bytes(nil) + if err != nil { + return nil, err + } + } + + x.BoolField, err = d.Bool() + if err != nil { + return nil, err + } + + sliceSizeBoolArrayField, err := d.Slice(polyglot.BoolKind) + if err != nil { + return nil, err + } + + if uint32(len(x.BoolArrayField)) != sliceSizeBoolArrayField { + x.BoolArrayField = make([]bool, sliceSizeBoolArrayField) + } + + for i := uint32(0); i < sliceSizeBoolArrayField; i++ { + x.BoolArrayField[i], err = d.Bool() + if err != nil { + return nil, err + } + } + + return x, nil +} diff --git a/integration/integration_ext_test.go b/integration/integration_ext_test.go new file mode 100644 index 00000000..8fef601f --- /dev/null +++ b/integration/integration_ext_test.go @@ -0,0 +1,270 @@ +//go:build integration && !generate + +/* + Copyright 2023 Loophole Labs + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package integration + +import ( + "context" + "encoding/hex" + "os" + "path/filepath" + "testing" + + "github.com/loopholelabs/scale" + "github.com/loopholelabs/scale/build" + "github.com/loopholelabs/scale/extension" + hostExtension "github.com/loopholelabs/scale/integration/golang_ext_tests/host_extension" + hostSignature "github.com/loopholelabs/scale/integration/golang_ext_tests/host_signature" + "github.com/loopholelabs/scale/scalefile" + "github.com/loopholelabs/scale/scalefunc" + "github.com/loopholelabs/scale/signature" + "github.com/loopholelabs/scale/storage" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func compileExtGolangGuest(t *testing.T) *scalefunc.V1BetaSchema { + wd, err := os.Getwd() + require.NoError(t, err) + + s := new(signature.Schema) + err = s.Decode([]byte(signature.MasterTestingSchema)) + require.NoError(t, err) + + hash, err := s.Hash() + require.NoError(t, err) + + golangCompileDir := wd + "/golang_ext_tests/compile" + err = os.MkdirAll(golangCompileDir, 0755) + require.NoError(t, err) + + t.Cleanup(func() { + err = os.RemoveAll(golangCompileDir) + require.NoError(t, err) + }) + + ex := new(extension.Schema) + err = ex.Decode([]byte(extensionSchema)) + + require.NoError(t, err) + + golangFunctionDir := wd + "/golang_ext_tests/function" + scf := &scalefile.Schema{ + Version: scalefile.V1AlphaVersion, + Name: "example", + Tag: "latest", + Language: string(scalefunc.Go), + Signature: scalefile.SignatureSchema{ + Organization: "local", + Name: "example", + Tag: "latest", + }, + Function: "Example", + Extensions: []scalefile.ExtensionSchema{ + { + Organization: "local", + Name: "example", + Tag: "latest", + }, + }, + } + + stb, err := storage.NewBuild(golangCompileDir) + require.NoError(t, err) + + ext_dir, err := filepath.Abs("golang_ext_tests/extension") + require.NoError(t, err) + + extensionInfo := []extension.Info{ + { + Name: "extension", + Path: ext_dir, + Version: "v0.1.0", + }, + } + + extensionSchemas := []*extension.Schema{ + ex, + } + + schema, err := build.LocalGolang(&build.LocalGolangOptions{ + Stdout: os.Stdout, + Scalefile: scf, + SourceDirectory: golangFunctionDir, + SignatureSchema: s, + Storage: stb, + Release: false, + Target: build.WASITarget, + Extensions: extensionInfo, + ExtensionSchemas: extensionSchemas, + }) + require.NoError(t, err) + + assert.Equal(t, scf.Name, schema.Name) + assert.Equal(t, scf.Tag, schema.Tag) + assert.Equal(t, scf.Signature.Name, schema.Signature.Name) + assert.Equal(t, scf.Signature.Organization, schema.Signature.Organization) + assert.Equal(t, scf.Signature.Tag, schema.Signature.Tag) + assert.Equal(t, s, schema.Signature.Schema) + assert.Equal(t, hex.EncodeToString(hash), schema.Signature.Hash) + assert.Equal(t, scalefunc.Go, schema.Language) + + assert.Equal(t, 1, len(schema.Extensions)) + + return schema +} + +func compileExtRustGuest(t *testing.T) *scalefunc.V1BetaSchema { + wd, err := os.Getwd() + require.NoError(t, err) + + s := new(signature.Schema) + err = s.Decode([]byte(signature.MasterTestingSchema)) + require.NoError(t, err) + + hash, err := s.Hash() + require.NoError(t, err) + + rustCompileDir := wd + "/rust_ext_tests/compile" + err = os.MkdirAll(rustCompileDir, 0755) + require.NoError(t, err) + + t.Cleanup(func() { + err = os.RemoveAll(rustCompileDir) + require.NoError(t, err) + }) + + ex := new(extension.Schema) + err = ex.Decode([]byte(extensionSchema)) + + rustFunctionDir := wd + "/rust_ext_tests/function" + scf := &scalefile.Schema{ + Version: scalefile.V1AlphaVersion, + Name: "example", + Tag: "latest", + Language: string(scalefunc.Rust), + Signature: scalefile.SignatureSchema{ + Organization: "local", + Name: "example", + Tag: "latest", + }, + Function: "example", + Extensions: []scalefile.ExtensionSchema{ + { + Organization: "local", + Name: "example", + Tag: "latest", + }, + }, + } + + stb, err := storage.NewBuild(rustCompileDir) + require.NoError(t, err) + + extensionSchemas := []*extension.Schema{ + ex, + } + + schema, err := build.LocalRust(&build.LocalRustOptions{ + Stdout: os.Stdout, + Scalefile: scf, + SourceDirectory: rustFunctionDir, + SignatureSchema: s, + Storage: stb, + Release: false, + Target: build.WASITarget, + ExtensionSchemas: extensionSchemas, + }) + require.NoError(t, err) + + assert.Equal(t, scf.Name, schema.Name) + assert.Equal(t, scf.Tag, schema.Tag) + assert.Equal(t, scf.Signature.Name, schema.Signature.Name) + assert.Equal(t, scf.Signature.Organization, schema.Signature.Organization) + assert.Equal(t, scf.Signature.Tag, schema.Signature.Tag) + assert.Equal(t, s, schema.Signature.Schema) + assert.Equal(t, hex.EncodeToString(hash), schema.Signature.Hash) + assert.Equal(t, scalefunc.Rust, schema.Language) + assert.Equal(t, 1, len(schema.Extensions)) + + return schema +} + +/** + * Implementation of the simple extension + * + */ +type ExtensionImpl struct{} + +func (ei ExtensionImpl) New(p *hostExtension.Stringval) (hostExtension.Example, error) { + return &ExtensionExample{}, nil +} + +func (ei ExtensionImpl) World(p *hostExtension.Stringval) (hostExtension.Stringval, error) { + return hostExtension.Stringval{Value: "Return World"}, nil +} + +type ExtensionExample struct{} + +func (ee ExtensionExample) Hello(p *hostExtension.Stringval) (hostExtension.Stringval, error) { + return hostExtension.Stringval{Value: "Return Hello"}, nil +} + +func TestExtGolangHostGolangGuest(t *testing.T) { + + ext_impl := &ExtensionImpl{} + + e := hostExtension.New(ext_impl) + + t.Log("Starting TestExtGolangHostGolangGuest") + schema := compileExtGolangGuest(t) + cfg := scale.NewConfig(hostSignature.New).WithFunction(schema).WithStdout(os.Stdout).WithStderr(os.Stderr).WithExtension(e) + runtime, err := scale.New(cfg) + require.NoError(t, err) + + instance, err := runtime.Instance() + require.NoError(t, err) + + sig := hostSignature.New() + + ctx := context.Background() + err = instance.Run(ctx, sig) + require.NoError(t, err) + + require.Equal(t, "This is a Golang Function. Extension New().Hello()=Return Hello World()=Return World", sig.Context.StringField) +} + +func TestExtGolangHostRustGuest(t *testing.T) { + ext_impl := &ExtensionImpl{} + + e := hostExtension.New(ext_impl) + + t.Log("Starting TestGolangHostRustGuest") + schema := compileExtRustGuest(t) + cfg := scale.NewConfig(hostSignature.New).WithFunction(schema).WithStdout(os.Stdout).WithStderr(os.Stderr).WithExtension(e) + runtime, err := scale.New(cfg) + require.NoError(t, err) + + instance, err := runtime.Instance() + require.NoError(t, err) + + sig := hostSignature.New() + + ctx := context.Background() + err = instance.Run(ctx, sig) + require.NoError(t, err) + + require.Equal(t, "This is a Rust Function. Extension New().Hello()=Return Hello World()=Return World", sig.Context.StringField) +} diff --git a/integration/rust_ext_tests/extension/Cargo.toml b/integration/rust_ext_tests/extension/Cargo.toml new file mode 100644 index 00000000..31b6f99b --- /dev/null +++ b/integration/rust_ext_tests/extension/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2021" +name = "local_inttest_latest_guest" +version = "0.1.0" + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 + +[lib] +path = "guest.rs" + +[dependencies.num_enum] +version = "0.7.0" + +[dependencies.regex] +version = "1.9.4" + +[dependencies.scale_signature_interfaces] +version = "0.1.0" + +[dependencies.polyglot_rs] +version = "1.1.3" diff --git a/integration/rust_ext_tests/extension/guest.rs b/integration/rust_ext_tests/extension/guest.rs new file mode 100644 index 00000000..b29f141b --- /dev/null +++ b/integration/rust_ext_tests/extension/guest.rs @@ -0,0 +1,137 @@ +// Code generated by scale-extension 0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +pub mod types; +use crate::types::{Encode, Decode}; +use std::io::Cursor; +use polyglot_rs::{Decoder, Encoder}; +static HASH: &'static str = "b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7"; +static mut READ_BUFFER: Vec = Vec::new(); +static mut WRITE_BUFFER: Vec = Vec::new(); +pub trait Example { + fn Hello( + &self, + params: types::Stringval, + ) -> Result, Box>; +} +#[export_name = "ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize"] +#[no_mangle] +pub unsafe fn ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Resize( + size: u32, +) -> *const u8 { + READ_BUFFER.resize(size as usize, 0); + return READ_BUFFER.as_ptr(); +} +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello"] + fn _ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello( + instance: u64, + ptr: u32, + size: u32, + ) -> u64; +} +#[derive(Clone, Debug, PartialEq)] +pub struct _Example { + pub instanceId: u64, +} +impl Example for _Example { + fn Hello( + &self, + params: types::Stringval, + ) -> Result, Box> { + unsafe { + let mut cursor = Cursor::new(Vec::new()); + types::Stringval::encode(Some(¶ms), &mut cursor); + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + _ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_Example_Hello( + self.instanceId, + off, + l, + ); + let mut cursor = Cursor::new(&mut READ_BUFFER); + return types::Stringval::decode(&mut cursor); + } + } +} +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New"] + fn _ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New( + instance: u64, + ptr: u32, + size: u32, + ) -> u64; +} +pub fn New( + params: types::Stringval, +) -> Result, Box> { + unsafe { + let mut cursor = Cursor::new(Vec::new()); + types::Stringval::encode(Some(¶ms), &mut cursor); + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + READ_BUFFER.resize(0, 0); + let v = _ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_New( + 0, + off, + l, + ); + if READ_BUFFER.len() > 0 { + let mut cursor = Cursor::new(&mut READ_BUFFER); + if let Ok(error) = cursor.decode_error() { + return Err(error); + } + } + let c = _Example { instanceId: v }; + return Ok(Some(c)); + } +} +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World"] + fn _ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World( + instance: u64, + ptr: u32, + size: u32, + ) -> u64; +} +pub fn World( + params: types::Stringval, +) -> Result, Box> { + unsafe { + let mut cursor = Cursor::new(Vec::new()); + types::Stringval::encode(Some(¶ms), &mut cursor); + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + let mut off = WRITE_BUFFER.as_ptr() as u32; + let mut l = WRITE_BUFFER.len() as u32; + _ext_b30af2dd8561988edd7b281ad5c1b84487072727a8ad0e490a87be0a66b037d7_World( + 0, + off, + l, + ); + let mut cursor = Cursor::new(&mut READ_BUFFER); + return types::Stringval::decode(&mut cursor); + } +} +pub unsafe fn error(error: Box) -> (u32, u32) { + let mut cursor = Cursor::new(Vec::new()); + return match cursor.encode_error(error) { + Ok(_) => { + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + (WRITE_BUFFER.as_ptr() as u32, WRITE_BUFFER.len() as u32) + } + Err(_) => (0, 0), + }; +} diff --git a/integration/rust_ext_tests/extension/types.rs b/integration/rust_ext_tests/extension/types.rs new file mode 100644 index 00000000..8a26baa4 --- /dev/null +++ b/integration/rust_ext_tests/extension/types.rs @@ -0,0 +1,101 @@ +// Code generated by scale-signature 0.4.5, DO NOT EDIT. +// output: local_inttest_latest_guest + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] +use std::io::Cursor; +use polyglot_rs::{DecodingError, Encoder, Decoder, Kind}; +use num_enum::TryFromPrimitive; +use std::convert::TryFrom; +use std::collections::HashMap; +use regex::Regex; +pub trait Encode { + fn encode<'a>( + a: Option<&Self>, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> + where + Self: Sized; +} +trait EncodeSelf { + fn encode_self<'a, 'b>( + &'b self, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box>; +} +pub trait Decode { + fn decode( + b: &mut Cursor<&mut Vec>, + ) -> Result, Box> + where + Self: Sized; +} +#[derive(Clone, Debug, PartialEq)] +pub struct Stringval { + pub value: String, +} +impl Stringval { + pub fn new() -> Self { + Self { value: "".to_string() } + } +} +impl Encode for Stringval { + fn encode<'a>( + a: Option<&Stringval>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for Stringval { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.value)?; + Ok(e) + } +} +impl EncodeSelf for Option<&Stringval> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for Stringval { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = Stringval::new(); + x.value = d.decode_string()?; + Ok(Some(x)) + } +} diff --git a/integration/rust_ext_tests/function/Cargo.toml b/integration/rust_ext_tests/function/Cargo.toml new file mode 100644 index 00000000..6b4fc754 --- /dev/null +++ b/integration/rust_ext_tests/function/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "example" +version = "0.1.0" +edition = "2021" + +[lib] +path = "lib.rs" + +[dependencies] +signature = { package = "local_example_latest_guest", path = "../signature"} +extension = { package = "local_inttest_latest_guest", path = "../extension"} + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 \ No newline at end of file diff --git a/integration/rust_ext_tests/function/lib.rs b/integration/rust_ext_tests/function/lib.rs new file mode 100644 index 00000000..98b71986 --- /dev/null +++ b/integration/rust_ext_tests/function/lib.rs @@ -0,0 +1,57 @@ +/* + Copyright 2023 Loophole Labs + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +use signature::types; + +use extension::types::Stringval; +use extension::New; +use extension::World; +use extension::Example; + +pub fn example( + ctx: Option, +) -> Result, Box> { + println!("This is a Rust Function, which calls an extension."); + + let ex_op = New(Stringval{ value: "".to_string() }); + + if let Err(e) = ex_op { + return Err(e) + } + + let ex = ex_op.unwrap(); + + let hello_op = ex.unwrap().Hello(Stringval{ value: "".to_string() }); + + if let Err(e) = hello_op { + return Err(e) + } + + let hello = hello_op.unwrap().unwrap().value; + + let world_op = World(Stringval{ value: "".to_string() }); + + if let Err(e) = world_op { + return Err(e) + } + + let world = world_op.unwrap().unwrap().value; + + let mut unwrapped = ctx.unwrap(); + unwrapped.string_field = format!("This is a Rust Function. Extension New().Hello()={hello} World()={world}"); + return signature::next(Some(unwrapped)); + // return Ok(Some(unwrapped)) +} diff --git a/integration/rust_ext_tests/generated/generated.rs b/integration/rust_ext_tests/generated/generated.rs new file mode 100644 index 00000000..31bb34ad --- /dev/null +++ b/integration/rust_ext_tests/generated/generated.rs @@ -0,0 +1,107 @@ +// Code generated by scale-signature 0.4.5, DO NOT EDIT. +// output: generated + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] +use std::io::Cursor; +use polyglot_rs::{DecodingError, Encoder, Decoder, Kind}; +use num_enum::TryFromPrimitive; +use std::convert::TryFrom; +use std::collections::HashMap; +use regex::Regex; +pub trait Encode { + fn encode<'a>( + a: Option<&Self>, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> + where + Self: Sized; +} +trait EncodeSelf { + fn encode_self<'a, 'b>( + &'b self, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box>; +} +pub trait Decode { + fn decode( + b: &mut Cursor<&mut Vec>, + ) -> Result, Box> + where + Self: Sized; +} +#[derive(Clone, Debug, PartialEq)] +pub struct Context { + pub a: i32, + pub b: i32, + pub c: i32, +} +impl Context { + pub fn new() -> Self { + Self { a: 0, b: 0, c: 0 } + } +} +impl Encode for Context { + fn encode<'a>( + a: Option<&Context>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for Context { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_i32(self.a)?; + e.encode_i32(self.b)?; + e.encode_i32(self.c)?; + Ok(e) + } +} +impl EncodeSelf for Option<&Context> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for Context { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = Context::new(); + x.a = d.decode_i32()?; + x.b = d.decode_i32()?; + x.c = d.decode_i32()?; + Ok(Some(x)) + } +} diff --git a/integration/rust_ext_tests/signature/Cargo.toml b/integration/rust_ext_tests/signature/Cargo.toml new file mode 100644 index 00000000..5464c252 --- /dev/null +++ b/integration/rust_ext_tests/signature/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2021" +name = "local_example_latest_guest" +version = "0.1.0" + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 + +[lib] +path = "guest.rs" + +[dependencies.num_enum] +version = "0.7.0" + +[dependencies.regex] +version = "1.9.4" + +[dependencies.scale_signature_interfaces] +version = "0.1.7" + +[dependencies.polyglot_rs] +version = "1.1.3" diff --git a/integration/rust_ext_tests/signature/guest.rs b/integration/rust_ext_tests/signature/guest.rs new file mode 100644 index 00000000..118b814a --- /dev/null +++ b/integration/rust_ext_tests/signature/guest.rs @@ -0,0 +1,86 @@ +// Code generated by scale-signature 0.4.5, DO NOT EDIT. +// output: local_example_latest_guest + +pub mod types; +use crate::types::{Encode, Decode}; +use std::io::Cursor; +use polyglot_rs::Encoder; +static HASH: &'static str = "3a592aa345d412faa2e6285ee048ca2ab5aa64b0caa2f9ca67b2c1e0792101e5"; +static mut READ_BUFFER: Vec = Vec::new(); +static mut WRITE_BUFFER: Vec = Vec::new(); +pub unsafe fn write(ctx: Option<&mut types::ModelWithAllFieldTypes>) -> (u32, u32) { + let mut cursor = Cursor::new(Vec::new()); + match ctx { + Some(ctx) => { + cursor = match types::ModelWithAllFieldTypes::encode( + Some(ctx), + &mut cursor, + ) { + Ok(_) => cursor, + Err(err) => return error(err), + }; + } + None => { + cursor = match types::ModelWithAllFieldTypes::encode(None, &mut cursor) { + Ok(_) => cursor, + Err(err) => return error(err), + }; + } + } + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + return (WRITE_BUFFER.as_ptr() as u32, WRITE_BUFFER.len() as u32); +} +pub unsafe fn read() -> Result< + Option, + Box, +> { + let mut cursor = Cursor::new(&mut READ_BUFFER); + types::ModelWithAllFieldTypes::decode(&mut cursor) +} +pub unsafe fn error(error: Box) -> (u32, u32) { + let mut cursor = Cursor::new(Vec::new()); + return match cursor.encode_error(error) { + Ok(_) => { + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + (WRITE_BUFFER.as_ptr() as u32, WRITE_BUFFER.len() as u32) + } + Err(_) => (0, 0), + }; +} +pub unsafe fn resize(size: u32) -> *const u8 { + READ_BUFFER.resize(size as usize, 0); + return READ_BUFFER.as_ptr(); +} +pub unsafe fn hash() -> (u32, u32) { + let mut cursor = Cursor::new(Vec::new()); + return match cursor.encode_string(&String::from(HASH)) { + Ok(_) => { + let vec = cursor.into_inner(); + WRITE_BUFFER.resize(vec.len() as usize, 0); + WRITE_BUFFER.copy_from_slice(&vec); + (WRITE_BUFFER.as_ptr() as u32, WRITE_BUFFER.len() as u32) + } + Err(_) => (0, 0), + }; +} +pub fn next( + ctx: Option, +) -> Result, Box> { + unsafe { + let (ptr, len) = match ctx { + Some(mut ctx) => write(Some(&mut ctx)), + None => write(None), + }; + _next(ptr, len); + read() + } +} +#[link(wasm_import_module = "env")] +extern "C" { + #[link_name = "next"] + fn _next(ptr: u32, size: u32); +} diff --git a/integration/rust_ext_tests/signature/tests/types.rs b/integration/rust_ext_tests/signature/tests/types.rs new file mode 100644 index 00000000..596f098d --- /dev/null +++ b/integration/rust_ext_tests/signature/tests/types.rs @@ -0,0 +1,472 @@ +#[cfg(test)] +mod tests { + use std::fs; + use std::error::Error; + use std::io::{Cursor, Seek, SeekFrom}; + use local_example_latest_guest::types; + use local_example_latest_guest::types::{Encode, Decode}; + + #[test] + fn test_output() -> Result<(), Box> { + let mut buf = Cursor::new(Vec::new()); + + let nil_model: Option<&types::EmptyModel> = None; + types::EmptyModel::encode(nil_model, &mut buf)?; + fs::write("../../test_data/nil_model.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let empty_model = types::EmptyModel::new(); + types::EmptyModel::encode(Some(&empty_model), &mut buf)?; + fs::write("../../test_data/empty_model.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let empty_model_with_description = types::EmptyModelWithDescription::new(); + types::EmptyModelWithDescription::encode(Some(&empty_model_with_description), &mut buf)?; + fs::write("../../test_data/empty_model_with_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_single_string_field = types::ModelWithSingleStringField::new(); + assert_eq!(model_with_single_string_field.string_field, String::from("DefaultValue")); + model_with_single_string_field.string_field = String::from("hello world"); + types::ModelWithSingleStringField::encode(Some(&model_with_single_string_field), &mut buf)?; + fs::write("../../test_data/model_with_single_string_field.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_single_string_field_and_description = types::ModelWithSingleStringFieldAndDescription::new(); + assert_eq!(model_with_single_string_field_and_description.string_field, String::from("DefaultValue")); + model_with_single_string_field_and_description.string_field = String::from("hello world"); + types::ModelWithSingleStringFieldAndDescription::encode(Some(&model_with_single_string_field_and_description), &mut buf)?; + fs::write("../../test_data/model_with_single_string_field_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_single_int32_field = types::ModelWithSingleInt32Field::new(); + assert_eq!(model_with_single_int32_field.int32_field, 32); + model_with_single_int32_field.int32_field = 42; + types::ModelWithSingleInt32Field::encode(Some(&model_with_single_int32_field), &mut buf)?; + fs::write("../../test_data/model_with_single_int32_field.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_single_int32_field_and_description = types::ModelWithSingleInt32FieldAndDescription::new(); + assert_eq!(model_with_single_int32_field_and_description.int32_field, 32); + model_with_single_int32_field_and_description.int32_field = 42; + types::ModelWithSingleInt32FieldAndDescription::encode(Some(&model_with_single_int32_field_and_description), &mut buf)?; + fs::write("../../test_data/model_with_single_int32_field_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_multiple_fields = types::ModelWithMultipleFields::new(); + assert_eq!(model_with_multiple_fields.string_field, String::from("DefaultValue")); + assert_eq!(model_with_multiple_fields.int32_field, 32); + model_with_multiple_fields.string_field = String::from("hello world"); + model_with_multiple_fields.int32_field = 42; + types::ModelWithMultipleFields::encode(Some(&model_with_multiple_fields), &mut buf)?; + fs::write("../../test_data/model_with_multiple_fields.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_multiple_fields_and_description = types::ModelWithMultipleFieldsAndDescription::new(); + assert_eq!(model_with_multiple_fields_and_description.string_field, String::from("DefaultValue")); + assert_eq!(model_with_multiple_fields_and_description.int32_field, 32); + model_with_multiple_fields_and_description.string_field = String::from("hello world"); + model_with_multiple_fields_and_description.int32_field = 42; + types::ModelWithMultipleFieldsAndDescription::encode(Some(&model_with_multiple_fields_and_description), &mut buf)?; + fs::write("../../test_data/model_with_multiple_fields_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_enum = types::ModelWithEnum::new(); + assert_eq!(model_with_enum.enum_field, types::GenericEnum::DefaultValue); + model_with_enum.enum_field = types::GenericEnum::SecondValue; + types::ModelWithEnum::encode(Some(&model_with_enum), &mut buf)?; + fs::write("../../test_data/model_with_enum.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_enum_and_description = types::ModelWithEnumAndDescription::new(); + assert_eq!(model_with_enum_and_description.enum_field, types::GenericEnum::DefaultValue); + model_with_enum_and_description.enum_field = types::GenericEnum::SecondValue; + types::ModelWithEnumAndDescription::encode(Some(&model_with_enum_and_description), &mut buf)?; + fs::write("../../test_data/model_with_enum_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_enum_accessor = types::ModelWithEnumAccessor::new(); + let default_enum_value = model_with_enum_accessor.get_enum_field(); + assert_eq!(*default_enum_value, types::GenericEnum::DefaultValue); + model_with_enum_accessor.set_enum_field(types::GenericEnum::SecondValue); + types::ModelWithEnumAccessor::encode(Some(&model_with_enum_accessor), &mut buf)?; + fs::write("../../test_data/model_with_enum_accessor.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_enum_accessor_and_description = types::ModelWithEnumAccessorAndDescription::new(); + let default_enum_value = model_with_enum_accessor_and_description.get_enum_field(); + assert_eq!(*default_enum_value, types::GenericEnum::DefaultValue); + model_with_enum_accessor_and_description.set_enum_field(types::GenericEnum::SecondValue); + types::ModelWithEnumAccessorAndDescription::encode(Some(&model_with_enum_accessor_and_description), &mut buf)?; + fs::write("../../test_data/model_with_enum_accessor_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_multiple_fields_accessor = types::ModelWithMultipleFieldsAccessor::new(); + let mut string_value = model_with_multiple_fields_accessor.get_string_field(); + let int32_value = model_with_multiple_fields_accessor.get_int32_field(); + assert_eq!(string_value, String::from("DefaultValue")); + assert_eq!(int32_value, 32); + assert!(model_with_multiple_fields_accessor.set_string_field(String::from("hello world")).is_err()); + assert!(model_with_multiple_fields_accessor.set_string_field(String::from("")).is_err()); + model_with_multiple_fields_accessor.set_string_field(String::from("hello"))?; + string_value = model_with_multiple_fields_accessor.get_string_field(); + assert_eq!(string_value, String::from("HELLO")); + assert!(model_with_multiple_fields_accessor.set_int32_field(-1).is_err()); + assert!(model_with_multiple_fields_accessor.set_int32_field(101).is_err()); + model_with_multiple_fields_accessor.set_int32_field(42)?; + types::ModelWithMultipleFieldsAccessor::encode(Some(&model_with_multiple_fields_accessor), &mut buf)?; + fs::write("../../test_data/model_with_multiple_fields_accessor.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_multiple_fields_accessor_and_description = types::ModelWithMultipleFieldsAccessorAndDescription::new(); + let string_value = model_with_multiple_fields_accessor_and_description.get_string_field(); + let int32_value = model_with_multiple_fields_accessor_and_description.get_int32_field(); + assert_eq!(string_value, String::from("DefaultValue")); + assert_eq!(int32_value, 32); + model_with_multiple_fields_accessor_and_description.set_string_field(String::from("hello world"))?; + model_with_multiple_fields_accessor_and_description.set_int32_field(42)?; + types::ModelWithMultipleFieldsAccessorAndDescription::encode(Some(&model_with_multiple_fields_accessor_and_description), &mut buf)?; + fs::write("../../test_data/model_with_multiple_fields_accessor_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_embedded_models = types::ModelWithEmbeddedModels::new(); + assert!(model_with_embedded_models.embedded_empty_model.is_some()); + assert_eq!(model_with_embedded_models.embedded_model_array_with_multiple_fields_accessor.capacity(), 64); + assert_eq!(model_with_embedded_models.embedded_model_array_with_multiple_fields_accessor.len(), 0); + model_with_embedded_models.embedded_model_array_with_multiple_fields_accessor.push(model_with_multiple_fields_accessor.clone()); + types::ModelWithEmbeddedModels::encode(Some(&model_with_embedded_models), &mut buf)?; + fs::write("../../test_data/model_with_embedded_models.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_embedded_models_and_description = types::ModelWithEmbeddedModelsAndDescription::new(); + assert!(model_with_embedded_models_and_description.embedded_empty_model.is_some()); + assert_eq!(model_with_embedded_models_and_description.embedded_model_array_with_multiple_fields_accessor.capacity(), 0); + assert_eq!(model_with_embedded_models_and_description.embedded_model_array_with_multiple_fields_accessor.len(), 0); + model_with_embedded_models_and_description.embedded_model_array_with_multiple_fields_accessor.push(model_with_multiple_fields_accessor.clone()); + types::ModelWithEmbeddedModelsAndDescription::encode(Some(&model_with_embedded_models_and_description), &mut buf)?; + fs::write("../../test_data/model_with_embedded_models_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_embedded_models_accessor = types::ModelWithEmbeddedModelsAccessor::new(); + let embedded_model = model_with_embedded_models_accessor.get_embedded_empty_model(); + assert!(embedded_model.is_some()); + let embedded_model_array = model_with_embedded_models_accessor.get_embedded_model_array_with_multiple_fields_accessor().unwrap(); + assert_eq!(embedded_model_array.capacity(), 0); + assert_eq!(embedded_model_array.len(), 0); + model_with_embedded_models_accessor.set_embedded_model_array_with_multiple_fields_accessor(vec![model_with_multiple_fields_accessor.clone()]); + types::ModelWithEmbeddedModelsAccessor::encode(Some(&model_with_embedded_models_accessor), &mut buf)?; + fs::write("../../test_data/model_with_embedded_models_accessor.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_embedded_models_accessor_and_description = types::ModelWithEmbeddedModelsAccessorAndDescription::new(); + let embedded_model = model_with_embedded_models_accessor_and_description.get_embedded_empty_model(); + assert!(embedded_model.is_some()); + let embedded_model_array = model_with_embedded_models_accessor_and_description.get_embedded_model_array_with_multiple_fields_accessor().unwrap(); + assert_eq!(embedded_model_array.capacity(), 0); + assert_eq!(embedded_model_array.len(), 0); + model_with_embedded_models_accessor_and_description.set_embedded_model_array_with_multiple_fields_accessor(vec![model_with_multiple_fields_accessor.clone()]); + types::ModelWithEmbeddedModelsAccessorAndDescription::encode(Some(&model_with_embedded_models_accessor_and_description), &mut buf)?; + fs::write("../../test_data/model_with_embedded_models_accessor_and_description.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + let mut model_with_all_field_types = types::ModelWithAllFieldTypes::new(); + + assert_eq!(model_with_all_field_types.string_field, String::from("DefaultValue")); + model_with_all_field_types.string_field = "hello world".to_string(); + assert_eq!(model_with_all_field_types.string_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.string_array_field.len(), 0); + model_with_all_field_types.string_array_field.push("hello".to_string()); + model_with_all_field_types.string_array_field.push("world".to_string()); + assert_eq!(model_with_all_field_types.string_map_field.capacity(), 0); + assert_eq!(model_with_all_field_types.string_map_field.len(), 0); + model_with_all_field_types.string_map_field.insert("hello".to_string(), "world".to_string()); + model_with_all_field_types.string_map_field_embedded.insert("hello".to_string(), empty_model.clone()); + + assert_eq!(model_with_all_field_types.int32_field, 32); + model_with_all_field_types.int32_field = 42; + assert_eq!(model_with_all_field_types.int32_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.int32_array_field.len(), 0); + model_with_all_field_types.int32_array_field.push(42); + model_with_all_field_types.int32_array_field.push(84); + assert_eq!(model_with_all_field_types.int32_map_field.capacity(), 0); + assert_eq!(model_with_all_field_types.int32_map_field.len(), 0); + model_with_all_field_types.int32_map_field.insert(42, 84); + model_with_all_field_types.int32_map_field_embedded.insert(42, empty_model.clone()); + + assert_eq!(model_with_all_field_types.int64_field, 64); + model_with_all_field_types.int64_field = 100; + assert_eq!(model_with_all_field_types.int64_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.int64_array_field.len(), 0); + model_with_all_field_types.int64_array_field.push(100); + model_with_all_field_types.int64_array_field.push(200); + assert_eq!(model_with_all_field_types.int64_map_field.capacity(), 0); + assert_eq!(model_with_all_field_types.int64_map_field.len(), 0); + model_with_all_field_types.int64_map_field.insert(100, 200); + model_with_all_field_types.int64_map_field_embedded.insert(100, empty_model.clone()); + + assert_eq!(model_with_all_field_types.uint32_field, 32); + model_with_all_field_types.uint32_field = 42; + assert_eq!(model_with_all_field_types.uint32_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.uint32_array_field.len(), 0); + model_with_all_field_types.uint32_array_field.push(42); + model_with_all_field_types.uint32_array_field.push(84); + assert_eq!(model_with_all_field_types.uint32_map_field.capacity(), 0); + assert_eq!(model_with_all_field_types.uint32_map_field.len(), 0); + model_with_all_field_types.uint32_map_field.insert(42, 84); + model_with_all_field_types.uint32_map_field_embedded.insert(42, empty_model.clone()); + + assert_eq!(model_with_all_field_types.uint64_field, 64); + model_with_all_field_types.uint64_field = 100; + assert_eq!(model_with_all_field_types.uint64_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.uint64_array_field.len(), 0); + model_with_all_field_types.uint64_array_field.push(100); + model_with_all_field_types.uint64_array_field.push(200); + assert_eq!(model_with_all_field_types.uint64_map_field.capacity(), 0); + assert_eq!(model_with_all_field_types.uint64_map_field.len(), 0); + model_with_all_field_types.uint64_map_field.insert(100, 200); + model_with_all_field_types.uint64_map_field_embedded.insert(100, empty_model.clone()); + + assert_eq!(model_with_all_field_types.float32_field, 32.32); + model_with_all_field_types.float32_field = 42.0; + assert_eq!(model_with_all_field_types.float32_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.float32_array_field.len(), 0); + model_with_all_field_types.float32_array_field.push(42.0); + model_with_all_field_types.float32_array_field.push(84.0); + + assert_eq!(model_with_all_field_types.float64_field, 64.64); + model_with_all_field_types.float64_field = 100.0; + assert_eq!(model_with_all_field_types.float64_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.float64_array_field.len(), 0); + model_with_all_field_types.float64_array_field.push(100.0); + model_with_all_field_types.float64_array_field.push(200.0); + + assert!(model_with_all_field_types.bool_field); + model_with_all_field_types.bool_field = false; + assert_eq!(model_with_all_field_types.bool_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.bool_array_field.len(), 0); + model_with_all_field_types.bool_array_field.push(true); + model_with_all_field_types.bool_array_field.push(false); + + assert_eq!(model_with_all_field_types.bytes_field.capacity(), 512); + assert_eq!(model_with_all_field_types.bytes_field.len(), 0); + model_with_all_field_types.bytes_field.extend_from_slice(&[42, 84]); + assert_eq!(model_with_all_field_types.bytes_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.bytes_array_field.len(), 0); + model_with_all_field_types.bytes_array_field.push(vec![42, 84]); + model_with_all_field_types.bytes_array_field.push(vec![84, 42]); + + assert_eq!(model_with_all_field_types.enum_field, types::GenericEnum::DefaultValue); + model_with_all_field_types.enum_field = types::GenericEnum::SecondValue; + assert_eq!(model_with_all_field_types.enum_array_field.capacity(), 0); + assert_eq!(model_with_all_field_types.enum_array_field.len(), 0); + model_with_all_field_types.enum_array_field.push(types::GenericEnum::FirstValue); + model_with_all_field_types.enum_array_field.push(types::GenericEnum::SecondValue); + assert_eq!(model_with_all_field_types.enum_map_field.capacity(), 0); + assert_eq!(model_with_all_field_types.enum_map_field.len(), 0); + model_with_all_field_types.enum_map_field.insert(types::GenericEnum::FirstValue, "hello world".to_string()); + model_with_all_field_types.enum_map_field_embedded.insert(types::GenericEnum::FirstValue, empty_model.clone()); + + assert!(model_with_all_field_types.model_field.is_some()); + assert_eq!(model_with_all_field_types.model_array_field.len(), 0); + model_with_all_field_types.model_array_field.push(empty_model.clone()); + model_with_all_field_types.model_array_field.push(empty_model.clone()); + + types::ModelWithAllFieldTypes::encode(Some(&model_with_all_field_types), &mut buf)?; + fs::write("../../test_data/model_with_all_field_types.bin", buf.get_ref())?; + buf.seek(SeekFrom::Start(0))?; + buf.get_mut().clear(); + + Ok(()) + } + + #[test] + fn test_input() -> Result<(), Box> { + let mut null_model_data = fs::read("../../test_data/nil_model.bin")?; + let _null_model = types::EmptyModel::decode(&mut Cursor::new(&mut null_model_data))?; + assert!(_null_model.is_none()); + + let mut empty_model_data = fs::read("../../test_data/empty_model.bin")?; + let _empty_model = types::EmptyModel::decode(&mut Cursor::new(&mut empty_model_data))?; + assert!(_empty_model.is_some()); + + let mut empty_model_with_description_data = fs::read("../../test_data/empty_model_with_description.bin")?; + let _empty_model_with_description = types::EmptyModelWithDescription::decode(&mut Cursor::new(&mut empty_model_with_description_data))?; + assert!(_empty_model_with_description.is_some()); + + let mut model_with_single_string_field_data = fs::read("../../test_data/model_with_single_string_field.bin")?; + let model_with_single_string_field = types::ModelWithSingleStringField::decode(&mut Cursor::new(&mut model_with_single_string_field_data))?.unwrap(); + assert_eq!(model_with_single_string_field.string_field, "hello world"); + + let mut model_with_single_string_field_and_description_data = fs::read("../../test_data/model_with_single_string_field_and_description.bin")?; + let model_with_single_string_field_and_description = types::ModelWithSingleStringFieldAndDescription::decode(&mut Cursor::new(&mut model_with_single_string_field_and_description_data))?.unwrap(); + assert_eq!(model_with_single_string_field_and_description.string_field, "hello world"); + + let mut model_with_single_int32_field_data = fs::read("../../test_data/model_with_single_int32_field.bin")?; + let model_with_single_int32_field = types::ModelWithSingleInt32Field::decode(&mut Cursor::new(&mut model_with_single_int32_field_data))?.unwrap(); + assert_eq!(model_with_single_int32_field.int32_field, 42); + + let mut model_with_single_int32_field_and_description_data = fs::read("../../test_data/model_with_single_int32_field_and_description.bin")?; + let model_with_single_int32_field_and_description = types::ModelWithSingleInt32FieldAndDescription::decode(&mut Cursor::new(&mut model_with_single_int32_field_and_description_data))?.unwrap(); + assert_eq!(model_with_single_int32_field_and_description.int32_field, 42); + + let mut model_with_multiple_fields_data = fs::read("../../test_data/model_with_multiple_fields.bin")?; + let model_with_multiple_fields = types::ModelWithMultipleFields::decode(&mut Cursor::new(&mut model_with_multiple_fields_data))?.unwrap(); + assert_eq!(model_with_multiple_fields.string_field, "hello world"); + assert_eq!(model_with_multiple_fields.int32_field, 42); + + let mut model_with_multiple_fields_and_description_data = fs::read("../../test_data/model_with_multiple_fields_and_description.bin")?; + let model_with_multiple_fields_and_description = types::ModelWithMultipleFieldsAndDescription::decode(&mut Cursor::new(&mut model_with_multiple_fields_and_description_data))?.unwrap(); + assert_eq!(model_with_multiple_fields_and_description.string_field, "hello world"); + assert_eq!(model_with_multiple_fields_and_description.int32_field, 42); + + let mut model_with_enum_data = fs::read("../../test_data/model_with_enum.bin")?; + let model_with_enum = types::ModelWithEnum::decode(&mut Cursor::new(&mut model_with_enum_data))?.unwrap(); + assert_eq!(model_with_enum.enum_field, types::GenericEnum::SecondValue); + + let mut model_with_enum_and_description_data = fs::read("../../test_data/model_with_enum_and_description.bin")?; + let model_with_enum_and_description = types::ModelWithEnumAndDescription::decode(&mut Cursor::new(&mut model_with_enum_and_description_data))?.unwrap(); + assert_eq!(model_with_enum_and_description.enum_field, types::GenericEnum::SecondValue); + + let mut model_with_enum_accessor_data = fs::read("../../test_data/model_with_enum_accessor.bin")?; + let model_with_enum_accessor = types::ModelWithEnumAccessor::decode(&mut Cursor::new(&mut model_with_enum_accessor_data))?.unwrap(); + let enum_value = model_with_enum_accessor.get_enum_field(); + assert_eq!(*enum_value, types::GenericEnum::SecondValue); + + let mut model_with_enum_accessor_and_description_data = fs::read("../../test_data/model_with_enum_accessor_and_description.bin")?; + let model_with_enum_accessor_and_description = types::ModelWithEnumAccessorAndDescription::decode(&mut Cursor::new(&mut model_with_enum_accessor_and_description_data))?.unwrap(); + let enum_value = model_with_enum_accessor_and_description.get_enum_field(); + assert_eq!(*enum_value, types::GenericEnum::SecondValue); + + let mut model_with_multiple_fields_accessor_data = fs::read("../../test_data/model_with_multiple_fields_accessor.bin")?; + let model_with_multiple_fields_accessor = types::ModelWithMultipleFieldsAccessor::decode(&mut Cursor::new(&mut model_with_multiple_fields_accessor_data))?.unwrap(); + let string_field_value = model_with_multiple_fields_accessor.get_string_field(); + assert_eq!(string_field_value, "HELLO"); + let int32_field_value = model_with_multiple_fields_accessor.get_int32_field(); + assert_eq!(int32_field_value, 42); + + let mut model_with_multiple_fields_accessor_and_description_data = fs::read("../../test_data/model_with_multiple_fields_accessor_and_description.bin")?; + let model_with_multiple_fields_accessor_and_description = types::ModelWithMultipleFieldsAccessorAndDescription::decode(&mut Cursor::new(&mut model_with_multiple_fields_accessor_and_description_data))?.unwrap(); + let string_field_value = model_with_multiple_fields_accessor_and_description.get_string_field(); + assert_eq!(string_field_value, "hello world"); + let int32_field_value = model_with_multiple_fields_accessor_and_description.get_int32_field(); + assert_eq!(int32_field_value, 42); + + let mut model_with_embedded_models_data = fs::read("../../test_data/model_with_embedded_models.bin")?; + let model_with_embedded_models = types::ModelWithEmbeddedModels::decode(&mut Cursor::new(&mut model_with_embedded_models_data))?.unwrap(); + assert!(model_with_embedded_models.embedded_empty_model.is_some()); + assert_eq!(model_with_embedded_models.embedded_model_array_with_multiple_fields_accessor.len(), 1); + assert_eq!(model_with_embedded_models.embedded_model_array_with_multiple_fields_accessor[0].get_int32_field(), 42); + assert_eq!(model_with_embedded_models.embedded_model_array_with_multiple_fields_accessor[0].get_string_field(), "HELLO"); + + let mut model_with_embedded_models_and_description_data = fs::read("../../test_data/model_with_embedded_models_and_description.bin")?; + let model_with_embedded_models_and_description = types::ModelWithEmbeddedModelsAndDescription::decode(&mut Cursor::new(&mut model_with_embedded_models_and_description_data))?.unwrap(); + assert!(model_with_embedded_models_and_description.embedded_empty_model.is_some()); + assert_eq!(model_with_embedded_models_and_description.embedded_model_array_with_multiple_fields_accessor.len(), 1); + assert_eq!(model_with_embedded_models_and_description.embedded_model_array_with_multiple_fields_accessor[0].get_int32_field(), 42); + assert_eq!(model_with_embedded_models_and_description.embedded_model_array_with_multiple_fields_accessor[0].get_string_field(), "HELLO"); + + let mut model_with_embedded_models_accessor_data = fs::read("../../test_data/model_with_embedded_models_accessor.bin")?; + let model_with_embedded_models_accessor = types::ModelWithEmbeddedModelsAccessor::decode(&mut Cursor::new(&mut model_with_embedded_models_accessor_data))?.unwrap(); + let embedded_empty_model = model_with_embedded_models_accessor.get_embedded_empty_model(); + assert!(embedded_empty_model.is_some()); + let embedded_model_array_with_multiple_fields_accessor = model_with_embedded_models_accessor.get_embedded_model_array_with_multiple_fields_accessor().unwrap(); + assert_eq!(embedded_model_array_with_multiple_fields_accessor.len(), 1); + assert_eq!(embedded_model_array_with_multiple_fields_accessor[0].get_int32_field(), 42); + assert_eq!(embedded_model_array_with_multiple_fields_accessor[0].get_string_field(), "HELLO"); + + let mut model_with_embedded_models_accessor_and_description_data = fs::read("../../test_data/model_with_embedded_models_accessor_and_description.bin")?; + let model_with_embedded_models_accessor_and_description = types::ModelWithEmbeddedModelsAccessorAndDescription::decode(&mut Cursor::new(&mut model_with_embedded_models_accessor_and_description_data))?.unwrap(); + let embedded_empty_model = model_with_embedded_models_accessor_and_description.get_embedded_empty_model(); + assert!(embedded_empty_model.is_some()); + let embedded_model_array_with_multiple_fields_accessor = model_with_embedded_models_accessor_and_description.get_embedded_model_array_with_multiple_fields_accessor().unwrap(); + assert_eq!(embedded_model_array_with_multiple_fields_accessor[0].get_int32_field(), 42); + assert_eq!(embedded_model_array_with_multiple_fields_accessor[0].get_string_field(), "HELLO"); + + let mut model_with_all_field_types_data = fs::read("../../test_data/model_with_all_field_types.bin")?; + let model_with_all_field_types = types::ModelWithAllFieldTypes::decode(&mut Cursor::new(&mut model_with_all_field_types_data))?.unwrap(); + assert_eq!(model_with_all_field_types.string_field, "hello world"); + assert_eq!(model_with_all_field_types.string_array_field.len(), 2); + assert_eq!(model_with_all_field_types.string_array_field[0], "hello"); + assert_eq!(model_with_all_field_types.string_array_field[1], "world"); + assert_eq!(model_with_all_field_types.string_map_field.get("hello"), Some(&"world".to_string())); + assert!(model_with_all_field_types.string_map_field_embedded.get("hello").is_some()); + + assert_eq!(model_with_all_field_types.int32_field, 42); + assert_eq!(model_with_all_field_types.int32_array_field.len(), 2); + assert_eq!(model_with_all_field_types.int32_array_field[0], 42); + assert_eq!(model_with_all_field_types.int32_array_field[1], 84); + assert_eq!(model_with_all_field_types.int32_map_field.get(&42), Some(&84)); + assert!(model_with_all_field_types.int32_map_field_embedded.get(&42).is_some()); + + assert_eq!(model_with_all_field_types.int64_field, 100); + assert_eq!(model_with_all_field_types.int64_array_field.len(), 2); + assert_eq!(model_with_all_field_types.int64_array_field[0], 100); + assert_eq!(model_with_all_field_types.int64_array_field[1], 200); + assert_eq!(model_with_all_field_types.int64_map_field.get(&100), Some(&200)); + assert!(model_with_all_field_types.int64_map_field_embedded.get(&100).is_some()); + + assert_eq!(model_with_all_field_types.uint32_field, 42); + assert_eq!(model_with_all_field_types.uint32_array_field.len(), 2); + assert_eq!(model_with_all_field_types.uint32_array_field[0], 42); + assert_eq!(model_with_all_field_types.uint32_array_field[1], 84); + assert_eq!(model_with_all_field_types.uint32_map_field.get(&42), Some(&84)); + assert!(model_with_all_field_types.uint32_map_field_embedded.get(&42).is_some()); + + assert_eq!(model_with_all_field_types.uint64_field, 100); + assert_eq!(model_with_all_field_types.uint64_array_field.len(), 2); + assert_eq!(model_with_all_field_types.uint64_array_field[0], 100); + assert_eq!(model_with_all_field_types.uint64_array_field[1], 200); + assert_eq!(model_with_all_field_types.uint64_map_field.get(&100), Some(&200)); + assert!(model_with_all_field_types.uint64_map_field_embedded.get(&100).is_some()); + + assert_eq!(model_with_all_field_types.float32_field, 42.0); + assert_eq!(model_with_all_field_types.float32_array_field.len(), 2); + assert_eq!(model_with_all_field_types.float32_array_field[0], 42.0); + assert_eq!(model_with_all_field_types.float32_array_field[1], 84.0); + + assert_eq!(model_with_all_field_types.float64_field, 100.0); + assert_eq!(model_with_all_field_types.float64_array_field.len(), 2); + assert_eq!(model_with_all_field_types.float64_array_field[0], 100.0); + assert_eq!(model_with_all_field_types.float64_array_field[1], 200.0); + + assert_eq!(model_with_all_field_types.bool_field, false); + assert_eq!(model_with_all_field_types.bool_array_field.len(), 2); + assert_eq!(model_with_all_field_types.bool_array_field[0], true); + assert_eq!(model_with_all_field_types.bool_array_field[1], false); + + assert_eq!(model_with_all_field_types.bytes_field, &[42, 84]); + assert_eq!(model_with_all_field_types.bytes_array_field.len(), 2); + assert_eq!(model_with_all_field_types.bytes_array_field[0], &[42, 84]); + assert_eq!(model_with_all_field_types.bytes_array_field[1], &[84, 42]); + + assert_eq!(model_with_all_field_types.enum_field, types::GenericEnum::SecondValue); + assert_eq!(model_with_all_field_types.enum_array_field.len(), 2); + assert_eq!(model_with_all_field_types.enum_array_field[0], types::GenericEnum::FirstValue); + assert_eq!(model_with_all_field_types.enum_array_field[1], types::GenericEnum::SecondValue); + assert_eq!(model_with_all_field_types.enum_map_field.get(&types::GenericEnum::FirstValue), Some(&"hello world".to_string())); + assert!(model_with_all_field_types.enum_map_field_embedded.get(&types::GenericEnum::FirstValue).is_some()); + + assert_eq!(model_with_all_field_types.model_array_field.len(), 2); + + Ok(()) + } +} \ No newline at end of file diff --git a/integration/rust_ext_tests/signature/types.rs b/integration/rust_ext_tests/signature/types.rs new file mode 100644 index 00000000..1db5894b --- /dev/null +++ b/integration/rust_ext_tests/signature/types.rs @@ -0,0 +1,1887 @@ +// Code generated by scale-signature 0.4.5, DO NOT EDIT. +// output: local_example_latest_guest + +#![allow(dead_code)] +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] +use std::io::Cursor; +use polyglot_rs::{DecodingError, Encoder, Decoder, Kind}; +use num_enum::TryFromPrimitive; +use std::convert::TryFrom; +use std::collections::HashMap; +use regex::Regex; +pub trait Encode { + fn encode<'a>( + a: Option<&Self>, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> + where + Self: Sized; +} +trait EncodeSelf { + fn encode_self<'a, 'b>( + &'b self, + b: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box>; +} +pub trait Decode { + fn decode( + b: &mut Cursor<&mut Vec>, + ) -> Result, Box> + where + Self: Sized; +} +#[derive(Debug, Eq, PartialEq, TryFromPrimitive, Copy, Clone, Hash)] +#[repr(u32)] +pub enum GenericEnum { + FirstValue = 0, + SecondValue = 1, + DefaultValue = 2, +} +#[derive(Clone, Debug, PartialEq)] +pub struct EmptyModel {} +impl EmptyModel { + pub fn new() -> Self { + Self {} + } +} +impl Encode for EmptyModel { + fn encode<'a>( + a: Option<&EmptyModel>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for EmptyModel { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + Ok(e) + } +} +impl EncodeSelf for Option<&EmptyModel> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for EmptyModel { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = EmptyModel::new(); + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct EmptyModelWithDescription {} +impl EmptyModelWithDescription { + pub fn new() -> Self { + Self {} + } +} +impl Encode for EmptyModelWithDescription { + fn encode<'a>( + a: Option<&EmptyModelWithDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for EmptyModelWithDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + Ok(e) + } +} +impl EncodeSelf for Option<&EmptyModelWithDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for EmptyModelWithDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = EmptyModelWithDescription::new(); + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithSingleStringField { + pub string_field: String, +} +impl ModelWithSingleStringField { + pub fn new() -> Self { + Self { + string_field: "DefaultValue".to_string(), + } + } +} +impl Encode for ModelWithSingleStringField { + fn encode<'a>( + a: Option<&ModelWithSingleStringField>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithSingleStringField { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.string_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithSingleStringField> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithSingleStringField { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithSingleStringField::new(); + x.string_field = d.decode_string()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithSingleStringFieldAndDescription { + pub string_field: String, +} +impl ModelWithSingleStringFieldAndDescription { + pub fn new() -> Self { + Self { + string_field: "DefaultValue".to_string(), + } + } +} +impl Encode for ModelWithSingleStringFieldAndDescription { + fn encode<'a>( + a: Option<&ModelWithSingleStringFieldAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithSingleStringFieldAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.string_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithSingleStringFieldAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithSingleStringFieldAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithSingleStringFieldAndDescription::new(); + x.string_field = d.decode_string()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithSingleInt32Field { + pub int32_field: i32, +} +impl ModelWithSingleInt32Field { + pub fn new() -> Self { + Self { int32_field: 32 } + } +} +impl Encode for ModelWithSingleInt32Field { + fn encode<'a>( + a: Option<&ModelWithSingleInt32Field>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithSingleInt32Field { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_i32(self.int32_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithSingleInt32Field> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithSingleInt32Field { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithSingleInt32Field::new(); + x.int32_field = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithSingleInt32FieldAndDescription { + pub int32_field: i32, +} +impl ModelWithSingleInt32FieldAndDescription { + pub fn new() -> Self { + Self { int32_field: 32 } + } +} +impl Encode for ModelWithSingleInt32FieldAndDescription { + fn encode<'a>( + a: Option<&ModelWithSingleInt32FieldAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithSingleInt32FieldAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_i32(self.int32_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithSingleInt32FieldAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithSingleInt32FieldAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithSingleInt32FieldAndDescription::new(); + x.int32_field = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithMultipleFields { + pub string_field: String, + pub int32_field: i32, +} +impl ModelWithMultipleFields { + pub fn new() -> Self { + Self { + string_field: "DefaultValue".to_string(), + int32_field: 32, + } + } +} +impl Encode for ModelWithMultipleFields { + fn encode<'a>( + a: Option<&ModelWithMultipleFields>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithMultipleFields { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.string_field)?; + e.encode_i32(self.int32_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithMultipleFields> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithMultipleFields { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithMultipleFields::new(); + x.string_field = d.decode_string()?; + x.int32_field = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithMultipleFieldsAndDescription { + pub string_field: String, + pub int32_field: i32, +} +impl ModelWithMultipleFieldsAndDescription { + pub fn new() -> Self { + Self { + string_field: "DefaultValue".to_string(), + int32_field: 32, + } + } +} +impl Encode for ModelWithMultipleFieldsAndDescription { + fn encode<'a>( + a: Option<&ModelWithMultipleFieldsAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithMultipleFieldsAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.string_field)?; + e.encode_i32(self.int32_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithMultipleFieldsAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithMultipleFieldsAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithMultipleFieldsAndDescription::new(); + x.string_field = d.decode_string()?; + x.int32_field = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEnum { + pub enum_field: GenericEnum, +} +impl ModelWithEnum { + pub fn new() -> Self { + Self { + enum_field: GenericEnum::DefaultValue, + } + } +} +impl Encode for ModelWithEnum { + fn encode<'a>( + a: Option<&ModelWithEnum>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEnum { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_u32(self.enum_field as u32)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEnum> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEnum { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEnum::new(); + x + .enum_field = GenericEnum::try_from(d.decode_u32()?) + .ok() + .ok_or(DecodingError::InvalidEnum)?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEnumAndDescription { + pub enum_field: GenericEnum, +} +impl ModelWithEnumAndDescription { + pub fn new() -> Self { + Self { + enum_field: GenericEnum::DefaultValue, + } + } +} +impl Encode for ModelWithEnumAndDescription { + fn encode<'a>( + a: Option<&ModelWithEnumAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEnumAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_u32(self.enum_field as u32)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEnumAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEnumAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEnumAndDescription::new(); + x + .enum_field = GenericEnum::try_from(d.decode_u32()?) + .ok() + .ok_or(DecodingError::InvalidEnum)?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEnumAccessor { + enum_field: GenericEnum, +} +impl ModelWithEnumAccessor { + pub fn new() -> Self { + Self { + enum_field: GenericEnum::DefaultValue, + } + } +} +impl Encode for ModelWithEnumAccessor { + fn encode<'a>( + a: Option<&ModelWithEnumAccessor>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEnumAccessor { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_u32(self.enum_field as u32)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEnumAccessor> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEnumAccessor { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEnumAccessor::new(); + x + .enum_field = GenericEnum::try_from(d.decode_u32()?) + .ok() + .ok_or(DecodingError::InvalidEnum)?; + Ok(Some(x)) + } +} +impl ModelWithEnumAccessor { + pub fn get_enum_field(&self) -> &GenericEnum { + &self.enum_field + } + pub fn set_enum_field(&mut self, v: GenericEnum) { + self.enum_field = v; + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEnumAccessorAndDescription { + enum_field: GenericEnum, +} +impl ModelWithEnumAccessorAndDescription { + pub fn new() -> Self { + Self { + enum_field: GenericEnum::DefaultValue, + } + } +} +impl Encode for ModelWithEnumAccessorAndDescription { + fn encode<'a>( + a: Option<&ModelWithEnumAccessorAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEnumAccessorAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_u32(self.enum_field as u32)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEnumAccessorAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEnumAccessorAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEnumAccessorAndDescription::new(); + x + .enum_field = GenericEnum::try_from(d.decode_u32()?) + .ok() + .ok_or(DecodingError::InvalidEnum)?; + Ok(Some(x)) + } +} +impl ModelWithEnumAccessorAndDescription { + pub fn get_enum_field(&self) -> &GenericEnum { + &self.enum_field + } + pub fn set_enum_field(&mut self, v: GenericEnum) { + self.enum_field = v; + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithMultipleFieldsAccessor { + string_field: String, + int32_field: i32, +} +impl ModelWithMultipleFieldsAccessor { + pub fn new() -> Self { + Self { + string_field: "DefaultValue".to_string(), + int32_field: 32, + } + } + pub fn get_string_field(&self) -> String { + self.string_field.clone() + } + pub fn set_string_field( + &mut self, + mut v: String, + ) -> Result<(), Box> { + if !Regex::new("^[a-zA-Z0-9]*$")?.is_match(v.as_str()) { + return Err( + Box::::from("value must match ^[a-zA-Z0-9]*$"), + ); + } + if v.len() > 20 || v.len() < 1 { + return Err( + Box::< + dyn std::error::Error, + >::from("value must be between { .Minimum }} and 20"), + ); + } + v = v.to_uppercase(); + self.string_field = v; + Ok(()) + } + pub fn get_int32_field(&self) -> i32 { + self.int32_field + } + pub fn set_int32_field(&mut self, v: i32) -> Result<(), Box> { + if v > 100 || v < 0 { + return Err( + Box::< + dyn std::error::Error, + >::from("value must be between { .Minimum }} and 100"), + ); + } + self.int32_field = v; + Ok(()) + } +} +impl Encode for ModelWithMultipleFieldsAccessor { + fn encode<'a>( + a: Option<&ModelWithMultipleFieldsAccessor>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithMultipleFieldsAccessor { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.string_field)?; + e.encode_i32(self.int32_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithMultipleFieldsAccessor> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithMultipleFieldsAccessor { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithMultipleFieldsAccessor::new(); + x.string_field = d.decode_string()?; + x.int32_field = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithMultipleFieldsAccessorAndDescription { + string_field: String, + int32_field: i32, +} +impl ModelWithMultipleFieldsAccessorAndDescription { + pub fn new() -> Self { + Self { + string_field: "DefaultValue".to_string(), + int32_field: 32, + } + } + pub fn get_string_field(&self) -> String { + self.string_field.clone() + } + pub fn set_string_field( + &mut self, + mut v: String, + ) -> Result<(), Box> { + self.string_field = v; + Ok(()) + } + pub fn get_int32_field(&self) -> i32 { + self.int32_field + } + pub fn set_int32_field(&mut self, v: i32) -> Result<(), Box> { + self.int32_field = v; + Ok(()) + } +} +impl Encode for ModelWithMultipleFieldsAccessorAndDescription { + fn encode<'a>( + a: Option<&ModelWithMultipleFieldsAccessorAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithMultipleFieldsAccessorAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + e.encode_string(&self.string_field)?; + e.encode_i32(self.int32_field)?; + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithMultipleFieldsAccessorAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithMultipleFieldsAccessorAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithMultipleFieldsAccessorAndDescription::new(); + x.string_field = d.decode_string()?; + x.int32_field = d.decode_i32()?; + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEmbeddedModels { + pub embedded_empty_model: Option, + pub embedded_model_array_with_multiple_fields_accessor: Vec< + ModelWithMultipleFieldsAccessor, + >, +} +impl ModelWithEmbeddedModels { + pub fn new() -> Self { + Self { + embedded_empty_model: Some(EmptyModel::new()), + embedded_model_array_with_multiple_fields_accessor: Vec::with_capacity(64), + } + } +} +impl Encode for ModelWithEmbeddedModels { + fn encode<'a>( + a: Option<&ModelWithEmbeddedModels>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEmbeddedModels { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + self.embedded_empty_model.encode_self(e)?; + e.encode_array( + self.embedded_model_array_with_multiple_fields_accessor.len(), + Kind::Any, + )?; + for a in &self.embedded_model_array_with_multiple_fields_accessor { + a.encode_self(e)?; + } + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEmbeddedModels> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEmbeddedModels { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEmbeddedModels::new(); + x.embedded_empty_model = EmptyModel::decode(d)?; + let size_embedded_model_array_with_multiple_fields_accessor = d + .decode_array(Kind::Any)?; + for _ in 0..size_embedded_model_array_with_multiple_fields_accessor { + x.embedded_model_array_with_multiple_fields_accessor + .push( + ModelWithMultipleFieldsAccessor::decode(d)? + .ok_or(DecodingError::InvalidArray)?, + ); + } + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEmbeddedModelsAndDescription { + pub embedded_empty_model: Option, + pub embedded_model_array_with_multiple_fields_accessor: Vec< + ModelWithMultipleFieldsAccessor, + >, +} +impl ModelWithEmbeddedModelsAndDescription { + pub fn new() -> Self { + Self { + embedded_empty_model: Some(EmptyModel::new()), + embedded_model_array_with_multiple_fields_accessor: Vec::with_capacity(0), + } + } +} +impl Encode for ModelWithEmbeddedModelsAndDescription { + fn encode<'a>( + a: Option<&ModelWithEmbeddedModelsAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEmbeddedModelsAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + self.embedded_empty_model.encode_self(e)?; + e.encode_array( + self.embedded_model_array_with_multiple_fields_accessor.len(), + Kind::Any, + )?; + for a in &self.embedded_model_array_with_multiple_fields_accessor { + a.encode_self(e)?; + } + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEmbeddedModelsAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEmbeddedModelsAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEmbeddedModelsAndDescription::new(); + x.embedded_empty_model = EmptyModel::decode(d)?; + let size_embedded_model_array_with_multiple_fields_accessor = d + .decode_array(Kind::Any)?; + for _ in 0..size_embedded_model_array_with_multiple_fields_accessor { + x.embedded_model_array_with_multiple_fields_accessor + .push( + ModelWithMultipleFieldsAccessor::decode(d)? + .ok_or(DecodingError::InvalidArray)?, + ); + } + Ok(Some(x)) + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEmbeddedModelsAccessor { + embedded_empty_model: Option, + embedded_model_array_with_multiple_fields_accessor: Vec< + ModelWithMultipleFieldsAccessor, + >, +} +impl ModelWithEmbeddedModelsAccessor { + pub fn new() -> Self { + Self { + embedded_empty_model: Some(EmptyModel::new()), + embedded_model_array_with_multiple_fields_accessor: Vec::with_capacity(0), + } + } +} +impl Encode for ModelWithEmbeddedModelsAccessor { + fn encode<'a>( + a: Option<&ModelWithEmbeddedModelsAccessor>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEmbeddedModelsAccessor { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + self.embedded_empty_model.encode_self(e)?; + e.encode_array( + self.embedded_model_array_with_multiple_fields_accessor.len(), + Kind::Any, + )?; + for a in &self.embedded_model_array_with_multiple_fields_accessor { + a.encode_self(e)?; + } + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEmbeddedModelsAccessor> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEmbeddedModelsAccessor { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEmbeddedModelsAccessor::new(); + x.embedded_empty_model = EmptyModel::decode(d)?; + let size_embedded_model_array_with_multiple_fields_accessor = d + .decode_array(Kind::Any)?; + for _ in 0..size_embedded_model_array_with_multiple_fields_accessor { + x.embedded_model_array_with_multiple_fields_accessor + .push( + ModelWithMultipleFieldsAccessor::decode(d)? + .ok_or(DecodingError::InvalidArray)?, + ); + } + Ok(Some(x)) + } +} +impl ModelWithEmbeddedModelsAccessor { + pub fn get_embedded_empty_model(&self) -> &Option { + &self.embedded_empty_model + } + pub fn set_embedded_empty_model(&mut self, v: Option) { + self.embedded_empty_model = v; + } +} +impl ModelWithEmbeddedModelsAccessor { + pub fn get_embedded_model_array_with_multiple_fields_accessor( + &self, + ) -> Option<&Vec> { + Some(&self.embedded_model_array_with_multiple_fields_accessor) + } + pub fn set_embedded_model_array_with_multiple_fields_accessor( + &mut self, + v: Vec, + ) { + self.embedded_model_array_with_multiple_fields_accessor = v; + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithEmbeddedModelsAccessorAndDescription { + embedded_empty_model: Option, + embedded_model_array_with_multiple_fields_accessor: Vec< + ModelWithMultipleFieldsAccessor, + >, +} +impl ModelWithEmbeddedModelsAccessorAndDescription { + pub fn new() -> Self { + Self { + embedded_empty_model: Some(EmptyModel::new()), + embedded_model_array_with_multiple_fields_accessor: Vec::with_capacity(0), + } + } +} +impl Encode for ModelWithEmbeddedModelsAccessorAndDescription { + fn encode<'a>( + a: Option<&ModelWithEmbeddedModelsAccessorAndDescription>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithEmbeddedModelsAccessorAndDescription { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + self.embedded_empty_model.encode_self(e)?; + e.encode_array( + self.embedded_model_array_with_multiple_fields_accessor.len(), + Kind::Any, + )?; + for a in &self.embedded_model_array_with_multiple_fields_accessor { + a.encode_self(e)?; + } + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithEmbeddedModelsAccessorAndDescription> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithEmbeddedModelsAccessorAndDescription { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result< + Option, + Box, + > { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithEmbeddedModelsAccessorAndDescription::new(); + x.embedded_empty_model = EmptyModel::decode(d)?; + let size_embedded_model_array_with_multiple_fields_accessor = d + .decode_array(Kind::Any)?; + for _ in 0..size_embedded_model_array_with_multiple_fields_accessor { + x.embedded_model_array_with_multiple_fields_accessor + .push( + ModelWithMultipleFieldsAccessor::decode(d)? + .ok_or(DecodingError::InvalidArray)?, + ); + } + Ok(Some(x)) + } +} +impl ModelWithEmbeddedModelsAccessorAndDescription { + pub fn get_embedded_empty_model(&self) -> &Option { + &self.embedded_empty_model + } + pub fn set_embedded_empty_model(&mut self, v: Option) { + self.embedded_empty_model = v; + } +} +impl ModelWithEmbeddedModelsAccessorAndDescription { + pub fn get_embedded_model_array_with_multiple_fields_accessor( + &self, + ) -> Option<&Vec> { + Some(&self.embedded_model_array_with_multiple_fields_accessor) + } + pub fn set_embedded_model_array_with_multiple_fields_accessor( + &mut self, + v: Vec, + ) { + self.embedded_model_array_with_multiple_fields_accessor = v; + } +} +#[derive(Clone, Debug, PartialEq)] +pub struct ModelWithAllFieldTypes { + pub model_field: Option, + pub model_array_field: Vec, + pub string_field: String, + pub string_array_field: Vec, + pub string_map_field: HashMap, + pub string_map_field_embedded: HashMap, + pub int32_field: i32, + pub int32_array_field: Vec, + pub int32_map_field: HashMap, + pub int32_map_field_embedded: HashMap, + pub int64_field: i64, + pub int64_array_field: Vec, + pub int64_map_field: HashMap, + pub int64_map_field_embedded: HashMap, + pub uint32_field: u32, + pub uint32_array_field: Vec, + pub uint32_map_field: HashMap, + pub uint32_map_field_embedded: HashMap, + pub uint64_field: u64, + pub uint64_array_field: Vec, + pub uint64_map_field: HashMap, + pub uint64_map_field_embedded: HashMap, + pub float32_field: f32, + pub float32_array_field: Vec, + pub float64_field: f64, + pub float64_array_field: Vec, + pub enum_field: GenericEnum, + pub enum_array_field: Vec, + pub enum_map_field: HashMap, + pub enum_map_field_embedded: HashMap, + pub bytes_field: Vec, + pub bytes_array_field: Vec>, + pub bool_field: bool, + pub bool_array_field: Vec, +} +impl ModelWithAllFieldTypes { + pub fn new() -> Self { + Self { + model_field: Some(EmptyModel::new()), + model_array_field: Vec::with_capacity(0), + string_field: "DefaultValue".to_string(), + string_array_field: Vec::with_capacity(0), + string_map_field: HashMap::new(), + string_map_field_embedded: HashMap::new(), + int32_field: 32, + int32_array_field: Vec::with_capacity(0), + int32_map_field: HashMap::new(), + int32_map_field_embedded: HashMap::new(), + int64_field: 64, + int64_array_field: Vec::with_capacity(0), + int64_map_field: HashMap::new(), + int64_map_field_embedded: HashMap::new(), + uint32_field: 32, + uint32_array_field: Vec::with_capacity(0), + uint32_map_field: HashMap::new(), + uint32_map_field_embedded: HashMap::new(), + uint64_field: 64, + uint64_array_field: Vec::with_capacity(0), + uint64_map_field: HashMap::new(), + uint64_map_field_embedded: HashMap::new(), + float32_field: 32.32, + float32_array_field: Vec::with_capacity(0), + float64_field: 64.64, + float64_array_field: Vec::with_capacity(0), + enum_field: GenericEnum::DefaultValue, + enum_array_field: Vec::with_capacity(0), + enum_map_field: HashMap::new(), + enum_map_field_embedded: HashMap::new(), + bytes_field: Vec::with_capacity(512), + bytes_array_field: Vec::with_capacity(0), + bool_field: true, + bool_array_field: Vec::with_capacity(0), + } + } +} +impl Encode for ModelWithAllFieldTypes { + fn encode<'a>( + a: Option<&ModelWithAllFieldTypes>, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + a.encode_self(e) + } +} +impl EncodeSelf for ModelWithAllFieldTypes { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + self.model_field.encode_self(e)?; + e.encode_array(self.model_array_field.len(), Kind::Any)?; + for a in &self.model_array_field { + a.encode_self(e)?; + } + e.encode_string(&self.string_field)?; + e.encode_array(self.string_array_field.len(), Kind::String)?; + for a in &self.string_array_field { + e.encode_string(&a)?; + } + e.encode_map(self.string_map_field.len(), Kind::String, Kind::String)?; + for (k, v) in &self.string_map_field { + e.encode_string(&k)?; + e.encode_string(&v)?; + } + e.encode_map(self.string_map_field_embedded.len(), Kind::String, Kind::Any)?; + for (k, v) in &self.string_map_field_embedded { + e.encode_string(&k)?; + v.encode_self(e)?; + } + e.encode_i32(self.int32_field)?; + e.encode_array(self.int32_array_field.len(), Kind::I32)?; + for a in &self.int32_array_field { + e.encode_i32(*a)?; + } + e.encode_map(self.int32_map_field.len(), Kind::I32, Kind::I32)?; + for (k, v) in &self.int32_map_field { + e.encode_i32(*k)?; + e.encode_i32(*v)?; + } + e.encode_map(self.int32_map_field_embedded.len(), Kind::I32, Kind::Any)?; + for (k, v) in &self.int32_map_field_embedded { + e.encode_i32(*k)?; + v.encode_self(e)?; + } + e.encode_i64(self.int64_field)?; + e.encode_array(self.int64_array_field.len(), Kind::I64)?; + for a in &self.int64_array_field { + e.encode_i64(*a)?; + } + e.encode_map(self.int64_map_field.len(), Kind::I64, Kind::I64)?; + for (k, v) in &self.int64_map_field { + e.encode_i64(*k)?; + e.encode_i64(*v)?; + } + e.encode_map(self.int64_map_field_embedded.len(), Kind::I64, Kind::Any)?; + for (k, v) in &self.int64_map_field_embedded { + e.encode_i64(*k)?; + v.encode_self(e)?; + } + e.encode_u32(self.uint32_field)?; + e.encode_array(self.uint32_array_field.len(), Kind::U32)?; + for a in &self.uint32_array_field { + e.encode_u32(*a)?; + } + e.encode_map(self.uint32_map_field.len(), Kind::U32, Kind::U32)?; + for (k, v) in &self.uint32_map_field { + e.encode_u32(*k)?; + e.encode_u32(*v)?; + } + e.encode_map(self.uint32_map_field_embedded.len(), Kind::U32, Kind::Any)?; + for (k, v) in &self.uint32_map_field_embedded { + e.encode_u32(*k)?; + v.encode_self(e)?; + } + e.encode_u64(self.uint64_field)?; + e.encode_array(self.uint64_array_field.len(), Kind::U64)?; + for a in &self.uint64_array_field { + e.encode_u64(*a)?; + } + e.encode_map(self.uint64_map_field.len(), Kind::U64, Kind::U64)?; + for (k, v) in &self.uint64_map_field { + e.encode_u64(*k)?; + e.encode_u64(*v)?; + } + e.encode_map(self.uint64_map_field_embedded.len(), Kind::U64, Kind::Any)?; + for (k, v) in &self.uint64_map_field_embedded { + e.encode_u64(*k)?; + v.encode_self(e)?; + } + e.encode_f32(self.float32_field)?; + e.encode_array(self.float32_array_field.len(), Kind::F32)?; + for a in &self.float32_array_field { + e.encode_f32(*a)?; + } + e.encode_f64(self.float64_field)?; + e.encode_array(self.float64_array_field.len(), Kind::F64)?; + for a in &self.float64_array_field { + e.encode_f64(*a)?; + } + e.encode_u32(self.enum_field as u32)?; + e.encode_array(self.enum_array_field.len(), Kind::U32)?; + for a in &self.enum_array_field { + e.encode_u32(*a as u32)?; + } + e.encode_map(self.enum_map_field.len(), Kind::U32, Kind::String)?; + for (k, v) in &self.enum_map_field { + e.encode_u32(*k as u32)?; + e.encode_string(&v)?; + } + e.encode_map(self.enum_map_field_embedded.len(), Kind::U32, Kind::Any)?; + for (k, v) in &self.enum_map_field_embedded { + e.encode_u32(*k as u32)?; + v.encode_self(e)?; + } + e.encode_bytes(&self.bytes_field)?; + e.encode_array(self.bytes_array_field.len(), Kind::Bytes)?; + for a in &self.bytes_array_field { + e.encode_bytes(&a)?; + } + e.encode_bool(self.bool_field)?; + e.encode_array(self.bool_array_field.len(), Kind::Bool)?; + for a in &self.bool_array_field { + e.encode_bool(*a)?; + } + Ok(e) + } +} +impl EncodeSelf for Option<&ModelWithAllFieldTypes> { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl EncodeSelf for Option { + fn encode_self<'a, 'b>( + &'b self, + e: &'a mut Cursor>, + ) -> Result<&'a mut Cursor>, Box> { + if let Some(x) = self { + x.encode_self(e)?; + } else { + e.encode_none()?; + } + Ok(e) + } +} +impl Decode for ModelWithAllFieldTypes { + fn decode( + d: &mut Cursor<&mut Vec>, + ) -> Result, Box> { + if d.decode_none() { + return Ok(None); + } + if let Ok(error) = d.decode_error() { + return Err(error); + } + let mut x = ModelWithAllFieldTypes::new(); + x.model_field = EmptyModel::decode(d)?; + let size_model_array_field = d.decode_array(Kind::Any)?; + for _ in 0..size_model_array_field { + x.model_array_field + .push(EmptyModel::decode(d)?.ok_or(DecodingError::InvalidArray)?); + } + x.string_field = d.decode_string()?; + let size_string_array_field = d.decode_array(Kind::String)?; + for _ in 0..size_string_array_field { + x.string_array_field.push(d.decode_string()?); + } + let size_string_map_field = d.decode_map(Kind::String, Kind::String)?; + for _ in 0..size_string_map_field { + let k = d.decode_string()?; + let v = d.decode_string()?; + x.string_map_field.insert(k, v); + } + let size_string_map_field_embedded = d.decode_map(Kind::String, Kind::Any)?; + for _ in 0..size_string_map_field_embedded { + let k = d.decode_string()?; + let v = EmptyModel::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.string_map_field_embedded.insert(k, v); + } + x.int32_field = d.decode_i32()?; + let size_int32_array_field = d.decode_array(Kind::I32)?; + for _ in 0..size_int32_array_field { + x.int32_array_field.push(d.decode_i32()?); + } + let size_int32_map_field = d.decode_map(Kind::I32, Kind::I32)?; + for _ in 0..size_int32_map_field { + let k = d.decode_i32()?; + let v = d.decode_i32()?; + x.int32_map_field.insert(k, v); + } + let size_int32_map_field_embedded = d.decode_map(Kind::I32, Kind::Any)?; + for _ in 0..size_int32_map_field_embedded { + let k = d.decode_i32()?; + let v = EmptyModel::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.int32_map_field_embedded.insert(k, v); + } + x.int64_field = d.decode_i64()?; + let size_int64_array_field = d.decode_array(Kind::I64)?; + for _ in 0..size_int64_array_field { + x.int64_array_field.push(d.decode_i64()?); + } + let size_int64_map_field = d.decode_map(Kind::I64, Kind::I64)?; + for _ in 0..size_int64_map_field { + let k = d.decode_i64()?; + let v = d.decode_i64()?; + x.int64_map_field.insert(k, v); + } + let size_int64_map_field_embedded = d.decode_map(Kind::I64, Kind::Any)?; + for _ in 0..size_int64_map_field_embedded { + let k = d.decode_i64()?; + let v = EmptyModel::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.int64_map_field_embedded.insert(k, v); + } + x.uint32_field = d.decode_u32()?; + let size_uint32_array_field = d.decode_array(Kind::U32)?; + for _ in 0..size_uint32_array_field { + x.uint32_array_field.push(d.decode_u32()?); + } + let size_uint32_map_field = d.decode_map(Kind::U32, Kind::U32)?; + for _ in 0..size_uint32_map_field { + let k = d.decode_u32()?; + let v = d.decode_u32()?; + x.uint32_map_field.insert(k, v); + } + let size_uint32_map_field_embedded = d.decode_map(Kind::U32, Kind::Any)?; + for _ in 0..size_uint32_map_field_embedded { + let k = d.decode_u32()?; + let v = EmptyModel::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.uint32_map_field_embedded.insert(k, v); + } + x.uint64_field = d.decode_u64()?; + let size_uint64_array_field = d.decode_array(Kind::U64)?; + for _ in 0..size_uint64_array_field { + x.uint64_array_field.push(d.decode_u64()?); + } + let size_uint64_map_field = d.decode_map(Kind::U64, Kind::U64)?; + for _ in 0..size_uint64_map_field { + let k = d.decode_u64()?; + let v = d.decode_u64()?; + x.uint64_map_field.insert(k, v); + } + let size_uint64_map_field_embedded = d.decode_map(Kind::U64, Kind::Any)?; + for _ in 0..size_uint64_map_field_embedded { + let k = d.decode_u64()?; + let v = EmptyModel::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.uint64_map_field_embedded.insert(k, v); + } + x.float32_field = d.decode_f32()?; + let size_float32_array_field = d.decode_array(Kind::F32)?; + for _ in 0..size_float32_array_field { + x.float32_array_field.push(d.decode_f32()?); + } + x.float64_field = d.decode_f64()?; + let size_float64_array_field = d.decode_array(Kind::F64)?; + for _ in 0..size_float64_array_field { + x.float64_array_field.push(d.decode_f64()?); + } + x + .enum_field = GenericEnum::try_from(d.decode_u32()?) + .ok() + .ok_or(DecodingError::InvalidEnum)?; + let size_enum_array_field = d.decode_array(Kind::U32)?; + for _ in 0..size_enum_array_field { + x.enum_array_field.push(GenericEnum::try_from(d.decode_u32()?)?); + } + let size_enum_map_field = d.decode_map(Kind::U32, Kind::String)?; + for _ in 0..size_enum_map_field { + let k = GenericEnum::try_from(d.decode_u32()?)?; + let v = d.decode_string()?; + x.enum_map_field.insert(k, v); + } + let size_enum_map_field_embedded = d.decode_map(Kind::U32, Kind::Any)?; + for _ in 0..size_enum_map_field_embedded { + let k = GenericEnum::try_from(d.decode_u32()?)?; + let v = EmptyModel::decode(d)?.ok_or(DecodingError::InvalidMap)?; + x.enum_map_field_embedded.insert(k, v); + } + x.bytes_field = d.decode_bytes()?; + let size_bytes_array_field = d.decode_array(Kind::Bytes)?; + for _ in 0..size_bytes_array_field { + x.bytes_array_field.push(d.decode_bytes()?); + } + x.bool_field = d.decode_bool()?; + let size_bool_array_field = d.decode_array(Kind::Bool)?; + for _ in 0..size_bool_array_field { + x.bool_array_field.push(d.decode_bool()?); + } + Ok(Some(x)) + } +} diff --git a/scale.go b/scale.go index 5c8b019b..1de83df0 100644 --- a/scale.go +++ b/scale.go @@ -28,6 +28,8 @@ import ( "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" + + extension "github.com/loopholelabs/scale-extension-interfaces" ) // Next is the next function in the middleware chain. It's meant to be implemented @@ -68,6 +70,13 @@ func (r *Scale[T]) Instance(next ...Next[T]) (*Instance[T], error) { return newInstance(r.config.context, r, next...) } +// Reset any extensions between executions. +func (r *Scale[T]) resetExtensions() { + for _, ext := range r.config.extensions { + ext.Reset() + } +} + func (r *Scale[T]) init() error { err := r.config.validate() if err != nil { @@ -82,7 +91,30 @@ func (r *Scale[T]) init() error { r.moduleConfig = r.moduleConfig.WithStderr(r.config.stderr) } - envHostModuleBuilder := r.runtime.NewHostModuleBuilder("env"). + envModule := r.runtime.NewHostModuleBuilder("env") + + // Install any extensions... + for _, ext := range r.config.extensions { + fns := ext.Init() + for name, fn := range fns { + wfn := func(n string, f extension.InstallableFunc) func(context.Context, api.Module, []uint64) { + return func(ctx context.Context, mod api.Module, params []uint64) { + mem := mod.Memory() + resize := func(name string, size uint64) (uint64, error) { + w, err := mod.ExportedFunction(name).Call(context.Background(), size) + return w[0], err + } + f(mem, resize, params) + } + }(name, fn) + + envModule.NewFunctionBuilder(). + WithGoModuleFunction(api.GoModuleFunc(wfn), []api.ValueType{api.ValueTypeI64, api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI64}). + WithParameterNames("instance", "pointer", "length").Export(name) + } + } + + envHostModuleBuilder := envModule. NewFunctionBuilder(). WithGoModuleFunction(api.GoModuleFunc(r.next), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{}). WithParameterNames("pointer", "length").Export("next") diff --git a/scalefile/scalefile.go b/scalefile/scalefile.go index edb6be91..d9c8282e 100644 --- a/scalefile/scalefile.go +++ b/scalefile/scalefile.go @@ -63,7 +63,7 @@ type Schema struct { Function string `hcl:"function,attr"` Initialize string `hcl:"initialize,attr"` Description string `hcl:"description,optional"` - Extensions []ExtensionSchema `hcl:"extension,optional"` + Extensions []ExtensionSchema `hcl:"extension,block"` } func ReadSchema(path string) (*Schema, error) { diff --git a/signature/signature.go b/signature/signature.go index 980c0c05..d3ec2c10 100644 --- a/signature/signature.go +++ b/signature/signature.go @@ -458,21 +458,41 @@ func (s *Schema) HasLimitValidator() bool { return s.hasLimitValidator } +// SetHasLimitValidator sets the hasLimitValidator flag +func (s *Schema) SetHasLimitValidator(value bool) { + s.hasLimitValidator = value +} + // HasLengthValidator returns true if the schema has a length validator func (s *Schema) HasLengthValidator() bool { return s.hasLengthValidator } +// SetHasLengthValidator sets the hasLengthValidator flag +func (s *Schema) SetHasLengthValidator(value bool) { + s.hasLengthValidator = value +} + // HasRegexValidator returns true if the schema has a regex validator func (s *Schema) HasRegexValidator() bool { return s.hasRegexValidator } +// SetHasRegexValidator sets the hasRegexValidator flag +func (s *Schema) SetHasRegexValidator(value bool) { + s.hasRegexValidator = value +} + // HasCaseModifier returns true if the schema has a case modifier func (s *Schema) HasCaseModifier() bool { return s.hasCaseModifier } +// SetHasCaseModifier sets the hasCaseModifier flag +func (s *Schema) SetHasCaseModifier(value bool) { + s.hasCaseModifier = value +} + func ValidPrimitiveType(t string) bool { switch t { case "string", "int32", "int64", "uint32", "uint64", "float32", "float64", "bool", "bytes": diff --git a/storage/extension.go b/storage/extension.go new file mode 100644 index 00000000..99e19fb4 --- /dev/null +++ b/storage/extension.go @@ -0,0 +1,353 @@ +/* + Copyright 2022 Loophole Labs + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package storage is used to store and retrieve built Scale Functions +package storage + +import ( + "encoding/hex" + "fmt" + "os" + "path" + "path/filepath" + + "github.com/loopholelabs/scale/extension" + "github.com/loopholelabs/scale/extension/generator" + "github.com/loopholelabs/scale/scalefunc" +) + +const ( + ExtensionDirectory = "extensions" +) + +var ( + DefaultExtension *ExtensionStorage +) + +type Extension struct { + Name string + Tag string + Schema *extension.Schema + Hash string + Organization string +} + +type ExtensionStorage struct { + Directory string +} + +func init() { + homeDir, err := os.UserHomeDir() + if err != nil { + panic(err) + } + DefaultExtension, err = NewExtension(path.Join(homeDir, DefaultDirectory, ExtensionDirectory)) + if err != nil { + panic(err) + } +} + +func NewExtension(baseDirectory string) (*ExtensionStorage, error) { + err := os.MkdirAll(baseDirectory, 0755) + if err != nil { + if !os.IsExist(err) { + return nil, err + } + } + + return &ExtensionStorage{ + Directory: baseDirectory, + }, nil +} + +// Get returns the Scale Extension with the given name, tag, and organization. +// The hash parameter is optional and can be used to check for a specific hash. +func (s *ExtensionStorage) Get(name string, tag string, org string, hash string) (*Extension, error) { + if name == "" || !scalefunc.ValidString(name) { + return nil, ErrInvalidName + } + + if tag == "" || !scalefunc.ValidString(tag) { + return nil, ErrInvalidTag + } + + if org == "" || !scalefunc.ValidString(org) { + return nil, ErrInvalidOrganization + } + + if hash != "" { + f := s.extensionName(name, tag, org, hash) + p := s.fullPath(f) + + stat, err := os.Stat(p) + if err != nil { + return nil, err + } + + if !stat.IsDir() { + return nil, fmt.Errorf("found extension is a file not a directory %s/%s:%s", org, name, tag) + } + + sig, err := extension.ReadSchema(path.Join(p, "extension")) + if err != nil { + return nil, err + } + + return &Extension{ + Name: name, + Tag: tag, + Schema: sig, + Hash: hash, + Organization: org, + }, nil + } + + f := s.extensionSearch(name, tag, org) + p := s.fullPath(f) + + matches, err := filepath.Glob(p) + if err != nil { + return nil, err + } + + if len(matches) == 0 { + return nil, nil + } + + if len(matches) > 1 { + return nil, fmt.Errorf("multiple matches found for %s/%s:%s", org, name, tag) + } + + stat, err := os.Stat(matches[0]) + if err != nil { + return nil, err + } + + if !stat.IsDir() { + return nil, fmt.Errorf("found extension is a file not a directory %s/%s:%s", org, name, tag) + } + + sig, err := extension.ReadSchema(path.Join(matches[0], "extension")) + if err != nil { + return nil, err + } + + return &Extension{ + Name: name, + Tag: tag, + Schema: sig, + Hash: getHashFromName(filepath.Base(matches[0])), + Organization: getOrgFromName(filepath.Base(matches[0])), + }, nil +} + +func (s *ExtensionStorage) Path(name string, tag string, org string, hash string) (string, error) { + if name == "" || !scalefunc.ValidString(name) { + return "", ErrInvalidName + } + + if tag == "" || !scalefunc.ValidString(tag) { + return "", ErrInvalidTag + } + + if org == "" || !scalefunc.ValidString(org) { + return "", ErrInvalidOrganization + } + + if hash != "" { + f := s.extensionName(name, tag, org, hash) + p := s.fullPath(f) + + stat, err := os.Stat(p) + if err != nil { + return "", err + } + + if !stat.IsDir() { + return "", fmt.Errorf("found extension is a file not a directory %s/%s:%s", org, name, tag) + } + + return p, nil + } + + f := s.extensionSearch(name, tag, org) + p := s.fullPath(f) + + matches, err := filepath.Glob(p) + if err != nil { + return "", err + } + + if len(matches) == 0 { + return "", nil + } + + if len(matches) > 1 { + return "", fmt.Errorf("multiple matches found for %s/%s:%s", org, name, tag) + } + + stat, err := os.Stat(matches[0]) + if err != nil { + return "", err + } + + if !stat.IsDir() { + return "", fmt.Errorf("found extension is a file not a directory %s/%s:%s", org, name, tag) + } + + return matches[0], nil +} + +// Put stores the Scale Extension with the given name, tag, organization +func (s *ExtensionStorage) Put(name string, tag string, org string, sig *extension.Schema) error { + hash, err := sig.Hash() + if err != nil { + return err + } + + hashString := hex.EncodeToString(hash) + + f := s.extensionName(name, tag, org, hashString) + directory := s.fullPath(f) + err = os.MkdirAll(directory, 0755) + if err != nil { + return err + } + + err = GenerateExtension(sig, name, tag, org, directory) + if err != nil { + return err + } + + return nil +} + +// Delete removes the Scale Extension with the given name, tag, org, and hash +func (s *ExtensionStorage) Delete(name string, tag string, org string, hash string) error { + return os.RemoveAll(s.fullPath(s.extensionName(name, tag, org, hash))) +} + +// List returns all the Scale Extensions stored in the storage +func (s *ExtensionStorage) List() ([]Extension, error) { + entries, err := os.ReadDir(s.Directory) + if err != nil { + return nil, fmt.Errorf("failed to read storage directory %s: %w", s.Directory, err) + } + var scaleExtensionEntries []Extension + for _, entry := range entries { + if !entry.IsDir() { + continue + } + + sig, err := extension.ReadSchema(path.Join(s.fullPath(entry.Name()), "extension")) + if err != nil { + return nil, fmt.Errorf("failed to decode scale extension %s: %w", s.fullPath(entry.Name()), err) + } + scaleExtensionEntries = append(scaleExtensionEntries, Extension{ + Name: getNameFromName(entry.Name()), + Tag: getTagFromName(entry.Name()), + Schema: sig, + Hash: getHashFromName(entry.Name()), + Organization: getOrgFromName(entry.Name()), + }) + } + return scaleExtensionEntries, nil +} + +func (s *ExtensionStorage) fullPath(p string) string { + return path.Join(s.Directory, p) +} + +func (s *ExtensionStorage) extensionName(name string, tag string, org string, hash string) string { + return fmt.Sprintf("%s_%s_%s_%s_extension", org, name, tag, hash) +} + +func (s *ExtensionStorage) extensionSearch(name string, tag string, org string) string { + return fmt.Sprintf("%s_%s_%s_*_extension", org, name, tag) +} + +// GenerateExtension generates the extension files and writes them to +// the given path. +func GenerateExtension(ext *extension.Schema, name string, tag string, org string, directory string) error { + encoded, err := ext.Encode() + if err != nil { + return err + } + + err = os.WriteFile(path.Join(directory, "extension"), encoded, 0644) + if err != nil { + return err + } + + err = os.MkdirAll(path.Join(directory, "golang", "guest"), 0755) + if err != nil { + return err + } + + err = os.MkdirAll(path.Join(directory, "rust", "guest"), 0755) + if err != nil { + return err + } + + err = os.MkdirAll(path.Join(directory, "golang", "host"), 0755) + if err != nil { + return err + } + + guestPackage, err := generator.GenerateGuestLocal(&generator.Options{ + Extension: ext, + GolangPackageImportPath: fmt.Sprintf("%s_%s_%s_guest", org, name, tag), + GolangPackageName: fmt.Sprintf("%s_%s_%s_guest", org, name, tag), + + RustPackageName: fmt.Sprintf("%s_%s_%s_guest", org, name, tag), + RustPackageVersion: defaultVersion, + }) + if err != nil { + return err + } + + for _, file := range guestPackage.GolangFiles { + err = os.WriteFile(path.Join(directory, "golang", "guest", file.Path()), file.Data(), 0644) + if err != nil { + return err + } + } + + for _, file := range guestPackage.RustFiles { + err = os.WriteFile(path.Join(directory, "rust", "guest", file.Path()), file.Data(), 0644) + if err != nil { + return err + } + } + + hostPackage, err := generator.GenerateHostLocal(&generator.Options{ + Extension: ext, + GolangPackageImportPath: fmt.Sprintf("%s_%s_%s_guest", org, name, tag), + GolangPackageName: fmt.Sprintf("%s_%s_%s_guest", org, name, tag), + }) + if err != nil { + return err + } + + for _, file := range hostPackage.GolangFiles { + err = os.WriteFile(path.Join(directory, "golang", "host", file.Path()), file.Data(), 0644) + if err != nil { + return err + } + } + + return nil +}