[
  {
    "path": ".github/dependabot.yaml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: gomod\n    directory: /\n    schedule:\n      interval: monthly\n    groups:\n      all-dependencies:\n        patterns:\n          - \"*\""
  },
  {
    "path": ".github/workflows/blockwatch.yml",
    "content": "name: blockwatch\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\npermissions:\n  contents: read\n\njobs:\n  blockwatch:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: mennanov/blockwatch-action@v1\n"
  },
  {
    "path": ".github/workflows/coverage.yml",
    "content": "name: Tests coverage\n\non: [ \"push\", \"pull_request\" ]\n\njobs:\n\n  build:\n    name: Coverage\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup Go 1.22\n        uses: actions/setup-go@v5\n        with:\n          go-version: '1.22'\n      - name: Run tests with coverage\n        run: go test -v -coverprofile=coverage.txt -covermode=atomic ./...\n      - uses: codecov/codecov-action@v4\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          verbose: true\n"
  },
  {
    "path": ".github/workflows/linter.yml",
    "content": "name: Linter\n\non: [ \"push\", \"pull_request\" ]\n\njobs:\n\n  build:\n    name: Linter\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup Go 1.22\n        uses: actions/setup-go@v5\n        with:\n          go-version: '1.22'\n      - name: Go vet\n        run: go vet ./...\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Go tests\n\non: [ push, pull_request ]\n\njobs:\n  go-test:\n\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        go-version:\n          # <block keep-sorted=\"asc\" keep-unique>\n          - '1.17'\n          - '1.18'\n          - '1.19'\n          - '1.20'\n          - '1.21'\n          - '1.22'\n          # </block>\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup Go ${{ matrix.go-version }}\n        uses: actions/setup-go@v5\n        with:\n          go-version: ${{ matrix.go-version }}\n          cache: true\n\n      - name: Run tests\n        run: go test -v ./..."
  },
  {
    "path": ".gitignore",
    "content": ".idea/\nvendor/\ncoverage.out\ncoverage.txt\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: local\n    hooks:\n      - id: blockwatch\n        name: blockwatch\n        entry: bash -c 'git diff --patch --cached --unified=0 | blockwatch'\n        language: system\n        stages: [ pre-commit ]\n        pass_filenames: false\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Renat Mennanov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "## Protobuf Field Mask utils for Go\n\n[![Tests](https://github.com/mennanov/fieldmask-utils/actions/workflows/tests.yml/badge.svg)](https://github.com/mennanov/fieldmask-utils/actions/workflows/tests.yml)\n[![Coverage](https://codecov.io/gh/mennanov/fieldmask-utils/branch/master/graph/badge.svg?token=O7HtNMO6Ra)](https://codecov.io/gh/mennanov/fieldmask-utils)\n\nFeatures:\n\n* Copy from any Go struct to any compatible Go struct with a field mask applied\n* Copy from any Go struct to a `map[string]interface{}` with a field mask applied\n* Extensible masks (e.g. inverse mask: copy all except those mentioned, etc.)\n* Supports [Protobuf Any](https://developers.google.com/protocol-buffers/docs/proto3#any) message types.\n\nIf you're looking for a simple FieldMask library to work with protobuf messages only (not arbitrary structs) consider this tiny repo: [https://github.com/mennanov/fmutils](https://github.com/mennanov/fmutils)\n\n### Examples\n\nCopy from a protobuf message to a protobuf message:\n\n```proto\n// testproto/test.proto\n\nmessage UpdateUserRequest {\n    User user = 1;\n    google.protobuf.FieldMask field_mask = 2;\n}\n```\n\n```go\npackage main\n\nimport fieldmask_utils \"github.com/mennanov/fieldmask-utils\"\n\n// A function that maps field mask field names to the names used in Go structs.\n// It has to be implemented according to your needs.\n// Scroll down for a reference on how to apply field masks to your gRPC services.\nfunc naming(s string) string {\n\tif s == \"foo\" {\n\t\treturn \"Foo\"\n\t}\n\treturn s\n}\n\nfunc main () {\n\tvar request UpdateUserRequest\n\tuserDst := &testproto.User{} // a struct to copy to\n\tmask, _ := fieldmask_utils.MaskFromPaths(request.FieldMask.Paths, naming)\n\tfieldmask_utils.StructToStruct(mask, request.User, userDst)\n\t// Only the fields mentioned in the field mask will be copied to userDst, other fields are left intact\n}\n```\n\nCopy from a protobuf message to a `map[string]interface{}`:\n\n```go\npackage main\n\nimport fieldmask_utils \"github.com/mennanov/fieldmask-utils\"\n\nfunc main() {\n\tvar request UpdateUserRequest\n\tuserDst := make(map[string]interface{}) // a map to copy to\n\tmask, _ := fieldmask_utils.MaskFromProtoFieldMask(request.FieldMask, naming)\n\terr := fieldmask_utils.StructToMap(mask, request.User, userDst)\n\t// Only the fields mentioned in the field mask will be copied to userDst, other fields are left intact\n}\n```\n\nCopy with an inverse mask:\n\n```go\npackage main\n\nimport fieldmask_utils \"github.com/mennanov/fieldmask-utils\"\n\nfunc main() {\n\tvar request UpdateUserRequest\n\tuserDst := &testproto.User{} // a struct to copy to\n\tmask := fieldmask_utils.MaskInverse{\"Id\": nil, \"Friends\": fieldmask_utils.MaskInverse{\"Username\": nil}}\n\tfieldmask_utils.StructToStruct(mask, request.User, userDst)\n\t// Only the fields that are not mentioned in the field mask will be copied to userDst, other fields are left intact.\n}\n```\n\n#### Naming function\n\nFor developers that are looking for a mechanism to apply a mask field in their update endpoints using gRPC services,\nthere are multiple options for the naming function described above:\n\n- Using the `CamelCase` function provided in\n  the [original protobuf repository](https://github.com/golang/protobuf/blob/master/protoc-gen-go/generator/generator.go#L2648).\n  This repository has been deprecated and it will potentially trigger lint errors.\n    - You can copy-paste the `CamelCase` function to your own project or,\n    - You can use an [Open Source alternative](https://github.com/gojaguar/jaguar) that provides the same functionality,\n      already took care of [copying the code](https://github.com/gojaguar/jaguar/blob/main/strings/pascal_case.go), and also added tests.\n\n```go\nfunc main() {\n    mask := &fieldmaskpb.FieldMask{Paths: []string{\"username\"}}\n    mask.Normalize()\n    req := &UpdateUserRequest{\n        User: &User{\n            Id:       1234,\n            Username: \"Test\",\n        },\n    }\n    if !mask.IsValid(req) {\n        return\n    }\n    protoMask, err := fieldmask_utils.MaskFromProtoFieldMask(mask, strings.PascalCase)\n    if err != nil {\n        return\n    }\n    m := make(map[string]any)\n    err = fieldmask_utils.StructToMap(protoMask, req, m)\n\tif err != nil {\n\t\treturn\n    }\n\tfmt.Println(\"Resulting map:\", m)\n}\n```\n\nThis will result in a map that contains the fields that need to be updated with their respective values.\n\n#### Converter hooks\n\nWhen trying to assign a source field to a destination using different types, one can use the Option `WithConverterHook`.\nAll provided converter functions will be tried in order until src is assignable to dst or an error occured.\n\nBelow you will find an example of how to convert from string to int64 when applying a mask by specifying such converter:\n\n```go\ntype A struct {\n    Field1 string\n}\ntype B struct {\n    Field1 int64\n}\n\nfunc main() {\n\tsrc := &A{\n\t\tField1: \"   42   \",\n\t}\n\tdst := &B{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\n    err = fieldmask_utils.StructToStruct(mask, src, dst,\n\t\tfieldmask_utils.WithConverterHook(func(src, dst *reflect.Value) (interface{}, error) {\n\t\t\tdata := src.Interface()\n\n            // only care for this conversion\n\t\t\tif src.Kind() != reflect.String ||\n\t\t\t\tdst.Kind() != reflect.Int64 {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n            // cast it\n\t\t\traw, ok := data.(string)\n\t\t\tif !ok {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n            // parse it\n\t\t\treturn strconv.ParseInt(strings.TrimSpace(raw), 10, 64)\n\t\t}))\n\n\tfmt.Println(\"src:\", src)\n\tfmt.Println(\"dst:\", dst)\n}\n```\n\n### Limitations\n\n1.  Larger scope field masks have no effect and are not considered invalid:\n\n    field mask strings `\"a\", \"a.b\", \"a.b.c\"` will result in a mask `a{b{c}}`, which is the same as `\"a.b.c\"`.\n\n2.  Masks inside a protobuf `Map` are not supported.\n3.  When copying from a struct to struct the destination struct must have the same fields (or a subset)\n    as the source struct. Either of source or destination fields can be a pointer as long as it is a pointer to\n    the type of the corresponding field.\n4. `oneof` fields are represented differently in `fieldmaskpb.FieldMask` compared to `fieldmask_util.Mask`. In\n    [FieldMask](https://pkg.go.dev/google.golang.org/protobuf/types/known/fieldmaskpb#:~:text=%23%20Field%20Masks%20and%20Oneof%20Fields)\n    the fields are represented using their property name, in this library they are prefixed with the `oneof` name\n    matching how Go generated code is laid out. This can lead to issues when converting between the two, for example\n    when using `MaskFromPaths` or `MaskFromProtoFieldMask`.\n"
  },
  {
    "path": "copy.go",
    "content": "// Package fieldmask_utils provides utility functions for copying data from structs using a field mask.\npackage fieldmask_utils\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/pkg/errors\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/known/anypb\"\n)\n\n// StructToStruct copies `src` struct to `dst` struct using the given FieldFilter.\n// Only the fields where FieldFilter returns true will be copied to `dst`.\n// `src` and `dst` must be coherent in terms of the field names, but it is not required for them to be of the same type.\n// Unexported fields are copied only if the corresponding struct filter is empty and `dst` is assignable to `src`.\nfunc StructToStruct(filter FieldFilter, src, dst interface{}, userOpts ...Option) error {\n\topts := newDefaultOptions()\n\tfor _, o := range userOpts {\n\t\to(opts)\n\t}\n\n\tdstVal := reflect.ValueOf(dst)\n\tif dstVal.Kind() != reflect.Ptr {\n\t\treturn errors.Errorf(\"dst must be a pointer, %s given\", dstVal.Kind())\n\t}\n\tsrcVal := indirect(reflect.ValueOf(src))\n\tif srcVal.Kind() != reflect.Struct {\n\t\treturn errors.Errorf(\"src kind must be a struct, %s given\", srcVal.Kind())\n\t}\n\tdstVal = indirect(dstVal)\n\tif dstVal.Kind() != reflect.Struct {\n\t\treturn errors.Errorf(\"dst kind must be a struct, %s given\", dstVal.Kind())\n\t}\n\treturn structToStruct(filter, &srcVal, &dstVal, opts)\n}\n\nfunc ensureCompatible(src, dst *reflect.Value) error {\n\tsrcKind := src.Kind()\n\tif srcKind == reflect.Ptr {\n\t\tsrcKind = src.Type().Elem().Kind()\n\t}\n\tdstKind := dst.Kind()\n\tif dstKind == reflect.Ptr {\n\t\tdstKind = dst.Type().Elem().Kind()\n\t}\n\tif srcKind != dstKind {\n\t\treturn errors.Errorf(\"src kind %s differs from dst kind %s\", srcKind, dstKind)\n\t}\n\treturn nil\n}\n\nfunc structToStruct(filter FieldFilter, src, dst *reflect.Value, userOptions *options) error {\n\tif err := ensureCompatible(src, dst); err != nil {\n\t\t// incompatible, try using converters:\n\t\tconverted := false\n\t\tfor _, fn := range userOptions.ConverterHooks {\n\t\t\tdata, err := fn(src, dst)\n\t\t\tif err != nil {\n\t\t\t\t// error during conversion, pass upwards\n\t\t\t\treturn err\n\t\t\t}\n\t\t\trdata := reflect.ValueOf(data)\n\t\t\tif err := ensureCompatible(&rdata, dst); err != nil {\n\t\t\t\t// no change using conversion, try next\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// it is convertable, replace src\n\t\t\tsrc = &rdata\n\t\t\tconverted = true\n\t\t\tbreak\n\t\t}\n\t\tif !converted {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tswitch src.Kind() {\n\tcase reflect.Struct:\n\t\tif dst.CanSet() && dst.Type().AssignableTo(src.Type()) && filter.IsEmpty() {\n\t\t\tdst.Set(*src)\n\t\t\treturn nil\n\t\t}\n\n\t\tif dst.Kind() == reflect.Ptr {\n\t\t\tif dst.IsNil() {\n\t\t\t\tdst.Set(reflect.New(dst.Type().Elem()))\n\t\t\t}\n\t\t\tv := dst.Elem()\n\t\t\tdst = &v\n\t\t}\n\n\t\tfor i := 0; i < src.NumField(); i++ {\n\t\t\tsrcType := src.Type()\n\t\t\tsrcName := fieldName(userOptions.SrcTag, srcType.Field(i))\n\t\t\tdstName := fieldName(userOptions.DstTag, srcType.Field(i))\n\n\t\t\tsubFilter, ok := filter.Filter(srcName)\n\t\t\tif !ok {\n\t\t\t\t// Skip this field.\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsrcField := src.Field(i)\n\t\t\tif !srcField.CanInterface() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdstField := dst.FieldByName(dstName)\n\t\t\tif !dstField.CanSet() {\n\t\t\t\treturn errors.Errorf(\"Can't set a value on a destination field %s\", dstName)\n\t\t\t}\n\n\t\t\tif err := structToStruct(subFilter, &srcField, &dstField, userOptions); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\tcase reflect.Ptr:\n\t\tif src.IsNil() {\n\t\t\t// If src is nil set dst to nil too.\n\t\t\tdst.Set(reflect.Zero(dst.Type()))\n\t\t\tbreak\n\t\t}\n\t\tif dst.Kind() == reflect.Ptr && dst.IsNil() {\n\t\t\t// If dst is nil create a new instance of the underlying type and set dst to the pointer of that instance.\n\t\t\tdst.Set(reflect.New(dst.Type().Elem()))\n\t\t}\n\n\t\tif srcAny, ok := src.Interface().(*anypb.Any); ok {\n\t\t\tdstAny, ok := dst.Interface().(*anypb.Any)\n\t\t\tif !ok {\n\t\t\t\treturn errors.Errorf(\"dst type is %s, expected: %s \", dst.Type(), \"*any.Any\")\n\t\t\t}\n\n\t\t\t// If subfilter is empty then copy the entire any without any unmarshalling.\n\t\t\tif filter.IsEmpty() && !userOptions.UnmarshalAllAny {\n\t\t\t\tdst.Set(*src)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tsrcProto, err := srcAny.UnmarshalNew()\n\t\t\tif err != nil {\n\t\t\t\treturn errors.WithStack(err)\n\t\t\t}\n\t\t\tsrcProtoValue := reflect.ValueOf(srcProto)\n\n\t\t\tif dstAny.GetTypeUrl() == \"\" {\n\t\t\t\tdstAny.TypeUrl = srcAny.GetTypeUrl()\n\t\t\t}\n\t\t\tdstProto, err := dstAny.UnmarshalNew()\n\t\t\tif err != nil {\n\t\t\t\treturn errors.WithStack(err)\n\t\t\t}\n\t\t\tdstProtoValue := reflect.ValueOf(dstProto)\n\n\t\t\tif err := structToStruct(filter, &srcProtoValue, &dstProtoValue, userOptions); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tnewDstAny := new(anypb.Any)\n\t\t\tif err := newDstAny.MarshalFrom(dstProtoValue.Interface().(proto.Message)); err != nil {\n\t\t\t\treturn errors.WithStack(err)\n\t\t\t}\n\n\t\t\tdst.Set(reflect.ValueOf(newDstAny))\n\t\t\tbreak\n\t\t}\n\n\t\tsrcElem, dstElem := src.Elem(), *dst\n\t\tif dst.Kind() == reflect.Ptr {\n\t\t\tdstElem = dst.Elem()\n\t\t}\n\n\t\tif err := structToStruct(filter, &srcElem, &dstElem, userOptions); err != nil {\n\t\t\treturn err\n\t\t}\n\n\tcase reflect.Interface:\n\t\tif src.IsNil() {\n\t\t\t// If src is nil set dst to nil too.\n\t\t\tdst.Set(reflect.Zero(dst.Type()))\n\t\t\tbreak\n\t\t}\n\t\tif dst.IsNil() {\n\t\t\tif src.Elem().Kind() != reflect.Ptr {\n\t\t\t\t// Non-pointer interface implementations are not addressable.\n\t\t\t\treturn errors.Errorf(\"expected a pointer for an interface value, got %s instead\", src.Elem().Kind())\n\t\t\t}\n\t\t\tdst.Set(reflect.New(src.Elem().Elem().Type()))\n\t\t}\n\n\t\tsrcElem, dstElem := src.Elem(), dst.Elem()\n\t\tif err := structToStruct(filter, &srcElem, &dstElem, userOptions); err != nil {\n\t\t\treturn err\n\t\t}\n\n\tcase reflect.Slice:\n\t\tif src.IsNil() {\n\t\t\t// If the source slice is nil the dst slice is set to nil too.\n\t\t\tdst.Set(reflect.Zero(dst.Type()))\n\t\t\tbreak\n\t\t}\n\n\t\tdstLen := dst.Len()\n\t\tsrcLen := userOptions.CopyListSize(src)\n\n\t\tfor i := 0; i < srcLen; i++ {\n\t\t\tsrcItem := src.Index(i)\n\t\t\tvar dstItem reflect.Value\n\t\t\tif i < dstLen {\n\t\t\t\t// Use an existing item.\n\t\t\t\tdstItem = dst.Index(i)\n\t\t\t} else {\n\t\t\t\t// Create a new item if needed.\n\t\t\t\tdstItem = reflect.New(dst.Type().Elem()).Elem()\n\t\t\t}\n\n\t\t\tif err := structToStruct(filter, &srcItem, &dstItem, userOptions); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif i >= dstLen {\n\t\t\t\t// Append newly created items to the slice.\n\t\t\t\tdst.Set(reflect.Append(*dst, dstItem))\n\t\t\t}\n\t\t}\n\t\tif dstLen > srcLen {\n\t\t\tdst.SetLen(srcLen)\n\t\t}\n\n\tcase reflect.Array:\n\t\tdstLen := dst.Len()\n\t\tsrcLen := userOptions.CopyListSize(src)\n\t\tif dstLen < srcLen {\n\t\t\treturn errors.Errorf(\"dst array size %d is less than src size %d\", dstLen, srcLen)\n\t\t}\n\t\tfor i := 0; i < srcLen; i++ {\n\t\t\tsrcItem := src.Index(i)\n\t\t\tdstItem := dst.Index(i)\n\t\t\tif err := structToStruct(filter, &srcItem, &dstItem, userOptions); err != nil {\n\t\t\t\treturn errors.WithStack(err)\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tif !dst.CanSet() {\n\t\t\treturn errors.Errorf(\"dst %s, %s is not settable\", dst, dst.Type())\n\t\t}\n\t\tif dst.Kind() == reflect.Ptr {\n\t\t\tif !src.CanAddr() {\n\t\t\t\treturn errors.Errorf(\"src %s, %s is not addressable\", src, src.Type())\n\t\t\t}\n\t\t\tdst.Set(src.Addr())\n\t\t} else {\n\t\t\tdst.Set(*src)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// options are used in StructToStruct and StructToMap functions to modify the copying behavior.\ntype options struct {\n\t// DstTag can be used to customize the dst field name according to the field's tag, i.g. json.\n\tDstTag string\n\n\t// SrcTag can be used to customize the src field name according to the field's tag, i.g. json.\n\tSrcTag string\n\n\t// CopyListSize can control the number of elements copied from src depending on src's Value\n\tCopyListSize func(src *reflect.Value) int\n\n\t// MapVisitor is called for every filtered field in structToMap.\n\t//\n\t// It is called before copying the data from source to destination allowing custom processing.\n\t// If the visitor function returns true the visited field is skipped.\n\tMapVisitor mapVisitor\n\n\t// UnmarshalAllAny is used to indicate unmarshal all any fields. Default to true to keep backward compatibility.\n\t//\n\t// If an any field is encountered and this flag is not set, it will only Unmarshal it if there is a subfilter for that field.\n\t// If set it will always Unmarshal all any fields\n\tUnmarshalAllAny bool\n\n\t// ConverterHooks stores converter functions to be used when calling [StructToStruct].\n\t//\n\t// All converters will be tried in order to convert a src to dst in cases\n\t// where src cannot be directly assigned to dst.\n\t// Any value returned by converters will be used for src if it is assignable\n\t// after conversion.\n\t// If a converter returns an error that error is propagated to the\n\t// initial call of StructToStruct.\n\tConverterHooks []func(src, dst *reflect.Value) (interface{}, error)\n}\n\n// mapVisitor is called for every filtered field in structToMap.\ntype mapVisitor func(\n\tfilter FieldFilter, src, dst reflect.Value,\n\tsrcFieldName, dstFieldName string, srcFieldValue reflect.Value) MapVisitorResult\n\ntype MapVisitorResult struct {\n\tSkipToNext bool\n\tUpdatedDst *reflect.Value\n}\n\n// Option function modifies the given options.\ntype Option func(*options)\n\n// WithTag sets the destination field name\nfunc WithTag(s string) Option {\n\treturn func(o *options) {\n\t\to.DstTag = s\n\t}\n}\n\n// WithSrcTag sets an option that gets the source field name from the field's tag.\nfunc WithSrcTag(s string) Option {\n\treturn func(o *options) {\n\t\to.SrcTag = s\n\t}\n}\n\n// WithCopyListSize sets CopyListSize func you can set copy size according to src.\nfunc WithCopyListSize(f func(src *reflect.Value) int) Option {\n\treturn func(o *options) {\n\t\to.CopyListSize = f\n\t}\n}\n\n// WithMapVisitor sets the fields visitor function for StructToMap.\nfunc WithMapVisitor(visitor mapVisitor) Option {\n\treturn func(o *options) {\n\t\to.MapVisitor = visitor\n\t}\n}\n\nfunc WithUnmarshalAllAny(unmarshal bool) Option {\n\treturn func(o *options) {\n\t\to.UnmarshalAllAny = unmarshal\n\t}\n}\n\n// WithConverterHook adds a converter hook to convert from src to dst.\nfunc WithConverterHook(converter func(src, dst *reflect.Value) (interface{}, error)) Option {\n\treturn func(o *options) {\n\t\to.ConverterHooks = append(o.ConverterHooks, converter)\n\t}\n}\n\nfunc newDefaultOptions() *options {\n\t// set default CopyListSize is func which return src.Len()\n\treturn &options{\n\t\tCopyListSize:    func(src *reflect.Value) int { return src.Len() },\n\t\tUnmarshalAllAny: true,\n\t}\n}\n\n// fieldName gets the field name according to the field's tag, or gets StructField.Name default when the field's tag is empty.\nfunc fieldName(tag string, f reflect.StructField) string {\n\tif tag == \"\" {\n\t\treturn f.Name\n\t}\n\tlookupResult, ok := f.Tag.Lookup(tag)\n\tif !ok {\n\t\treturn f.Name\n\t}\n\tfirstComma := strings.Index(lookupResult, \",\")\n\tif firstComma == -1 {\n\t\treturn lookupResult\n\t}\n\treturn lookupResult[:firstComma]\n}\n\n// StructToMap copies `src` struct to the `dst` map.\n// Behavior is similar to `StructToStruct`.\n// Arrays in the non-empty dst are converted to slices.\nfunc StructToMap(filter FieldFilter, src interface{}, dst map[string]interface{}, userOpts ...Option) error {\n\topts := newDefaultOptions()\n\tfor _, o := range userOpts {\n\t\to(opts)\n\t}\n\t_, err := structToMap(filter, reflect.ValueOf(src), reflect.ValueOf(dst), opts)\n\treturn err\n}\n\nfunc structToMap(filter FieldFilter, src, dst reflect.Value, userOptions *options) (reflect.Value, error) {\n\tswitch src.Kind() {\n\tcase reflect.Struct:\n\t\tif dst.Kind() != reflect.Map {\n\t\t\treturn dst, errors.Errorf(\"incompatible destination kind: %s, expected map\", dst.Kind())\n\t\t}\n\t\tsrcType := src.Type()\n\t\tfor i := 0; i < src.NumField(); i++ {\n\t\t\tsrcName := fieldName(userOptions.SrcTag, srcType.Field(i))\n\t\t\tif !isExported(srcType.Field(i)) {\n\t\t\t\t// Unexported fields can not be copied.\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsubFilter, ok := filter.Filter(srcName)\n\t\t\tif !ok {\n\t\t\t\t// Skip this field.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tsrcField := indirect(src.Field(i))\n\t\t\tdstName := fieldName(userOptions.DstTag, srcType.Field(i))\n\t\t\tmapValue := indirect(dst.MapIndex(reflect.ValueOf(dstName)))\n\t\t\tif !mapValue.IsValid() {\n\t\t\t\tif srcField.IsValid() {\n\t\t\t\t\tmapValue = newValue(srcField.Type())\n\t\t\t\t} else {\n\t\t\t\t\tdstMap := dst.Interface().(map[string]interface{})\n\t\t\t\t\tdstMap[dstName] = nil\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif userOptions.MapVisitor != nil {\n\t\t\t\tresult := userOptions.MapVisitor(filter, src, mapValue, srcName, dstName, srcField)\n\t\t\t\tif result.UpdatedDst != nil {\n\t\t\t\t\tmapValue = *result.UpdatedDst\n\n\t\t\t\t}\n\t\t\t\tif result.SkipToNext {\n\t\t\t\t\tif result.UpdatedDst != nil {\n\t\t\t\t\t\tdst.SetMapIndex(reflect.ValueOf(dstName), mapValue)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif isPrimitive(mapValue.Kind()) {\n\t\t\t\tdst.SetMapIndex(reflect.ValueOf(dstName), srcField)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar err error\n\t\t\tif mapValue, err = structToMap(subFilter, srcField, mapValue, userOptions); err != nil {\n\t\t\t\treturn dst, err\n\t\t\t}\n\t\t\tdst.SetMapIndex(reflect.ValueOf(dstName), mapValue)\n\t\t}\n\n\tcase reflect.Ptr:\n\t\tif src.IsNil() {\n\t\t\treflect.ValueOf(dst).Set(reflect.ValueOf(nil))\n\t\t\tbreak\n\t\t}\n\t\tvar err error\n\t\tif dst, err = structToMap(filter, indirect(src), dst, userOptions); err != nil {\n\t\t\treturn dst, err\n\t\t}\n\n\tcase reflect.Interface:\n\t\tif src.IsNil() {\n\t\t\treflect.ValueOf(dst).Set(reflect.ValueOf(nil))\n\t\t\tbreak\n\t\t}\n\n\t\tvar err error\n\t\tif dst, err = structToMap(filter, indirect(src), dst, userOptions); err != nil {\n\t\t\treturn dst, err\n\t\t}\n\n\tcase reflect.Array, reflect.Slice:\n\t\tif dstKind := dst.Kind(); dstKind != reflect.Slice && dstKind != reflect.Array {\n\t\t\treturn dst, errors.Errorf(\"incompatible destination kind: %s, expected slice\", dst.Kind())\n\t\t}\n\t\titemType := src.Type().Elem()\n\t\tdesiredDstLen := userOptions.CopyListSize(&src)\n\t\titemKind := itemType.Kind()\n\t\tif isPrimitive(itemKind) {\n\t\t\t// Handle this array/slice as a regular non-nested data structure: copy it entirely to dst.\n\t\t\tif desiredDstLen < src.Len() {\n\t\t\t\tdst = src.Slice(0, desiredDstLen)\n\t\t\t} else {\n\t\t\t\tdst = src\n\t\t\t}\n\t\t} else {\n\t\t\tif dst.Kind() == reflect.Array {\n\t\t\t\t// Convert the array to a slice.\n\t\t\t\tsliceDst := newValue(src.Type())\n\t\t\t\tfor i := 0; i < dst.Len(); i++ {\n\t\t\t\t\tsliceDst = reflect.Append(sliceDst, dst.Index(i))\n\t\t\t\t}\n\t\t\t\tdst = sliceDst\n\t\t\t}\n\t\t\tvar err error\n\t\t\tfor i := 0; i < desiredDstLen; i++ {\n\t\t\t\titemExists := false\n\t\t\t\tvar subDst reflect.Value\n\t\t\t\tif i < dst.Len() {\n\t\t\t\t\tsubDst = dst.Index(i)\n\t\t\t\t\titemExists = true\n\t\t\t\t} else {\n\t\t\t\t\tsubDst = newValue(itemType)\n\t\t\t\t}\n\t\t\t\tif subDst, err = structToMap(filter, src.Index(i), subDst, userOptions); err != nil {\n\t\t\t\t\treturn subDst, err\n\t\t\t\t}\n\t\t\t\tif !itemExists {\n\t\t\t\t\tdst = reflect.Append(dst, subDst)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif desiredDstLen < dst.Len() {\n\t\t\t\tdst = dst.Slice(0, desiredDstLen)\n\t\t\t}\n\t\t}\n\n\tcase reflect.Invalid:\n\t\tdst.Set(reflect.ValueOf(nil))\n\n\tdefault:\n\t\tdst.Set(src)\n\t}\n\treturn dst, nil\n}\n\nfunc indirect(v reflect.Value) reflect.Value {\n\tfor v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {\n\t\tv = v.Elem()\n\t}\n\treturn v\n}\n\n// isPrimitive checks whether the given kind is simple enough so that it can be copied directly without recursion.\nfunc isPrimitive(kind reflect.Kind) bool {\n\treturn kind != reflect.Ptr &&\n\t\tkind != reflect.Struct &&\n\t\tkind != reflect.Interface &&\n\t\tkind != reflect.Slice &&\n\t\tkind != reflect.Array &&\n\t\tkind != reflect.Map\n}\n\n// newValue creates a new value given its type.\nfunc newValue(t reflect.Type) reflect.Value {\n\tswitch t.Kind() {\n\tcase reflect.Struct:\n\t\treturn reflect.MakeMap(reflect.TypeOf(map[string]interface{}{}))\n\n\tcase reflect.Array, reflect.Slice:\n\t\treturn reflect.MakeSlice(reflect.SliceOf(newValue(t.Elem()).Type()), 0, 0)\n\n\tcase reflect.Ptr:\n\t\treturn newValue(t.Elem())\n\n\tdefault:\n\t\treturn reflect.New(t).Elem()\n\t}\n}\n\n// isExported is a backport of reflect.StructField.IsExported() for the older versions of golang (<1.17).\nfunc isExported(f reflect.StructField) bool {\n\treturn f.PkgPath == \"\"\n}\n"
  },
  {
    "path": "copy_proto_test.go",
    "content": "package fieldmask_utils_test\n\nimport (\n\t\"testing\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/known/anypb\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tfieldmask_utils \"github.com/mennanov/fieldmask-utils\"\n\t\"github.com/mennanov/fieldmask-utils/testproto\"\n)\n\nvar testUserFull *testproto.User\nvar testUserPartial *testproto.User\n\nfunc init() {\n\tts := &timestamppb.Timestamp{\n\t\tSeconds: 5, // easy to verify\n\t\tNanos:   6, // easy to verify\n\t}\n\tserializedTs, _ := proto.Marshal(ts)\n\n\tfriend1 := &testproto.User{\n\t\tId:          2,\n\t\tUsername:    \"friend\",\n\t\tRole:        testproto.Role_REGULAR,\n\t\tMeta:        map[string]string{\"foo\": \"bar\"},\n\t\tDeactivated: true,\n\t\tPermissions: []testproto.Permission{testproto.Permission_READ, testproto.Permission_WRITE},\n\t\tAvatar: &testproto.Image{\n\t\t\tOriginalUrl: \"original.jpg\",\n\t\t\tResizedUrl:  \"resized.jpg\",\n\t\t},\n\t\tImages: []*testproto.Image{\n\t\t\t{\n\t\t\t\tOriginalUrl: \"FRIEND original_image1.jpg\",\n\t\t\t\tResizedUrl:  \"FRIEND resized_image1.jpg\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tOriginalUrl: \"FRIEND original_image2.jpg\",\n\t\t\t\tResizedUrl:  \"FRIEND resized_image2.jpg\",\n\t\t\t},\n\t\t},\n\t\tTags: []string{\"FRIEND tag1\", \"FRIEND tag2\", \"FRIEND tag3\"},\n\t\tName: &testproto.User_FemaleName{FemaleName: \"Maggy\"},\n\t}\n\n\ttestUserFull = &testproto.User{\n\t\tId:          1,\n\t\tUsername:    \"username\",\n\t\tRole:        testproto.Role_ADMIN,\n\t\tMeta:        map[string]string{\"foo\": \"bar\"},\n\t\tDeactivated: true,\n\t\tPermissions: []testproto.Permission{testproto.Permission_READ, testproto.Permission_WRITE},\n\t\tAvatar: &testproto.Image{\n\t\t\tOriginalUrl: \"original.jpg\",\n\t\t\tResizedUrl:  \"resized.jpg\",\n\t\t},\n\t\tImages: []*testproto.Image{\n\t\t\t{\n\t\t\t\tOriginalUrl: \"original_image1.jpg\",\n\t\t\t\tResizedUrl:  \"resized_image1.jpg\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tOriginalUrl: \"original_image2.jpg\",\n\t\t\t\tResizedUrl:  \"resized_image2.jpg\",\n\t\t\t},\n\t\t},\n\t\tTags:    []string{\"tag1\", \"tag2\", \"tag3\"},\n\t\tFriends: []*testproto.User{friend1},\n\t\tName:    &testproto.User_MaleName{MaleName: \"John\"},\n\t\tDetails: []*anypb.Any{\n\t\t\t{\n\t\t\t\tTypeUrl: string(\"example.com/example/\" + proto.MessageName(ts)),\n\t\t\t\tValue:   serializedTs,\n\t\t\t},\n\t\t},\n\t}\n\n\textraUser, err := anypb.New(testUserFull)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\ttestUserFull.ExtraUser = extraUser\n\ttestUserPartial = &testproto.User{\n\t\tId:       1,\n\t\tUsername: \"username\",\n\t}\n}\n\nfunc TestStructToStruct_Proto(t *testing.T) {\n\tuserDst := &testproto.User{}\n\tmask := fieldmask_utils.MaskFromString(\n\t\t\"Id,Avatar{OriginalUrl},Tags,Images,Permissions,Friends{Images{ResizedUrl}},Name{MaleName},ExtraUser{Id,Avatar{OriginalUrl}}\")\n\terr := fieldmask_utils.StructToStruct(mask, testUserFull, userDst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, testUserFull.Id, userDst.Id)\n\tassert.Equal(t, testUserFull.Avatar.OriginalUrl, userDst.Avatar.OriginalUrl)\n\tassert.Equal(t, \"\", userDst.Avatar.ResizedUrl)\n\tassert.Equal(t, testUserFull.Tags, userDst.Tags)\n\trequire.Equal(t, len(testUserFull.Images), len(userDst.Images))\n\tfor i, srcImg := range testUserFull.Images {\n\t\tassert.Equal(t, srcImg.OriginalUrl, userDst.Images[i].OriginalUrl)\n\t\tassert.Equal(t, srcImg.ResizedUrl, userDst.Images[i].ResizedUrl)\n\t}\n\tassert.Equal(t, testUserFull.Name, userDst.Name)\n\tassert.Equal(t, testUserFull.Permissions, userDst.Permissions)\n\tassert.Equal(t, len(testUserFull.Friends), len(userDst.Friends))\n\tassert.Equal(t, len(testUserFull.Friends[0].Images), len(userDst.Friends[0].Images))\n\tassert.Equal(t, testUserFull.Friends[0].Images[0].ResizedUrl, userDst.Friends[0].Images[0].ResizedUrl)\n\tassert.Equal(t, \"\", userDst.Friends[0].Images[0].OriginalUrl)\n\t// Zero (default) values below.\n\tassert.Equal(t, testproto.Role_UNKNOWN, userDst.Role)\n\tassert.Equal(t, false, userDst.Deactivated)\n\tassert.Equal(t, map[string]string(nil), userDst.Meta)\n\n\textraUser := &testproto.User{}\n\terr = userDst.ExtraUser.UnmarshalTo(extraUser)\n\trequire.NoError(t, err)\n\tassert.Equal(t, testUserFull.Id, extraUser.Id)\n\tassert.Equal(t, testUserFull.Avatar.OriginalUrl, extraUser.Avatar.OriginalUrl)\n}\n\nfunc TestStructToStruct_ExistingAnyPreserved(t *testing.T) {\n\texistingExtraUser := &testproto.User{\n\t\tId:       42,\n\t\tUsername: \"emily\",\n\t\tRole:     testproto.Role_REGULAR,\n\t}\n\texistingExtraUserAny, err := anypb.New(existingExtraUser)\n\trequire.NoError(t, err)\n\tuserDst := &testproto.User{\n\t\tExtraUser: existingExtraUserAny,\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"ExtraUser{Id,Avatar{OriginalUrl}}\")\n\terr = fieldmask_utils.StructToStruct(mask, testUserFull, userDst)\n\trequire.NoError(t, err)\n\n\textraUser := &testproto.User{}\n\terr = userDst.ExtraUser.UnmarshalTo(extraUser)\n\trequire.NoError(t, err)\n\tassert.Equal(t, testUserFull.Id, extraUser.Id)\n\tassert.Equal(t, testUserFull.Avatar.OriginalUrl, extraUser.Avatar.OriginalUrl)\n\tassert.Equal(t, existingExtraUser.Username, extraUser.Username)\n\tassert.Equal(t, existingExtraUser.Role, extraUser.Role)\n}\n\nfunc TestStructToStruct_PartialProtoSuccess(t *testing.T) {\n\tuserDst := &testproto.User{}\n\tmask := fieldmask_utils.MaskFromString(\n\t\t\"Id,Avatar{OriginalUrl},Images,Username,Permissions,Name{MaleName}\")\n\terr := fieldmask_utils.StructToStruct(mask, testUserPartial, userDst)\n\tassert.Nil(t, err)\n\tassert.Equal(t, testUserPartial.Id, userDst.Id)\n\tassert.Equal(t, testUserPartial.Username, userDst.Username)\n\tassert.Equal(t, testUserPartial.Name, userDst.Name)\n}\n\nfunc TestStructToStruct_MaskInverse(t *testing.T) {\n\tuserSrc := &testproto.User{\n\t\tId:          1,\n\t\tUsername:    \"username\",\n\t\tRole:        testproto.Role_ADMIN,\n\t\tMeta:        map[string]string{\"foo\": \"bar\"},\n\t\tDeactivated: false,\n\t\tPermissions: []testproto.Permission{testproto.Permission_EXECUTE},\n\t\tName:        &testproto.User_FemaleName{FemaleName: \"Dana\"},\n\t\tFriends: []*testproto.User{\n\t\t\t{Id: 2, Username: \"friend1\"},\n\t\t\t{Id: 3, Username: \"friend2\"},\n\t\t},\n\t}\n\tuserDst := &testproto.User{}\n\tmask := fieldmask_utils.MaskInverse{\"Id\": nil, \"Friends\": fieldmask_utils.MaskInverse{\"Username\": nil}}\n\terr := fieldmask_utils.StructToStruct(mask, userSrc, userDst)\n\trequire.NoError(t, err)\n\t// Verify that Id is not copied.\n\tassert.Equal(t, uint32(0), userDst.Id)\n\t// Verify that Friend Usernames are not copied.\n\tassert.Equal(t, \"\", userDst.Friends[0].Username)\n\tassert.Equal(t, \"\", userDst.Friends[1].Username)\n\t// Copy missed fields manually and then compare these structs.\n\tuserDst.Id = userSrc.Id\n\tuserDst.Friends[0].Username = userSrc.Friends[0].Username\n\tuserDst.Friends[1].Username = userSrc.Friends[1].Username\n\tassert.Equal(t, userSrc, userDst)\n}\n\nfunc TestStructToStruct_NonProtoSuccess(t *testing.T) {\n\ttype Image struct {\n\t\tOriginalUrl string\n\t\tResizedUrl  string\n\t}\n\ttype User struct {\n\t\tId          uint32\n\t\tUsername    string\n\t\tDeactivated bool\n\t\tImages      []*Image\n\t}\n\n\tsrc := &User{\n\t\tId:          1,\n\t\tUsername:    \"johnny\",\n\t\tDeactivated: true,\n\t\tImages: []*Image{\n\t\t\t{\"original_url.jpg\", \"resized_url.jpg\"},\n\t\t\t{\"original_url.jpg\", \"resized_url.jpg\"},\n\t\t},\n\t}\n\tdst := &testproto.User{}\n\tmask := fieldmask_utils.MaskFromString(\"\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.NoError(t, err)\n\tassert.Equal(t, src.Id, dst.Id)\n\tassert.Equal(t, src.Username, dst.Username)\n\tassert.Equal(t, len(src.Images), len(dst.Images))\n\tassert.Equal(t, src.Images[0].OriginalUrl, dst.Images[0].OriginalUrl)\n\tassert.Equal(t, src.Images[0].ResizedUrl, dst.Images[0].ResizedUrl)\n\tassert.Equal(t, src.Images[1].OriginalUrl, dst.Images[1].OriginalUrl)\n\tassert.Equal(t, src.Images[1].ResizedUrl, dst.Images[1].ResizedUrl)\n\tassert.Equal(t, src.Deactivated, dst.Deactivated)\n}\n\nfunc TestStructToStruct_MaskInverseFromMask(t *testing.T) {\n\tuserSrc := &testproto.User{\n\t\tId:          1,\n\t\tUsername:    \"username\",\n\t\tRole:        testproto.Role_ADMIN,\n\t\tMeta:        map[string]string{\"foo\": \"bar\"},\n\t\tDeactivated: false,\n\t\tPermissions: []testproto.Permission{testproto.Permission_EXECUTE},\n\t\tName:        &testproto.User_FemaleName{FemaleName: \"Dana\"},\n\t\tFriends: []*testproto.User{\n\t\t\t{Id: 2, Username: \"friend1\"},\n\t\t\t{Id: 3, Username: \"friend2\"},\n\t\t},\n\t}\n\tuserDst := &testproto.User{}\n\t// Mask to MaskInverse\n\tmask := fieldmask_utils.MaskInverse{\"Id\": fieldmask_utils.Mask{}, \"Friends\": fieldmask_utils.Mask{\"Username\": fieldmask_utils.Mask{}}}\n\terr := fieldmask_utils.StructToStruct(mask, userSrc, userDst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &testproto.User{\n\t\tUsername:    userSrc.Username,\n\t\tRole:        userSrc.Role,\n\t\tMeta:        userSrc.Meta,\n\t\tDeactivated: userSrc.Deactivated,\n\t\tPermissions: userSrc.Permissions,\n\t\tName:        userSrc.Name,\n\t\tFriends: []*testproto.User{\n\t\t\t{Username: \"friend1\"},\n\t\t\t{Username: \"friend2\"},\n\t\t},\n\t}, userDst)\n}\n\nfunc TestStructToStruct_NonProtoFail(t *testing.T) {\n\ttype User struct {\n\t\tId           uint32\n\t\tUnknownField string\n\t\tDeactivated  bool\n\t}\n\n\tuserSrc := &User{\n\t\tId:           1,\n\t\tUnknownField: \"johnny\",\n\t\tDeactivated:  true,\n\t}\n\tuserDst := &testproto.User{}\n\tmask := fieldmask_utils.MaskFromString(\"\")\n\terr := fieldmask_utils.StructToStruct(mask, userSrc, userDst)\n\tassert.NotNil(t, err)\n}\n\nfunc TestStructToStruct_UnknownAnyInSrcNoSubfieldMask(t *testing.T) {\n\tuserWithUnknown := &testproto.User{\n\t\tDetails: []*anypb.Any{\n\t\t\t{\n\t\t\t\tTypeUrl: \"example.com/example/UnknownType\",\n\t\t\t\tValue:   []byte(\"unknown\"),\n\t\t\t},\n\t\t},\n\t}\n\temptyUser := &testproto.User{}\n\n\tmask := fieldmask_utils.MaskFromString(\"Details\")\n\terr := fieldmask_utils.StructToStruct(mask, userWithUnknown, emptyUser, fieldmask_utils.WithUnmarshalAllAny(false))\n\tassert.NoError(t, err)\n\tassert.Equal(t, userWithUnknown.Details, emptyUser.Details)\n}\n\nfunc TestStructToStruct_UnknownAnyInDstNoSubfieldMask(t *testing.T) {\n\tuserWithUnknown := &testproto.User{\n\t\tDetails: []*anypb.Any{\n\t\t\t{\n\t\t\t\tTypeUrl: \"example.com/example/UnknownType\",\n\t\t\t\tValue:   []byte(\"unknown\"),\n\t\t\t},\n\t\t},\n\t}\n\temptyUser := &testproto.User{}\n\n\tmask := fieldmask_utils.MaskFromString(\"Details\")\n\terr := fieldmask_utils.StructToStruct(mask, emptyUser, userWithUnknown, fieldmask_utils.WithUnmarshalAllAny(false))\n\tassert.NoError(t, err)\n\tassert.Equal(t, userWithUnknown.Details, emptyUser.Details)\n}\n\nfunc TestStructToStruct_UnknownAnyDefault(t *testing.T) {\n\tuserWithUnknown := &testproto.User{\n\t\tDetails: []*anypb.Any{\n\t\t\t{\n\t\t\t\tTypeUrl: \"example.com/example/UnknownType\",\n\t\t\t\tValue:   []byte(\"unknown\"),\n\t\t\t},\n\t\t},\n\t}\n\temptyUser := &testproto.User{}\n\n\tmask := fieldmask_utils.MaskFromString(\"Details\")\n\terr := fieldmask_utils.StructToStruct(mask, userWithUnknown, emptyUser)\n\tassert.Contains(t, err.Error(), \"not found\")\n}\n\nfunc TestStructToStruct_UnknownAnySubfieldMask(t *testing.T) {\n\tuserWithUnknown := &testproto.User{\n\t\tDetails: []*anypb.Any{\n\t\t\t{\n\t\t\t\tTypeUrl: \"example.com/example/UnknownType\",\n\t\t\t\tValue:   []byte(\"unknown\"),\n\t\t\t},\n\t\t},\n\t}\n\temptyUser := &testproto.User{}\n\n\tmask := fieldmask_utils.MaskFromString(\"Details{Id}\")\n\terr := fieldmask_utils.StructToStruct(mask, userWithUnknown, emptyUser, fieldmask_utils.WithUnmarshalAllAny(false))\n\tassert.Contains(t, err.Error(), \"not found\")\n}\nfunc TestStructToMap_Success(t *testing.T) {\n\tuserDst := make(map[string]interface{})\n\tmask := fieldmask_utils.MaskFromString(\n\t\t\"Id,Avatar{OriginalUrl},Tags,Images,Permissions,Friends{Images{ResizedUrl}}\")\n\terr := fieldmask_utils.StructToMap(mask, testUserFull, userDst)\n\trequire.Nil(t, err)\n\texpected := map[string]interface{}{\n\t\t\"Id\": testUserFull.Id,\n\t\t\"Avatar\": map[string]interface{}{\n\t\t\t\"OriginalUrl\": testUserFull.Avatar.OriginalUrl,\n\t\t},\n\t\t\"Tags\": testUserFull.Tags,\n\t\t\"Images\": []map[string]interface{}{\n\t\t\t{\"OriginalUrl\": testUserFull.Images[0].OriginalUrl, \"ResizedUrl\": testUserFull.Images[0].ResizedUrl},\n\t\t\t{\"OriginalUrl\": testUserFull.Images[1].OriginalUrl, \"ResizedUrl\": testUserFull.Images[1].ResizedUrl},\n\t\t},\n\t\t\"Permissions\": testUserFull.Permissions,\n\t\t\"Friends\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Images\": []map[string]interface{}{\n\t\t\t\t\t{\"ResizedUrl\": testUserFull.Friends[0].Images[0].ResizedUrl},\n\t\t\t\t\t{\"ResizedUrl\": testUserFull.Friends[0].Images[1].ResizedUrl},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tassert.Equal(t, expected, userDst)\n}\n\nfunc TestStructToMap_PartialProtoSuccess(t *testing.T) {\n\tuserDst := make(map[string]interface{})\n\tmask := fieldmask_utils.MaskFromString(\n\t\t\"Id,Avatar{OriginalUrl},Images,Username,Permissions,Name{MaleName}\")\n\terr := fieldmask_utils.StructToMap(mask, testUserPartial, userDst)\n\trequire.Nil(t, err)\n\texpected := map[string]interface{}{\n\t\t\"Id\":          testUserPartial.Id,\n\t\t\"Avatar\":      nil,\n\t\t\"Images\":      []map[string]interface{}{},\n\t\t\"Username\":    testUserPartial.Username,\n\t\t\"Permissions\": []testproto.Permission(nil),\n\t\t\"Name\":        nil,\n\t}\n\tassert.Equal(t, expected, userDst)\n}\n"
  },
  {
    "path": "copy_test.go",
    "content": "package fieldmask_utils_test\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\tfieldmask_utils \"github.com/mennanov/fieldmask-utils\"\n)\n\nfunc TestStructToStruct_SimpleStruct(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\tsrc := &A{\n\t\tField1: \"src field1\",\n\t\tField2: 1,\n\t}\n\tdst := new(A)\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: \"src field1\",\n\t\tField2: 0,\n\t}, dst)\n}\n\nfunc TestStructToStruct_PtrToInt(t *testing.T) {\n\ttype A struct {\n\t\tField2 *int\n\t}\n\tn := 42\n\tsrc := &A{\n\t\tField2: &n,\n\t}\n\tdst := new(A)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField2: src.Field2,\n\t}, dst)\n}\n\nfunc TestStructToStruct_StructToPointer(t *testing.T) {\n\tv15 := 15\n\tv42 := 42\n\n\ttype N struct {\n\t\tField1 int\n\t}\n\ttype S struct {\n\t\tField1 N\n\t\tField2 int\n\t}\n\tsrc := &S{\n\t\tField1: N{\n\t\t\tField1: v15,\n\t\t},\n\t\tField2: v42,\n\t}\n\ttype SN struct {\n\t\tField1 *int\n\t}\n\ttype D struct {\n\t\tField1 *SN\n\t\tField2 *int\n\t}\n\tdst := new(D)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &D{\n\t\tField1: &SN{\n\t\t\tField1: &v15,\n\t\t},\n\t\tField2: &v42,\n\t}, dst)\n}\n\nfunc TestStructToStruct_IntToPointer(t *testing.T) {\n\tv := 42\n\n\ttype S struct {\n\t\tField2 int\n\t}\n\tsrc := &S{\n\t\tField2: v,\n\t}\n\ttype D struct {\n\t\tField2 *int\n\t}\n\tdst := new(D)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &D{\n\t\tField2: &v,\n\t}, dst)\n}\n\nfunc TestStructToStruct_PointerToInt(t *testing.T) {\n\tv := 42\n\n\ttype S struct {\n\t\tField2 *int\n\t}\n\tsrc := &S{\n\t\tField2: &v,\n\t}\n\ttype D struct {\n\t\tField2 int\n\t}\n\tdst := new(D)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &D{\n\t\tField2: 42,\n\t}, dst)\n}\n\nfunc TestStructToStruct_Incompatible(t *testing.T) {\n\ttype S struct {\n\t\tField2 int\n\t}\n\tsrc := &S{\n\t\tField2: 42,\n\t}\n\ttype D struct {\n\t\tField2 string\n\t}\n\tdst := new(D)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.EqualError(t, err, \"src kind int differs from dst kind string\")\n}\n\nfunc TestStructToStruct_PtrToStruct_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tField2 int\n\t\tA      *A\n\t}\n\ttype C struct {\n\t\tField1 string\n\t\tB      *B\n\t}\n\tsrc := &C{\n\t\tField1: \"C field1\",\n\t\tB: &B{\n\t\t\tField1: \"StringerB field1\",\n\t\t\tField2: 1,\n\t\t\tA: &A{\n\t\t\t\tField1: \"StringerA field1\",\n\t\t\t\tField2: 5,\n\t\t\t},\n\t\t},\n\t}\n\tdst := new(C)\n\n\tmask := fieldmask_utils.MaskFromString(\"B{Field1,A{Field2}}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tField1: \"\",\n\t\tB: &B{\n\t\t\tField1: src.B.Field1,\n\t\t\tField2: 0,\n\t\t\tA: &A{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.B.A.Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_PtrToStruct_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tField2 int\n\t\tA      *A\n\t}\n\ttype C struct {\n\t\tField1 string\n\t\tB      *B\n\t}\n\tsrc := &C{\n\t\tField1: \"src C field1\",\n\t\tB: &B{\n\t\t\tField1: \"StringerB field1\",\n\t\t\tField2: 1,\n\t\t\tA: &A{\n\t\t\t\tField1: \"StringerA field1\",\n\t\t\t\tField2: 5,\n\t\t\t},\n\t\t},\n\t}\n\tdst := &C{\n\t\tField1: \"dst C field1\",\n\t\tB: &B{\n\t\t\tField1: \"dst StringerB field1\",\n\t\t\tField2: 2,\n\t\t\tA: &A{\n\t\t\t\tField1: \"dst StringerA field1\",\n\t\t\t\tField2: 10,\n\t\t\t},\n\t\t},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"B{Field1,A{Field2}}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tField1: \"dst C field1\",\n\t\tB: &B{\n\t\t\tField1: src.B.Field1,\n\t\t\tField2: 2,\n\t\t\tA: &A{\n\t\t\t\tField1: \"dst StringerA field1\",\n\t\t\t\tField2: src.B.A.Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_NestedStruct_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tField2 int\n\t\tA      A\n\t}\n\ttype C struct {\n\t\tField1 string\n\t\tB      B\n\t}\n\tsrc := &C{\n\t\tField1: \"C field1\",\n\t\tB: B{\n\t\t\tField1: \"StringerB field1\",\n\t\t\tField2: 1,\n\t\t\tA: A{\n\t\t\t\tField1: \"StringerA field1\",\n\t\t\t\tField2: 5,\n\t\t\t},\n\t\t},\n\t}\n\tdst := new(C)\n\n\tmask := fieldmask_utils.MaskFromString(\"B{Field1,A{Field2}}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tField1: \"\",\n\t\tB: B{\n\t\t\tField1: src.B.Field1,\n\t\t\tField2: 0,\n\t\t\tA: A{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.B.A.Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_NestedStruct_EmptyDst_OptionDst(t *testing.T) {\n\topts := fieldmask_utils.WithTag(\"db\")\n\ttype ASrc struct {\n\t\tField1 string\n\t\tField2 int `db:\"SomeField\"`\n\t}\n\ttype BSrc struct {\n\t\tField1 string `struct:\"a_name\"`\n\t\tA      ASrc   `db:\"AnotherName\"`\n\t}\n\tsrc := &BSrc{\n\t\tField1: \"B Field1\",\n\t\tA: ASrc{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\n\ttype ADst struct {\n\t\tField1    string\n\t\tSomeField int\n\t}\n\ttype BDst struct {\n\t\tField1      string\n\t\tAnotherName ADst\n\t}\n\tdst := &BDst{}\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, opts)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &BDst{\n\t\tField1: src.Field1,\n\t\tAnotherName: ADst{\n\t\t\tSomeField: src.A.Field2,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_NestedStruct_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tField2 int\n\t\tA      A\n\t}\n\ttype C struct {\n\t\tField1 string\n\t\tB      B\n\t}\n\tsrc := &C{\n\t\tField1: \"src C field1\",\n\t\tB: B{\n\t\t\tField1: \"src StringerB field1\",\n\t\t\tField2: 1,\n\t\t\tA: A{\n\t\t\t\tField1: \"src StringerA field1\",\n\t\t\t\tField2: 5,\n\t\t\t},\n\t\t},\n\t}\n\tdst := &C{\n\t\tField1: \"dst C field1\",\n\t\tB: B{\n\t\t\tField1: \"dst StringerB field1\",\n\t\t\tField2: 2,\n\t\t\tA: A{\n\t\t\t\tField1: \"dst StringerA field1\",\n\t\t\t\tField2: 10,\n\t\t\t},\n\t\t},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"B{Field1,A{Field2}}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tField1: \"dst C field1\",\n\t\tB: B{\n\t\t\tField1: src.B.Field1,\n\t\t\tField2: 2,\n\t\t\tA: A{\n\t\t\t\tField1: \"dst StringerA field1\",\n\t\t\t\tField2: src.B.A.Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_SliceOfStructs_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      []A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 0\",\n\t\t\t\tField2: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 1\",\n\t\t\t\tField2: 2,\n\t\t\t},\n\t\t},\n\t}\n\tdst := new(B)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{\n\t\tField1: src.Field1,\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[0].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[1].Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_SliceOfStructs_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      []A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 0\",\n\t\t\t\tField2: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 1\",\n\t\t\t\tField2: 2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 2\",\n\t\t\t\tField2: 3,\n\t\t\t},\n\t\t},\n\t}\n\tdst := &B{\n\t\tField1: \"dst StringerB field1\",\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 0\",\n\t\t\t\tField2: 10,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 1\",\n\t\t\t\tField2: 20,\n\t\t\t},\n\t\t},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{\n\t\tField1: src.Field1,\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 0\",\n\t\t\t\tField2: src.A[0].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 1\",\n\t\t\t\tField2: src.A[1].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[2].Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_EntireSlice_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      []A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 0\",\n\t\t\t\tField2: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 1\",\n\t\t\t\tField2: 2,\n\t\t\t},\n\t\t},\n\t}\n\tdst := &B{\n\t\tField1: \"dst StringerB field1\",\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 0\",\n\t\t\t\tField2: 10,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 1\",\n\t\t\t\tField2: 20,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 2\",\n\t\t\t\tField2: 30,\n\t\t\t},\n\t\t},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{\n\t\tField1: src.Field1,\n\t\tA:      src.A,\n\t}, dst)\n}\n\nfunc TestStructToStruct_NilSrcSlice_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      []A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA:      nil,\n\t}\n\tdst := &B{\n\t\tField1: \"dst StringerB field1\",\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 0\",\n\t\t\t\tField2: 10,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 1\",\n\t\t\t\tField2: 20,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"dst StringerA field1 2\",\n\t\t\t\tField2: 30,\n\t\t\t},\n\t\t},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{\n\t\tField1: src.Field1,\n\t\tA:      src.A,\n\t}, dst)\n}\n\nfunc TestStructToStruct_SliceOfPtrsToStruct_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      []*A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA: []*A{\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 0\",\n\t\t\t\tField2: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 1\",\n\t\t\t\tField2: 2,\n\t\t\t},\n\t\t},\n\t}\n\tdst := new(B)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{\n\t\tField1: src.Field1,\n\t\tA: []*A{\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[0].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[1].Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_ArrayOfStructs_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      [2]A\n\t}\n\ttype C struct {\n\t\tField1 string\n\t\tA      [3]A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA: [2]A{\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 0\",\n\t\t\t\tField2: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 1\",\n\t\t\t\tField2: 2,\n\t\t\t},\n\t\t},\n\t}\n\tdst := new(C)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tField1: src.Field1,\n\t\tA: [3]A{\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[0].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: src.A[1].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"\",\n\t\t\t\tField2: 0,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_Array_DstLenLessThanSrc(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      [2]A\n\t}\n\ttype C struct {\n\t\tField1 string\n\t\tA      [1]A\n\t}\n\tsrc := &B{\n\t\tField1: \"src StringerB field1\",\n\t\tA: [2]A{\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 0\",\n\t\t\t\tField2: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"StringerA field1 1\",\n\t\t\t\tField2: 2,\n\t\t\t},\n\t\t},\n\t}\n\tdst := new(C)\n\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.Error(t, err)\n}\n\nfunc TestStructToStruct_DifferentStructTypes(t *testing.T) {\n\ttype A struct {\n\t\tField string\n\t}\n\n\ttype B struct {\n\t\tField string\n\t}\n\n\tsrc := &A{\"value\"}\n\tdst := new(B)\n\tmask := fieldmask_utils.MaskFromString(\"Field\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{src.Field}, dst)\n}\n\nfunc TestStructToStruct_DifferentStructTypesNested(t *testing.T) {\n\ttype A struct {\n\t\tField string\n\t}\n\n\ttype AA struct {\n\t\tField string\n\t}\n\n\ttype B struct {\n\t\tA A\n\t}\n\n\ttype C struct {\n\t\tA AA\n\t}\n\n\tsrc := &B{\n\t\tA: A{\n\t\t\tField: \"value\",\n\t\t},\n\t}\n\tdst := new(C)\n\tmask := fieldmask_utils.MaskFromString(\"A\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tA: AA{\n\t\t\tField: src.A.Field,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_DifferentStructTypesPtrNested(t *testing.T) {\n\ttype A struct {\n\t\tField string\n\t}\n\n\ttype AA struct {\n\t\tField string\n\t}\n\n\ttype B struct {\n\t\tA *A\n\t}\n\n\ttype C struct {\n\t\tA *AA\n\t}\n\n\tsrc := &B{\n\t\tA: &A{\n\t\t\tField: \"value\",\n\t\t},\n\t}\n\tdst := new(C)\n\tmask := fieldmask_utils.MaskFromString(\"A\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tA: &AA{\n\t\t\tField: src.A.Field,\n\t\t},\n\t}, dst)\n}\n\ntype StringerA struct {\n\tField string\n}\n\nfunc (a *StringerA) String() string {\n\treturn a.Field\n}\n\ntype StringerB struct {\n\tField string\n}\n\nfunc (b *StringerB) String() string {\n\treturn b.Field\n}\n\nfunc TestStructToStruct_Interface_EmptyDst(t *testing.T) {\n\ttype C struct {\n\t\tS fmt.Stringer\n\t}\n\n\tsrc := &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerA\",\n\t\t},\n\t}\n\tdst := new(C)\n\tmask := fieldmask_utils.MaskFromString(\"S\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerA\",\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_SameInterfaces_NonEmptyDst(t *testing.T) {\n\ttype C struct {\n\t\tS fmt.Stringer\n\t}\n\n\tsrc := &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerA\",\n\t\t},\n\t}\n\tdst := &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerB\",\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"S\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, src.S.String(), dst.S.String())\n\tassert.Equal(t, &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerA\",\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_DifferentCompatibleInterfaces_NonEmptyDst(t *testing.T) {\n\ttype C struct {\n\t\tS fmt.Stringer\n\t}\n\n\tsrc := &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerA\",\n\t\t},\n\t}\n\tdst := &C{\n\t\tS: &StringerB{\n\t\t\tField: \"StringerB\",\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"S\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, src.S.String(), dst.S.String())\n}\n\ntype Logger interface {\n\tLog() string\n}\n\ntype LoggerImpl struct {\n\tField string\n}\n\nfunc (d *LoggerImpl) Log() string {\n\treturn d.Field\n}\n\nfunc TestStructToStruct_DifferentIncompatibleInterfaces(t *testing.T) {\n\ttype C struct {\n\t\tS fmt.Stringer\n\t}\n\n\ttype E struct {\n\t\tS Logger\n\t}\n\n\tsrc := &C{\n\t\tS: &StringerA{\n\t\t\tField: \"StringerA\",\n\t\t},\n\t}\n\tdst := &E{\n\t\tS: &LoggerImpl{\n\t\t\tField: \"Logger\",\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"S\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, src.S.String(), dst.S.Log())\n}\n\nfunc TestStructToStruct_EmptyMask(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\tsrc := &A{\n\t\tField1: \"A Field1\",\n\t\tField2: 1,\n\t}\n\tdst := new(A)\n\tmask := fieldmask_utils.MaskFromString(\"\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, src, dst)\n}\n\ntype StringerImpl struct {\n\tName string\n}\n\nfunc (*StringerImpl) someMethod() {}\nfunc (f *StringerImpl) String() string {\n\treturn f.Name\n}\n\ntype StringerNonPtrImpl struct {\n\tName string\n}\n\nfunc (s StringerNonPtrImpl) String() string {\n\treturn s.Name\n}\n\nfunc TestStructToStruct_SameInterfacesPtr_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tStringer fmt.Stringer\n\t}\n\n\ttype B struct {\n\t\tStringer fmt.Stringer\n\t}\n\n\tsrc := &A{\n\t\tStringer: &StringerImpl{Name: \"Jessica\"},\n\t}\n\n\tdst := new(B)\n\n\tmask := fieldmask_utils.MaskFromString(\"Stringer\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.NoError(t, err)\n\tassert.Equal(t, src.Stringer.String(), dst.Stringer.String())\n}\n\nfunc TestStructToStruct_SameInterfacesPtr_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tStringer fmt.Stringer\n\t}\n\n\ttype B struct {\n\t\tStringer fmt.Stringer\n\t}\n\n\tsrc := &A{\n\t\tStringer: &StringerImpl{\n\t\t\tName: \"Jessica\",\n\t\t},\n\t}\n\tdst := &B{\n\t\tStringer: &StringerImpl{\n\t\t\tName: \"Dana\",\n\t\t},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"Stringer\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.NoError(t, err)\n\tassert.Equal(t, dst.Stringer.String(), src.Stringer.String())\n}\n\nfunc TestStructToStruct_SameInterfacesNonPtr_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tStringer fmt.Stringer\n\t}\n\tsrc := &A{\n\t\tStringer: StringerNonPtrImpl{Name: \"Jessica\"},\n\t}\n\n\tdst := new(A)\n\n\tmask := fieldmask_utils.MaskFromString(\"Stringer\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.Error(t, err)\n}\n\nfunc TestStructToStruct_SameInterfacesNonPtr_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tStringer fmt.Stringer\n\t}\n\tsrc := &A{\n\t\tStringer: StringerNonPtrImpl{Name: \"Jessica\"},\n\t}\n\n\tdst := &A{\n\t\tStringer: StringerNonPtrImpl{Name: \"Adam\"},\n\t}\n\n\tmask := fieldmask_utils.MaskFromString(\"Stringer\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.Error(t, err)\n}\n\nfunc TestStructToStruct_NonPtrDst(t *testing.T) {\n\ttype A struct {\n\t\tField int\n\t}\n\tsrc := &A{Field: 1}\n\tdst := A{}\n\tmask := fieldmask_utils.MaskFromString(\"\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.Error(t, err)\n}\n\nfunc TestStructToStruct_DifferentDstKind(t *testing.T) {\n\ttype A struct {\n\t\tField int\n\t}\n\tsrc := &A{Field: 1}\n\tdst := &map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.Error(t, err)\n}\n\nfunc TestStructToStruct_UnexportedFieldsPtr(t *testing.T) {\n\ttype A struct {\n\t\tfoo string\n\t\tBar string\n\t}\n\n\ttype B struct {\n\t\tA *A\n\t\tB string\n\t}\n\n\tsrc := &B{\n\t\tA: &A{\n\t\t\tfoo: \"foo\",\n\t\t\tBar: \"Bar\",\n\t\t},\n\t\tB: \"B\",\n\t}\n\tdst := &B{}\n\n\tmask := fieldmask_utils.MaskFromString(\"A,B\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.NoError(t, err)\n\tassert.Equal(t, src, dst)\n}\n\nfunc TestStructToStruct_UnexportedFields(t *testing.T) {\n\ttype A struct {\n\t\tfoo string\n\t\tBar string\n\t}\n\n\ttype B struct {\n\t\tA A\n\t\tB string\n\t}\n\n\tsrc := &B{\n\t\tA: A{\n\t\t\tfoo: \"foo\",\n\t\t\tBar: \"Bar\",\n\t\t},\n\t\tB: \"B\",\n\t}\n\tdst := &B{}\n\n\tmask := fieldmask_utils.MaskFromString(\"A,B\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.NoError(t, err)\n\tassert.Equal(t, src, dst)\n}\n\nfunc TestStructToStruct_MaskWithInverseMask(t *testing.T) {\n\ttype A struct {\n\t\tFoo string\n\t\tBar string\n\t}\n\n\ttype B struct {\n\t\tA A\n\t\tB string\n\t\tC string\n\t}\n\tsrc := &B{\n\t\tA: A{\n\t\t\tFoo: \"foo\",\n\t\t\tBar: \"Bar\",\n\t\t},\n\t\tB: \"B\",\n\t\tC: \"C\",\n\t}\n\tfor _, mask := range []fieldmask_utils.FieldFilter{\n\t\tfieldmask_utils.Mask{\"B\": nil, \"A\": &fieldmask_utils.MaskInverse{\"Bar\": nil}},\n\t\tfieldmask_utils.Mask{\"B\": fieldmask_utils.Mask{}, \"A\": &fieldmask_utils.MaskInverse{\"Bar\": fieldmask_utils.Mask{}}},\n\t} {\n\t\tdst := &B{}\n\t\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &B{\n\t\t\tA: A{\n\t\t\t\tFoo: src.A.Foo,\n\t\t\t},\n\t\t\tB: \"B\",\n\t\t}, dst)\n\t}\n\n}\n\nfunc TestStructToStruct_InverseMaskWithMask(t *testing.T) {\n\ttype A struct {\n\t\tFoo string\n\t\tBar string\n\t}\n\n\ttype B struct {\n\t\tA A\n\t\tB string\n\t\tC string\n\t}\n\tsrc := &B{\n\t\tA: A{\n\t\t\tFoo: \"foo\",\n\t\t\tBar: \"Bar\",\n\t\t},\n\t\tB: \"B\",\n\t\tC: \"C\",\n\t}\n\tfor _, mask := range []fieldmask_utils.FieldFilter{\n\t\tfieldmask_utils.MaskInverse{\"B\": fieldmask_utils.Mask{}, \"A\": &fieldmask_utils.Mask{\"Bar\": fieldmask_utils.Mask{}}},\n\t\tfieldmask_utils.MaskInverse{\"B\": nil, \"A\": &fieldmask_utils.Mask{\"Bar\": nil}},\n\t} {\n\t\tdst := &B{}\n\t\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, &B{\n\t\t\tA: A{\n\t\t\t\tBar: src.A.Bar,\n\t\t\t},\n\t\t\tC: \"C\",\n\t\t}, dst)\n\t}\n\n}\n\nfunc TestStructToMap_NestedStruct_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      A\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tdst := make(map[string]interface{})\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t\t\"A\": map[string]interface{}{\n\t\t\t\"Field2\": src.A.Field2,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_NestedStruct_EmptyDst_OptionDst(t *testing.T) {\n\topts := fieldmask_utils.WithTag(\"db\")\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int `db:\"some_field\"`\n\t}\n\ttype B struct {\n\t\tField1 string `struct:\"a_name\"`\n\t\tA      A      `db:\"another_name\"`\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tdst := make(map[string]interface{})\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, opts)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t\t\"another_name\": map[string]interface{}{\n\t\t\t\"some_field\": src.A.Field2,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_NestedStruct_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      A\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tdst := map[string]interface{}{\n\t\t\"A\": map[string]interface{}{\n\t\t\t\"Field1\": \"existing value\",\n\t\t\t\"Field2\": 10,\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t\t\"A\": map[string]interface{}{\n\t\t\t\"Field1\": \"existing value\",\n\t\t\t\"Field2\": src.A.Field2,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_PtrToStruct_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      *A\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: &A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tdst := make(map[string]interface{})\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t\t\"A\": map[string]interface{}{\n\t\t\t\"Field2\": src.A.Field2,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_PtrToStruct_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int\n\t}\n\ttype B struct {\n\t\tField1 string\n\t\tA      *A\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: &A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tdst := map[string]interface{}{\n\t\t\"A\": map[string]interface{}{\n\t\t\t\"Field1\": \"existing value\",\n\t\t\t\"Field2\": 10,\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t\t\"A\": map[string]interface{}{\n\t\t\t\"Field1\": \"existing value\",\n\t\t\t\"Field2\": src.A.Field2,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_ArrayOfStructs_EmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 string\n\t}\n\ttype B struct {\n\t\tA [1]A\n\t}\n\tsrc := &B{\n\t\tA: [1]A{\n\t\t\t{\n\t\t\t\tField1: \"src field1\",\n\t\t\t\tField2: \"src field2\",\n\t\t\t},\n\t\t},\n\t}\n\tdst := make(map[string]interface{})\n\tmask := fieldmask_utils.MaskFromString(\"A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field2\": src.A[0].Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_SliceOfStructs_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 string\n\t}\n\ttype B struct {\n\t\tA []A\n\t}\n\tsrc := &B{\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"src field1\",\n\t\t\t\tField2: \"src field2\",\n\t\t\t},\n\t\t},\n\t}\n\tdst := map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst field1\",\n\t\t\t},\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst field1\",\n\t\t\t\t\"Field2\": src.A[0].Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_EntireSlicePrimitive_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t}\n\tsrc := &A{\n\t\tField1: []int{1, 2, 4, 8},\n\t}\n\n\tdst := map[string]interface{}{\n\t\t\"Field1\": []int{16, 32, 64},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t}, dst)\n}\n\nfunc TestStructToMap_EntireSlice_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 string\n\t}\n\ttype B struct {\n\t\tA []A\n\t}\n\tsrc := &B{\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"src ele1 field1\",\n\t\t\t\tField2: \"src ele1 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"src ele2 field1\",\n\t\t\t\tField2: \"src ele2 field2\",\n\t\t\t},\n\t\t},\n\t}\n\tdst := map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele1 field1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field2\": \"dst ele2 field 2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele3 field 3\",\n\t\t\t},\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"A\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": src.A[0].Field1,\n\t\t\t\t\"Field2\": src.A[0].Field2,\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field1\": src.A[1].Field1,\n\t\t\t\t\"Field2\": src.A[1].Field2,\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_NilSrcSlice_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 string\n\t}\n\ttype B struct {\n\t\tFieldA []A\n\t}\n\tsrc := &B{FieldA: nil}\n\tdst := map[string]interface{}{\n\t\t\"FieldA\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele1 field1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field2\": \"dst ele2 field 2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele3 field 3\",\n\t\t\t},\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"FieldA\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"FieldA\": []map[string]interface{}{},\n\t}, dst)\n}\n\nfunc TestStructToMap_EntireSlice_DstSliceLenIsLessThanSource(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 string\n\t}\n\ttype B struct {\n\t\tA []A\n\t}\n\tsrc := &B{\n\t\tA: []A{\n\t\t\t{\n\t\t\t\tField1: \"src ele1 field1\",\n\t\t\t\tField2: \"src ele1 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"src ele2 field1\",\n\t\t\t\tField2: \"src ele2 field2\",\n\t\t\t},\n\t\t},\n\t}\n\tdst := map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele1 field1\",\n\t\t\t},\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"A\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"src ele1 field1\",\n\t\t\t\t\"Field2\": \"src ele1 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field1\": \"src ele2 field1\",\n\t\t\t\t\"Field2\": \"src ele2 field2\",\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_Array_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 string\n\t}\n\ttype B struct {\n\t\tA [3]A\n\t}\n\tsrc := &B{\n\t\tA: [3]A{\n\t\t\t{\n\t\t\t\tField1: \"src ele1 field1\",\n\t\t\t\tField2: \"src ele1 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"src ele2 field1\",\n\t\t\t\tField2: \"src ele2 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tField1: \"src ele3 field1\",\n\t\t\t\tField2: \"src ele3 field2\",\n\t\t\t},\n\t\t},\n\t}\n\tdst := map[string]interface{}{\n\t\t\"A\": [2]map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele1 field1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele2 field1\",\n\t\t\t},\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"A{Field2}\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"A\": []map[string]interface{}{\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele1 field1\",\n\t\t\t\t\"Field2\": \"src ele1 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field1\": \"dst ele2 field1\",\n\t\t\t\t\"Field2\": \"src ele2 field2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"Field2\": \"src ele3 field2\",\n\t\t\t},\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToMap_ArrayPrimitive_NonEmptyDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 [5]int\n\t}\n\tsrc := &A{\n\t\tField1: [5]int{1, 2, 4, 8, 10},\n\t}\n\n\tdst := map[string]interface{}{\n\t\t\"Field1\": [4]int{16, 32, 64, 0},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": [5]int{1, 2, 4, 8, 10},\n\t}, dst)\n}\n\nfunc TestStructToMap_EmptySliceSrc_NonEmptyArrayDst(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t}\n\tsrc := &A{\n\t\tField1: []int{},\n\t}\n\n\tdst := map[string]interface{}{\n\t\t\"Field1\": [4]int{16, 32, 64, 0},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t}, dst)\n}\n\nfunc TestStructToStruct_CopyStructSlice_WithMaxCopyListSize(t *testing.T) {\n\ttype AA struct {\n\t\tField int\n\t}\n\ttype A struct {\n\t\tField1 []AA\n\t}\n\n\tsrc := &A{\n\t\tField1: []AA{{1}, {2}, {3}},\n\t}\n\tdst := &A{}\n\n\tconst copySize int = 2\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: src.Field1[:copySize],\n\t}, dst)\n}\n\nfunc TestStructToStruct_CopyIntSlice_WithMaxCopyListSize(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t}\n\n\tsrc := &A{\n\t\tField1: []int{1, 2, 3},\n\t}\n\n\tconst copySize int = 2\n\tdst := &A{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: src.Field1[:copySize],\n\t}, dst)\n}\n\nfunc TestStructToStruct_CopyIntArray_WithMaxCopyListSize(t *testing.T) {\n\tconst arraySize int = 3\n\ttype A struct {\n\t\tField1 [arraySize]int\n\t}\n\tsrc := &A{\n\t\tField1: [arraySize]int{1, 2, 3},\n\t}\n\tconst copySize int = arraySize - 1\n\tdst := &A{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: [3]int{1, 2},\n\t}, dst)\n}\n\nfunc TestStructToStruct_CopyStructArray_WithMaxCopyListSize(t *testing.T) {\n\tconst arraySize int = 3\n\ttype AA struct {\n\t\tField int\n\t}\n\ttype A struct {\n\t\tField1 [3]AA\n\t}\n\n\tsrc := &A{\n\t\tField1: [3]AA{{1}, {2}, {3}},\n\t}\n\tdst := &A{}\n\n\tconst copySize int = arraySize - 1\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: [3]AA{{1}, {2}},\n\t}, dst)\n}\n\nfunc TestStructToMap_CopyStructSlice_WithMaxCopyListSize(t *testing.T) {\n\ttype AA struct {\n\t\tField int\n\t}\n\ttype A struct {\n\t\tField1 []AA\n\t}\n\n\tsrc := &A{\n\t\tField1: []AA{{1}, {2}, {3}},\n\t}\n\tdst := map[string]interface{}{}\n\n\tconst copySize int = 2\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": []map[string]interface{}{{\"Field\": 1}, {\"Field\": 2}},\n\t}, dst)\n}\n\nfunc TestStructToMap_CopyIntSlice_WithMaxCopyListSize(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t}\n\n\tsrc := &A{\n\t\tField1: []int{1, 2, 3},\n\t}\n\tdst := map[string]interface{}{}\n\n\tconst copySize int = 2\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": []int{1, 2},\n\t}, dst)\n}\n\nfunc TestStructToMap_CopyStructArray_WithMaxCopyListSize(t *testing.T) {\n\tconst arraySize int = 3\n\ttype AA struct {\n\t\tField int\n\t}\n\ttype A struct {\n\t\tField1 [3]AA\n\t}\n\n\tsrc := &A{\n\t\tField1: [3]AA{{1}, {2}, {3}},\n\t}\n\tdst := map[string]interface{}{}\n\n\tconst copySize int = arraySize - 1\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": []map[string]interface{}{{\"Field\": 1}, {\"Field\": 2}},\n\t}, dst)\n}\n\nfunc TestStructToMap_CopyIntArray_WithMaxCopyListSize(t *testing.T) {\n\tconst arraySize int = 3\n\ttype A struct {\n\t\tField1 [arraySize]int\n\t}\n\tsrc := &A{\n\t\tField1: [arraySize]int{1, 2, 3},\n\t}\n\tconst copySize int = arraySize - 1\n\tdst := map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\treturn copySize\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1[:copySize],\n\t}, dst)\n}\n\nfunc TestStructToMap_CopyStructWithPrivateFields_WithMapVisitor(t *testing.T) {\n\ttype A struct {\n\t\tTime  time.Time\n\t\tOther int\n\t}\n\tunixTime := time.Unix(10, 10)\n\tsrc := &A{Time: unixTime}\n\tdst := map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"Time\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithMapVisitor(\n\t\tfunc(_ fieldmask_utils.FieldFilter, _, dst reflect.Value,\n\t\t\tsrcFieldName, dstFieldName string, srcFieldValue reflect.Value) fieldmask_utils.MapVisitorResult {\n\t\t\tif srcFieldName == \"Time\" {\n\t\t\t\treturn fieldmask_utils.MapVisitorResult{\n\t\t\t\t\tSkipToNext: true,\n\t\t\t\t\tUpdatedDst: &srcFieldValue,\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fieldmask_utils.MapVisitorResult{}\n\t\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Time\": unixTime,\n\t}, dst)\n}\n\nfunc TestStructToMap_MapVisitorVisitsOnlyFilteredFields(t *testing.T) {\n\ttype A struct {\n\t\tField1 int\n\t\tField2 string\n\t\tField3 int\n\t}\n\tsrc := &A{Field1: 42, Field2: \"hello\", Field3: 44}\n\tdst := map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1, Field2\")\n\tvar visitedFields []string\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithMapVisitor(\n\t\tfunc(_ fieldmask_utils.FieldFilter, _, _ reflect.Value,\n\t\t\tsrcFieldName, _ string, _ reflect.Value) fieldmask_utils.MapVisitorResult {\n\t\t\tvisitedFields = append(visitedFields, srcFieldName)\n\t\t\treturn fieldmask_utils.MapVisitorResult{}\n\t\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, visitedFields, []string{\"Field1\", \"Field2\"})\n}\n\nfunc TestStructToMap_WithMapVisitor_SkipsToNextField(t *testing.T) {\n\ttype A struct {\n\t\tField1 int\n\t\tField2 string\n\t\tField3 int\n\t}\n\tsrc := &A{Field1: 42, Field2: \"hello\", Field3: 44}\n\tdst := map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1, Field2\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithMapVisitor(\n\t\tfunc(_ fieldmask_utils.FieldFilter, _, _ reflect.Value,\n\t\t\tsrcFieldName, dstFieldName string, _ reflect.Value) fieldmask_utils.MapVisitorResult {\n\t\t\tif srcFieldName == \"Field1\" {\n\t\t\t\tupdatedDst := reflect.ValueOf(33)\n\t\t\t\treturn fieldmask_utils.MapVisitorResult{\n\t\t\t\t\tSkipToNext: true,\n\t\t\t\t\tUpdatedDst: &updatedDst,\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fieldmask_utils.MapVisitorResult{}\n\t\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\"Field1\": 33, \"Field2\": \"hello\"}, dst)\n}\n\nfunc TestStructToStruct_CopySlice_WithDiffentItemKind(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t\tField2 []string\n\t}\n\tsrc := &A{\n\t\tField1: []int{1, 2, 3},\n\t\tField2: []string{\"1\", \"2\", \"3\"},\n\t}\n\tdst := &A{}\n\tconst copySize int = 1\n\tmask := fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\tif itemKind := src.Type().Elem().Kind(); itemKind == reflect.Int {\n\t\t\treturn copySize\n\t\t} else {\n\t\t\treturn src.Len()\n\t\t}\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: []int{1},\n\t\tField2: []string{\"1\", \"2\", \"3\"},\n\t}, dst)\n}\n\nfunc TestStructToMap_CopySlice_WithDiffentItemKind(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t\tField2 []string\n\t}\n\tsrc := &A{\n\t\tField1: []int{1, 2, 3},\n\t\tField2: []string{\"1\", \"2\", \"3\"},\n\t}\n\tdst := map[string]interface{}{}\n\tconst copySize int = 1\n\tmask := fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\tif itemKind := src.Type().Elem().Kind(); itemKind == reflect.Int {\n\t\t\treturn copySize\n\t\t} else {\n\t\t\treturn src.Len()\n\t\t}\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": []int{1},\n\t\t\"Field2\": []string{\"1\", \"2\", \"3\"},\n\t}, dst)\n}\n\nfunc TestStructToStruct_CopySlice_WithDiffentItemType(t *testing.T) {\n\ttype AA struct {\n\t\tInt int\n\t}\n\ttype A struct {\n\t\tField1 []int\n\t\tField2 []AA\n\t}\n\tsrc := &A{\n\t\tField1: []int{1, 2, 3},\n\t\tField2: []AA{{1}, {2}, {3}},\n\t}\n\tdst := &A{}\n\tconst copySize int = 1\n\tmask := fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\tif itemType := src.Type().Elem().Name(); itemType == \"AA\" {\n\t\t\treturn copySize\n\t\t} else {\n\t\t\treturn src.Len()\n\t\t}\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: []int{1, 2, 3},\n\t\tField2: []AA{{1}},\n\t}, dst)\n}\n\nfunc TestStructToMap_CopySlice_WithDiffentItemType(t *testing.T) {\n\ttype AA struct {\n\t\tInt int\n\t}\n\ttype A struct {\n\t\tField1 []int\n\t\tField2 []AA\n\t}\n\tsrc := &A{\n\t\tField1: []int{1, 2, 3},\n\t\tField2: []AA{{1}, {2}, {3}},\n\t}\n\tdst := map[string]interface{}{}\n\tconst copySize int = 1\n\tmask := fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithCopyListSize(func(src *reflect.Value) int {\n\t\tif itemType := src.Type().Elem().Name(); itemType == \"AA\" {\n\t\t\treturn copySize\n\t\t} else {\n\t\t\treturn src.Len()\n\t\t}\n\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": []int{1, 2, 3},\n\t\t\"Field2\": []map[string]interface{}{{\"Int\": 1}},\n\t}, dst)\n}\n\nfunc TestStructToStruct_WithNonStructSrcError(t *testing.T) {\n\ttype A struct{ Field int }\n\tvar src = 1\n\tvar dst = &A{}\n\tmask := fieldmask_utils.MaskFromString(\"Field\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\trequire.Error(t, err)\n}\n\nfunc TestStructToStruct_WithMultiTagComma(t *testing.T) {\n\ttype A struct {\n\t\tField int `json:\"field,omitempty\"`\n\t}\n\tvar src = A{Field: 1}\n\tvar dst = map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"Field\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithTag(\"json\"))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"field\": 1,\n\t}, dst)\n}\n\nfunc TestStructToMap_WithInterface(t *testing.T) {\n\ttype user struct {\n\t\tA string\n\t\tB interface{}\n\t\tC interface{}\n\t}\n\ttype c struct {\n\t\tA int\n\t\tB interface{}\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"A,B,C\")\n\n\tsrc := &user{\n\t\tA: \"nick\",\n\t\tB: []int{1, 2, 3, 4},\n\t\tC: c{A: 42, B: map[string]interface{}{\"hi\": 34}},\n\t}\n\tdst := make(map[string]interface{})\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithTag(`json`))\n\tassert.Nil(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"A\": \"nick\",\n\t\t\"B\": []int{1, 2, 3, 4},\n\t\t\"C\": map[string]interface{}{\"A\": 42, \"B\": map[string]interface{}{\"hi\": 34}},\n\t}\n\tassert.Equal(t, expected, dst)\n}\n\nfunc TestStructToMap_PtrToInt(t *testing.T) {\n\ttype example struct {\n\t\tMyInt    *int64\n\t\tWhatEver string\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"MyInt,WhatEver\")\n\tmyInt := int64(42)\n\n\tsrc := &example{\n\t\tMyInt:    &myInt,\n\t\tWhatEver: \"hello\",\n\t}\n\tdst := make(map[string]interface{})\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\tassert.Nil(t, err)\n\n\texpected := map[string]interface{}{\n\t\t\"MyInt\":    int64(42),\n\t\t\"WhatEver\": \"hello\",\n\t}\n\tassert.Equal(t, expected, dst)\n}\n\nfunc TestStructToMap_DifferentTypeWithSameDstKey(t *testing.T) {\n\tt.Skip(\"this is a programming error which is expected to panic instead of returning an error\")\n\ttype BB struct {\n\t\tField int\n\t}\n\ttype A1 struct {\n\t\tFieldA []int\n\t\tFieldB []BB `json:\"FieldA\"`\n\t}\n\tvar src1 = A1{FieldA: []int{1, 2}, FieldB: []BB{{1}, {2}}}\n\tvar dst1 = map[string]interface{}{}\n\tmask := fieldmask_utils.MaskFromString(\"FieldA,FieldB\")\n\terr := fieldmask_utils.StructToMap(mask, src1, dst1, fieldmask_utils.WithTag(\"json\"))\n\trequire.Error(t, err)\n\n\ttype A2 struct {\n\t\tFieldA [2]int\n\t\tFieldB [2]BB `json:\"FieldA\"`\n\t}\n\tvar src2 = A2{FieldA: [2]int{1, 2}, FieldB: [2]BB{{1}, {2}}}\n\tvar dst2 = map[string]interface{}{}\n\tmask = fieldmask_utils.MaskFromString(\"FieldA,FieldB\")\n\terr = fieldmask_utils.StructToMap(mask, src2, dst2, fieldmask_utils.WithTag(\"json\"))\n\trequire.Error(t, err)\n}\n\nfunc TestStructToMap_EmptySrcSlice_JsonEncode(t *testing.T) {\n\ttype A struct{}\n\ttype B struct {\n\t\tAs []*A\n\t}\n\n\tsrc := &B{[]*A{}}\n\tdst := make(map[string]interface{})\n\n\tmask := fieldmask_utils.MaskFromString(\"As\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\n\tjsonStr, _ := json.Marshal(dst)\n\tassert.Equal(t, \"{\\\"As\\\":[]}\", string(jsonStr))\n}\n\nfunc TestStructToMap_NilSrcSlice_JsonEncode(t *testing.T) {\n\tt.Skip(\"the behavior that this test verifies has changed\")\n\ttype A struct{}\n\ttype B struct {\n\t\tAs []*A\n\t}\n\n\tsrc := &B{}\n\tdst := make(map[string]interface{})\n\n\tmask := fieldmask_utils.MaskFromString(\"As\")\n\terr := fieldmask_utils.StructToMap(mask, src, dst)\n\trequire.NoError(t, err)\n\n\tjsonStr, _ := json.Marshal(dst)\n\tassert.Equal(t, \"{\\\"As\\\":null}\", string(jsonStr))\n}\n\nfunc TestStructToStruct_CopySlice_WithDiffentAddr_WithDifferentFieldName(t *testing.T) {\n\ttype A struct {\n\t\tField1 []int\n\t\tField2 []int\n\t}\n\n\tvar src = &A{\n\t\tField1: []int{1, 2, 3},\n\t\tField2: []int{1, 2, 3},\n\t}\n\tvar field1 = reflect.ValueOf(src).Elem().FieldByName(\"Field1\")\n\tvar dst = &A{}\n\tvar mask = fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\tvar err = fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(\n\t\tfunc(src *reflect.Value) int {\n\t\t\tif src.Pointer() == (&field1).Pointer() {\n\t\t\t\treturn 2\n\t\t\t} else {\n\t\t\t\treturn src.Len()\n\t\t\t}\n\t\t},\n\t))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: []int{1, 2},\n\t\tField2: []int{1, 2, 3},\n\t}, dst)\n\n}\n\nfunc TestStructToStruct_CopySlice_WithSameAddr_WithDifferentFieldName(t *testing.T) {\n\tt.Skip(\"Not Address this problem\")\n\ttype A struct {\n\t\tField1 []int\n\t\tField2 []int\n\t}\n\n\tvar arr = []int{1, 2, 3}\n\n\tvar src = &A{\n\t\tField1: arr,\n\t\tField2: arr,\n\t}\n\tvar field1 = reflect.ValueOf(src).Elem().FieldByName(\"Field1\")\n\tvar dst = &A{}\n\tvar mask = fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\tvar err = fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(\n\t\tfunc(src *reflect.Value) int {\n\t\t\tif src.Pointer() == (&field1).Pointer() {\n\t\t\t\treturn 2\n\t\t\t} else {\n\t\t\t\treturn src.Len()\n\t\t\t}\n\t\t},\n\t))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: []int{1, 2},\n\t\tField2: []int{1, 2, 3},\n\t}, dst)\n}\n\nfunc TestStructToStruct_CopyArraySizeAccordingFieldName(t *testing.T) {\n\ttype A struct {\n\t\tField1 [3]int\n\t\tField2 [3]int\n\t}\n\n\tvar src = &A{\n\t\tField1: [3]int{1, 2, 3},\n\t\tField2: [3]int{1, 2, 3},\n\t}\n\tvar field1 = reflect.ValueOf(src).Elem().FieldByName(\"Field1\")\n\tvar dst = &A{}\n\tvar mask = fieldmask_utils.MaskFromString(\"Field1,Field2\")\n\tvar err = fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithCopyListSize(\n\t\tfunc(src *reflect.Value) int {\n\t\t\tif src.Addr() == (&field1).Addr() {\n\t\t\t\treturn 2\n\t\t\t} else {\n\t\t\t\treturn src.Len()\n\t\t\t}\n\t\t},\n\t))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &A{\n\t\tField1: [3]int{1, 2},\n\t\tField2: [3]int{1, 2, 3},\n\t}, dst)\n}\n\nfunc TestStructToStruct_WithSrcTag(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int `db:\"some_field\"`\n\t}\n\ttype B struct {\n\t\tField1 string `struct:\"a_name\"`\n\t\tA      A      `db:\"another_name,omitempty\"`\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tdst := &B{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\terr := fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithSrcTag(\"db\"))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{Field1: src.Field1}, dst)\n\n\tmask, _ = fieldmask_utils.MaskFromPaths([]string{\"Field1\", \"another_name.some_field\"}, func(s string) string { return s })\n\tdst = &B{}\n\terr = fieldmask_utils.StructToStruct(mask, src, dst, fieldmask_utils.WithSrcTag(\"db\"))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{Field1: src.Field1, A: A{Field2: src.A.Field2}}, dst)\n}\n\nfunc TestStructToMap_WithSrcTag(t *testing.T) {\n\ttype A struct {\n\t\tField1 string\n\t\tField2 int  `db:\"some_field1\" json:\"some_field1_json\"`\n\t\tField3 bool `db:\"some_field2\" json:\"some_field2_json\"`\n\t}\n\ttype B struct {\n\t\tField1 string `struct:\"a_name\"`\n\t\tA      A      `db:\"another_name,omitempty\" json:\"another_name_json\"`\n\t}\n\tsrc := &B{\n\t\tField1: \"B Field1\",\n\t\tA: A{\n\t\t\tField1: \"A Field 1\",\n\t\t\tField2: 1,\n\t\t},\n\t}\n\tmask := fieldmask_utils.MaskFromString(\"Field1,A{Field2}\")\n\tdst := make(map[string]interface{})\n\terr := fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithTag(\"json\"), fieldmask_utils.WithSrcTag(\"db\"))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t}, dst)\n\n\tmask, _ = fieldmask_utils.MaskFromPaths([]string{\"Field1\", \"another_name.some_field1\", \"another_name.some_field2\"}, func(s string) string { return s })\n\tdst = make(map[string]interface{})\n\terr = fieldmask_utils.StructToMap(mask, src, dst, fieldmask_utils.WithTag(\"json\"), fieldmask_utils.WithSrcTag(\"db\"))\n\trequire.NoError(t, err)\n\tassert.Equal(t, map[string]interface{}{\n\t\t\"Field1\": src.Field1,\n\t\t\"another_name_json\": map[string]interface{}{\n\t\t\t\"some_field1_json\": src.A.Field2,\n\t\t\t\"some_field2_json\": false,\n\t\t},\n\t}, dst)\n}\n\nfunc TestStructToStruct_WithConverterHook(t *testing.T) {\n\ttype E struct {\n\t\tField1 string\n\t}\n\ttype F struct {\n\t\tField1 string\n\t}\n\n\ttype A struct {\n\t\tField1 string\n\t\tField2 []*E\n\t\tField3 []*E\n\t\tField4 []string\n\t}\n\tsrc := &A{\n\t\tField1: \"   42   \",\n\t\tField2: nil,\n\t\tField3: []*E{\n\t\t\t{Field1: \"foo\"},\n\t\t},\n\t\tField4: []string{\"   3.141   \", \"-273.15\"},\n\t}\n\ttype B struct {\n\t\tField1 int64\n\t\tField2 []*F\n\t\tField3 []*F\n\t\tField4 []float64\n\t}\n\tdst := &B{}\n\tmask := fieldmask_utils.MaskFromString(\"Field1,Field2,Field3,Field4\")\n\n\t// test original error due to no conversion\n\terr := fieldmask_utils.StructToStruct(mask, src, dst)\n\tassert.Error(t, err)\n\n\t// test conversion errors are critical\n\terr = fieldmask_utils.StructToStruct(mask, src, dst,\n\t\tfieldmask_utils.WithConverterHook(func(src, dst *reflect.Value) (interface{}, error) {\n\t\t\treturn nil, errors.New(\"dummy error\")\n\t\t}))\n\trequire.Error(t, err)\n\tassert.ErrorContains(t, err, \"dummy error\")\n\n\t// test incompatible conversion still returns original error\n\terr = fieldmask_utils.StructToStruct(mask, src, dst,\n\t\tfieldmask_utils.WithConverterHook(func(src, dst *reflect.Value) (interface{}, error) {\n\t\t\treturn 3.14, nil\n\t\t}))\n\trequire.Error(t, err)\n\tassert.ErrorContains(t, err, \"differs from dst kind\")\n\n\t// test successful conversion\n\terr = fieldmask_utils.StructToStruct(mask, src, dst,\n\t\t// convert string to int64\n\t\tfieldmask_utils.WithConverterHook(func(src, dst *reflect.Value) (interface{}, error) {\n\t\t\tdata := src.Interface()\n\n\t\t\tif src.Kind() != reflect.String ||\n\t\t\t\tdst.Kind() != reflect.Int64 {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n\t\t\traw, ok := data.(string)\n\t\t\tif !ok {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n\t\t\treturn strconv.ParseInt(strings.TrimSpace(raw), 10, 64)\n\t\t}),\n\t\t// convert string to float64\n\t\tfieldmask_utils.WithConverterHook(func(src, dst *reflect.Value) (interface{}, error) {\n\t\t\tdata := src.Interface()\n\n\t\t\tif src.Kind() != reflect.String ||\n\t\t\t\tdst.Kind() != reflect.Float64 {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n\t\t\traw, ok := data.(string)\n\t\t\tif !ok {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n\t\t\treturn strconv.ParseFloat(strings.TrimSpace(raw), 64)\n\t\t}))\n\trequire.NoError(t, err)\n\tassert.Equal(t, &B{\n\t\tField1: 42,\n\t\tField2: nil,\n\t\tField3: []*F{\n\t\t\t{Field1: \"foo\"},\n\t\t},\n\t\tField4: []float64{3.141, -273.15},\n\t}, dst)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/mennanov/fieldmask-utils\n\ngo 1.16\n\nrequire (\n\tgithub.com/kr/text v0.2.0 // indirect\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/stretchr/testify v1.8.0\n\tgoogle.golang.org/genproto v0.0.0-20220531173845-685668d2de03\n\tgoogle.golang.org/protobuf v1.33.0\n\tgopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=\ngithub.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20220531173845-685668d2de03 h1:FG2YhwyltdDPC/0XuwzU0dijPcTzvfTtst0QdlDxoMU=\ngoogle.golang.org/genproto v0.0.0-20220531173845-685668d2de03/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=\ngoogle.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\n"
  },
  {
    "path": "mask.go",
    "content": "package fieldmask_utils\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/pkg/errors\"\n\t\"google.golang.org/genproto/protobuf/field_mask\"\n)\n\n// FieldFilter is an interface used by the copying function to filter fields that are needed to be copied.\ntype FieldFilter interface {\n\t// Filter should return a corresponding FieldFilter for the given fieldName and a boolean result. If result is true\n\t// then the field is copied, skipped otherwise.\n\tFilter(fieldName string) (FieldFilter, bool)\n\t// Returns true if the FieldFilter is empty. In this case all fields are copied.\n\tIsEmpty() bool\n}\n\n// FieldFilterContainer is a FieldFilter with additional methods Get and Set.\ntype FieldFilterContainer interface {\n\tFieldFilter\n\t// Get gets the FieldFilter for the given field name. Result is false if the filter is not found.\n\tGet(fieldName string) (filter FieldFilterContainer, result bool)\n\t// Set sets the FieldFilter for the given field name.\n\tSet(fieldName string, filter FieldFilterContainer)\n}\n\n// Mask is a tree-based implementation of a FieldFilter.\ntype Mask map[string]FieldFilterContainer\n\n// Get gets the FieldFilter for the given field name. Result is false if the filter is not found.\nfunc (m Mask) Get(fieldName string) (FieldFilterContainer, bool) {\n\tf, ok := m[fieldName]\n\treturn f, ok\n}\n\n// Set sets the FieldFilter for the given field name.\nfunc (m Mask) Set(fieldName string, filter FieldFilterContainer) {\n\tm[fieldName] = filter\n}\n\n// Compile time interface check.\nvar _ FieldFilter = Mask{}\n\n// Filter returns true for those fieldNames that exist in the underlying map.\n// Field names that start with \"XXX_\" are ignored as unexported.\nfunc (m Mask) Filter(fieldName string) (FieldFilter, bool) {\n\tif len(m) == 0 {\n\t\t// If the mask is empty choose all the exported fields.\n\t\treturn Mask{}, !strings.HasPrefix(fieldName, \"XXX_\")\n\t}\n\tsubFilter, ok := m[fieldName]\n\tif !ok {\n\t\tsubFilter = Mask{}\n\t}\n\treturn subFilter, ok\n}\n\n// IsEmpty returns true of the mask is empty.\nfunc (m Mask) IsEmpty() bool {\n\treturn len(m) == 0\n}\n\nfunc mapToString(m map[string]FieldFilterContainer) string {\n\tif len(m) == 0 {\n\t\treturn \"\"\n\t}\n\tvar result []string\n\tfor fieldName, maskNode := range m {\n\t\tr := fieldName\n\t\tvar sub string\n\t\tif stringer, ok := maskNode.(fmt.Stringer); ok {\n\t\t\tsub = stringer.String()\n\t\t} else {\n\t\t\tsub = fmt.Sprint(maskNode)\n\t\t}\n\t\tif sub != \"\" {\n\t\t\tr += \"{\" + sub + \"}\"\n\t\t}\n\t\tresult = append(result, r)\n\t}\n\treturn strings.Join(result, \",\")\n}\n\nfunc (m Mask) String() string {\n\treturn mapToString(m)\n}\n\n// MaskInverse is an inversed version of a Mask (will copy all the fields except those mentioned in the mask).\ntype MaskInverse map[string]FieldFilterContainer\n\n// Get gets the FieldFilter for the given field name. Result is false if the filter is not found.\nfunc (m MaskInverse) Get(fieldName string) (FieldFilterContainer, bool) {\n\tf, ok := m[fieldName]\n\treturn f, ok\n}\n\n// Set sets the FieldFilter for the given field name.\nfunc (m MaskInverse) Set(fieldName string, filter FieldFilterContainer) {\n\tm[fieldName] = filter\n}\n\n// Filter returns true for those fieldNames that do NOT exist in the underlying map.\n// Field names that start with \"XXX_\" are ignored as unexported.\nfunc (m MaskInverse) Filter(fieldName string) (FieldFilter, bool) {\n\tsubFilter, ok := m[fieldName]\n\tif !ok {\n\t\treturn MaskInverse{}, !strings.HasPrefix(fieldName, \"XXX_\")\n\t}\n\tif subFilter == nil {\n\t\treturn nil, false\n\t}\n\treturn subFilter, !subFilter.IsEmpty()\n}\n\n// IsEmpty returns true if the mask is empty.\nfunc (m MaskInverse) IsEmpty() bool {\n\treturn len(m) == 0\n}\n\nfunc (m MaskInverse) String() string {\n\treturn mapToString(m)\n}\n\n// MaskFromProtoFieldMask creates a Mask from the given FieldMask.\nfunc MaskFromProtoFieldMask(fm *field_mask.FieldMask, naming func(string) string) (Mask, error) {\n\treturn MaskFromPaths(fm.GetPaths(), naming)\n}\n\n// MaskInverseFromProtoFieldMask creates a MaskInverse from the given FieldMask.\nfunc MaskInverseFromProtoFieldMask(fm *field_mask.FieldMask, naming func(string) string) (MaskInverse, error) {\n\treturn MaskInverseFromPaths(fm.GetPaths(), naming)\n}\n\n// MaskFromPaths creates a new Mask from the given paths.\nfunc MaskFromPaths(paths []string, naming func(string) string) (Mask, error) {\n\tmask, err := FieldFilterFromPaths(paths, naming, func() FieldFilterContainer {\n\t\treturn make(Mask)\n\t})\n\tif mask != nil {\n\t\treturn mask.(Mask), err\n\t}\n\treturn nil, err\n}\n\n// MaskInverseFromPaths creates a new MaskInverse from the given paths.\nfunc MaskInverseFromPaths(paths []string, naming func(string) string) (MaskInverse, error) {\n\tmask, err := FieldFilterFromPaths(paths, naming, func() FieldFilterContainer {\n\t\treturn make(MaskInverse)\n\t})\n\tif mask != nil {\n\t\treturn mask.(MaskInverse), err\n\t}\n\treturn nil, err\n}\n\n// FieldFilterFromPaths creates a new FieldFilter from the given paths.\nfunc FieldFilterFromPaths(paths []string, naming func(string) string, filter func() FieldFilterContainer) (FieldFilterContainer, error) {\n\troot := filter()\n\tfor _, path := range paths {\n\t\tmask := root\n\t\tfor _, fieldName := range strings.Split(path, \".\") {\n\t\t\tif fieldName == \"\" {\n\t\t\t\treturn nil, errors.Errorf(\"invalid fieldName FieldFilter format: \\\"%s\\\"\", path)\n\t\t\t}\n\t\t\tnewFieldName := naming(fieldName)\n\t\t\tsubNode, ok := mask.Get(newFieldName)\n\t\t\tif !ok {\n\t\t\t\tmask.Set(newFieldName, filter())\n\t\t\t\tsubNode, _ = mask.Get(newFieldName)\n\t\t\t}\n\t\t\tmask = subNode\n\t\t}\n\t}\n\treturn root, nil\n}\n\n// MaskFromString creates a new Mask instance from a given string.\n// Use in tests only. See FieldFilterFromString for details.\nfunc MaskFromString(s string) Mask {\n\treturn FieldFilterFromString(s, func() FieldFilterContainer {\n\t\treturn make(Mask)\n\t}).(Mask)\n}\n\n// MaskInverseFromString creates a new MaskInverse instance from a given string.\n// Use in tests only. See FieldFilterFromString for details.\nfunc MaskInverseFromString(s string) MaskInverse {\n\treturn FieldFilterFromString(s, func() FieldFilterContainer {\n\t\treturn make(MaskInverse)\n\t}).(MaskInverse)\n}\n\n// FieldFilterFromString creates a new FieldFilterContainer from string.\n// Input string is supposed to be a valid string representation of a FieldFilter like \"a,b,c{d,e{f,g}},d\".\n// Use it in tests only as the input string is not validated and the underlying function panics in case of a\n// parse error.\nfunc FieldFilterFromString(input string, filter func() FieldFilterContainer) FieldFilterContainer {\n\tvar fieldName []string\n\tmask := filter()\n\tmasks := []FieldFilterContainer{mask}\n\tfor pos, r := range input {\n\t\tchar := string(r)\n\t\tswitch char {\n\t\tcase \" \", \"\\n\", \"\\t\":\n\t\t// Skip white spaces.\n\n\t\tcase \",\":\n\t\t\tif len(fieldName) != 0 {\n\t\t\t\tmask.Set(strings.Join(fieldName, \"\"), filter())\n\t\t\t\tfieldName = nil\n\t\t\t}\n\n\t\tcase \"{\":\n\t\t\tif len(fieldName) == 0 {\n\t\t\t\tpanic(fmt.Sprintf(\"invalid mask format at position %d: got '{', expected a character\", pos))\n\t\t\t}\n\t\t\tsubMask := filter()\n\t\t\tmask.Set(strings.Join(fieldName, \"\"), subMask)\n\t\t\tfieldName = nil\n\t\t\tmasks = append(masks, mask)\n\t\t\tmask = subMask\n\n\t\tcase \"}\":\n\t\t\tif len(fieldName) != 0 {\n\t\t\t\tmask.Set(strings.Join(fieldName, \"\"), filter())\n\t\t\t\tfieldName = nil\n\t\t\t}\n\t\t\tmask = masks[len(masks)-1]\n\t\t\tmasks = masks[:len(masks)-1]\n\n\t\tdefault:\n\t\t\tfieldName = append(fieldName, char)\n\t\t}\n\t}\n\tif len(fieldName) != 0 {\n\t\tmask.Set(strings.Join(fieldName, \"\"), filter())\n\t}\n\treturn mask\n}\n"
  },
  {
    "path": "mask_test.go",
    "content": "package fieldmask_utils_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/genproto/protobuf/field_mask\"\n\n\tfieldmask_utils \"github.com/mennanov/fieldmask-utils\"\n)\n\nfunc TestMask_String(t *testing.T) {\n\tmask := fieldmask_utils.MaskFromString(\"a{b{c}}\")\n\tassert.Equal(t, \"a{b{c}}\", mask.String())\n}\n\nfunc TestMaskInverse_String(t *testing.T) {\n\tmask := fieldmask_utils.MaskInverseFromString(\"a{b{c}}\")\n\tassert.Equal(t, \"a{b{c}}\", mask.String())\n}\n\nfunc TestFieldFilterFromPaths_Success(t *testing.T) {\n\teye := func(s string) string { return s }\n\ttestCases := []struct {\n\t\tmask         *field_mask.FieldMask\n\t\texpectedTree string\n\t}{\n\t\t{\n\t\t\t&field_mask.FieldMask{Paths: []string{\n\t\t\t\t\"a\", // overwritten by the paths below (a.*)\n\t\t\t\t\"a.b.c\",\n\t\t\t\t\"a.b.d\",\n\t\t\t\t\"a.c.d\",\n\t\t\t\t\"b.c.d\",\n\t\t\t\t\"a\", // has no effect, since more strict rules are applied above\n\t\t\t\t\"c\",\n\t\t\t}},\n\t\t\t\"a{b{c,d},c{d}},b{c{d}},c\",\n\t\t},\n\t\t{\n\t\t\t&field_mask.FieldMask{Paths: []string{\"a\", \"b\", \"b\", \"a\"}},\n\t\t\t\"a,b\",\n\t\t},\n\t\t{\n\t\t\t&field_mask.FieldMask{Paths: []string{}},\n\t\t\t\"\",\n\t\t},\n\t}\n\tfor _, testCase := range testCases {\n\t\tmaskFromProto, err := fieldmask_utils.MaskFromProtoFieldMask(testCase.mask, eye)\n\t\trequire.NoError(t, err)\n\t\tmaskFromPaths, err := fieldmask_utils.MaskFromPaths(testCase.mask.Paths, eye)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, fieldmask_utils.MaskFromString(testCase.expectedTree), maskFromProto)\n\t\tassert.Equal(t, maskFromProto, maskFromPaths)\n\t\t// MaskInverse\n\t\tmaskInverseFromProto, err := fieldmask_utils.MaskInverseFromProtoFieldMask(testCase.mask, eye)\n\t\trequire.NoError(t, err)\n\t\tmaskInverseFromPaths, err := fieldmask_utils.MaskInverseFromPaths(testCase.mask.Paths, eye)\n\t\trequire.NoError(t, err)\n\t\tfs := fieldmask_utils.MaskInverseFromString(testCase.expectedTree)\n\t\tassert.Equal(t, fs, maskInverseFromProto)\n\t\tassert.Equal(t, maskInverseFromProto, maskInverseFromPaths)\n\t}\n}\n\nfunc TestMaskFromProtoFieldMask_Failure(t *testing.T) {\n\ttestCases := []*field_mask.FieldMask{\n\t\t{Paths: []string{\"a\", \".a\"}},\n\t\t{Paths: []string{\".\"}},\n\t\t{Paths: []string{\"a.b.c.d.e\", \"a.b.\"}},\n\t}\n\n\tfor _, fieldMask := range testCases {\n\t\t_, err := fieldmask_utils.MaskFromProtoFieldMask(fieldMask, func(s string) string { return s })\n\t\tassert.NotNil(t, err)\n\t}\n}\n\nfunc TestMaskFromString(t *testing.T) {\n\ttestCases := []struct {\n\t\tinput        string\n\t\texpectedMask fieldmask_utils.Mask\n\t\tlength       int\n\t}{\n\t\t{\n\t\t\t\"foo,bar{c{d,e{f,g,h}}}\",\n\t\t\tfieldmask_utils.Mask{\n\t\t\t\t\"foo\": fieldmask_utils.Mask{},\n\t\t\t\t\"bar\": fieldmask_utils.Mask{\n\t\t\t\t\t\"c\": fieldmask_utils.Mask{\n\t\t\t\t\t\t\"d\": fieldmask_utils.Mask{},\n\t\t\t\t\t\t\"e\": fieldmask_utils.Mask{\n\t\t\t\t\t\t\t\"f\": fieldmask_utils.Mask{},\n\t\t\t\t\t\t\t\"g\": fieldmask_utils.Mask{},\n\t\t\t\t\t\t\t\"h\": fieldmask_utils.Mask{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}, 2,\n\t\t},\n\t\t{\"foo, bar{c {d,e{f,\\ng,h}}},\\tt\", fieldmask_utils.Mask{\n\t\t\t\"foo\": fieldmask_utils.Mask{},\n\t\t\t\"bar\": fieldmask_utils.Mask{\n\t\t\t\t\"c\": fieldmask_utils.Mask{\n\t\t\t\t\t\"d\": fieldmask_utils.Mask{},\n\t\t\t\t\t\"e\": fieldmask_utils.Mask{\n\t\t\t\t\t\t\"f\": fieldmask_utils.Mask{},\n\t\t\t\t\t\t\"g\": fieldmask_utils.Mask{},\n\t\t\t\t\t\t\"h\": fieldmask_utils.Mask{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"t\": fieldmask_utils.Mask{},\n\t\t}, 3},\n\t\t{\"foo\", fieldmask_utils.Mask{\"foo\": fieldmask_utils.Mask{}}, 1},\n\t\t{\"foo,bar\", fieldmask_utils.Mask{\n\t\t\t\"foo\": fieldmask_utils.Mask{},\n\t\t\t\"bar\": fieldmask_utils.Mask{},\n\t\t}, 2},\n\t\t{\"foo,bar{c},d,e\", fieldmask_utils.Mask{\n\t\t\t\"foo\": fieldmask_utils.Mask{},\n\t\t\t\"bar\": fieldmask_utils.Mask{\n\t\t\t\t\"c\": fieldmask_utils.Mask{},\n\t\t\t},\n\t\t\t\"d\": fieldmask_utils.Mask{},\n\t\t\t\"e\": fieldmask_utils.Mask{},\n\t\t}, 4},\n\t\t{\"\", fieldmask_utils.Mask{}, 0},\n\t}\n\tfor _, testCase := range testCases {\n\t\tmask := fieldmask_utils.MaskFromString(testCase.input)\n\t\tassert.Equal(t, testCase.expectedMask, mask)\n\t\tassert.Equal(t, testCase.length, len(mask))\n\t}\n}\n"
  },
  {
    "path": "revive.toml",
    "content": "ignoreGeneratedHeader = false\nseverity = \"warning\"\nconfidence = 0.8\nerrorCode = 1\nwarningCode = 1\n\n# <block keep-sorted=\"asc\">\n[rule.blank-imports]\n[rule.context-as-argument]\n[rule.context-keys-type]\n[rule.dot-imports]\n[rule.empty-block]\n[rule.error-naming]\n[rule.error-return]\n[rule.error-strings]\n[rule.errorf]\n[rule.exported]\n[rule.if-return]\n[rule.increment-decrement]\n[rule.indent-error-flow]\n[rule.package-comments]\n[rule.range]\n[rule.receiver-naming]\n[rule.redefines-builtin-id]\n[rule.superfluous-else]\n[rule.time-naming]\n[rule.unexported-return]\n[rule.unreachable-code]\n[rule.unused-parameter]\n[rule.var-declaration]\n# </block>\n"
  },
  {
    "path": "testproto/test.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.26.0\n// \tprotoc        v3.17.1\n// source: test.proto\n\npackage testproto\n\nimport (\n\treflect \"reflect\"\n\tsync \"sync\"\n\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n\tfieldmaskpb \"google.golang.org/protobuf/types/known/fieldmaskpb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype Role int32\n\nconst (\n\tRole_UNKNOWN Role = 0\n\tRole_REGULAR Role = 1\n\tRole_ADMIN   Role = 2\n)\n\n// Enum value maps for Role.\nvar (\n\tRole_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"REGULAR\",\n\t\t2: \"ADMIN\",\n\t}\n\tRole_value = map[string]int32{\n\t\t\"UNKNOWN\": 0,\n\t\t\"REGULAR\": 1,\n\t\t\"ADMIN\":   2,\n\t}\n)\n\nfunc (x Role) Enum() *Role {\n\tp := new(Role)\n\t*p = x\n\treturn p\n}\n\nfunc (x Role) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Role) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_test_proto_enumTypes[0].Descriptor()\n}\n\nfunc (Role) Type() protoreflect.EnumType {\n\treturn &file_test_proto_enumTypes[0]\n}\n\nfunc (x Role) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Role.Descriptor instead.\nfunc (Role) EnumDescriptor() ([]byte, []int) {\n\treturn file_test_proto_rawDescGZIP(), []int{0}\n}\n\ntype Permission int32\n\nconst (\n\tPermission_READ    Permission = 0\n\tPermission_WRITE   Permission = 1\n\tPermission_EXECUTE Permission = 2\n)\n\n// Enum value maps for Permission.\nvar (\n\tPermission_name = map[int32]string{\n\t\t0: \"READ\",\n\t\t1: \"WRITE\",\n\t\t2: \"EXECUTE\",\n\t}\n\tPermission_value = map[string]int32{\n\t\t\"READ\":    0,\n\t\t\"WRITE\":   1,\n\t\t\"EXECUTE\": 2,\n\t}\n)\n\nfunc (x Permission) Enum() *Permission {\n\tp := new(Permission)\n\t*p = x\n\treturn p\n}\n\nfunc (x Permission) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Permission) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_test_proto_enumTypes[1].Descriptor()\n}\n\nfunc (Permission) Type() protoreflect.EnumType {\n\treturn &file_test_proto_enumTypes[1]\n}\n\nfunc (x Permission) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use Permission.Descriptor instead.\nfunc (Permission) EnumDescriptor() ([]byte, []int) {\n\treturn file_test_proto_rawDescGZIP(), []int{1}\n}\n\ntype Image struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tOriginalUrl string `protobuf:\"bytes,1,opt,name=original_url,json=originalUrl,proto3\" json:\"original_url,omitempty\"`\n\tResizedUrl  string `protobuf:\"bytes,2,opt,name=resized_url,json=resizedUrl,proto3\" json:\"resized_url,omitempty\"`\n}\n\nfunc (x *Image) Reset() {\n\t*x = Image{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Image) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Image) ProtoMessage() {}\n\nfunc (x *Image) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Image.ProtoReflect.Descriptor instead.\nfunc (*Image) Descriptor() ([]byte, []int) {\n\treturn file_test_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Image) GetOriginalUrl() string {\n\tif x != nil {\n\t\treturn x.OriginalUrl\n\t}\n\treturn \"\"\n}\n\nfunc (x *Image) GetResizedUrl() string {\n\tif x != nil {\n\t\treturn x.ResizedUrl\n\t}\n\treturn \"\"\n}\n\ntype Metrics struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tHeight uint32 `protobuf:\"varint,1,opt,name=height,proto3\" json:\"height,omitempty\"`\n\tWeight uint32 `protobuf:\"varint,2,opt,name=weight,proto3\" json:\"weight,omitempty\"`\n}\n\nfunc (x *Metrics) Reset() {\n\t*x = Metrics{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Metrics) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Metrics) ProtoMessage() {}\n\nfunc (x *Metrics) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Metrics.ProtoReflect.Descriptor instead.\nfunc (*Metrics) Descriptor() ([]byte, []int) {\n\treturn file_test_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Metrics) GetHeight() uint32 {\n\tif x != nil {\n\t\treturn x.Height\n\t}\n\treturn 0\n}\n\nfunc (x *Metrics) GetWeight() uint32 {\n\tif x != nil {\n\t\treturn x.Weight\n\t}\n\treturn 0\n}\n\ntype User struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tId          uint32            `protobuf:\"varint,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tUsername    string            `protobuf:\"bytes,2,opt,name=username,proto3\" json:\"username,omitempty\"`\n\tRole        Role              `protobuf:\"varint,3,opt,name=role,proto3,enum=Role\" json:\"role,omitempty\"`\n\tMeta        map[string]string `protobuf:\"bytes,4,rep,name=meta,proto3\" json:\"meta,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\tDeactivated bool              `protobuf:\"varint,5,opt,name=deactivated,proto3\" json:\"deactivated,omitempty\"`\n\tPermissions []Permission      `protobuf:\"varint,6,rep,packed,name=permissions,proto3,enum=Permission\" json:\"permissions,omitempty\"`\n\t// Types that are assignable to Name:\n\t//\t*User_MaleName\n\t//\t*User_FemaleName\n\tName      isUser_Name  `protobuf_oneof:\"name\"`\n\tDetails   []*anypb.Any `protobuf:\"bytes,9,rep,name=details,proto3\" json:\"details,omitempty\"`\n\tImages    []*Image     `protobuf:\"bytes,10,rep,name=images,proto3\" json:\"images,omitempty\"`\n\tAvatar    *Image       `protobuf:\"bytes,11,opt,name=avatar,proto3\" json:\"avatar,omitempty\"`\n\tTags      []string     `protobuf:\"bytes,12,rep,name=tags,proto3\" json:\"tags,omitempty\"`\n\tFriends   []*User      `protobuf:\"bytes,13,rep,name=friends,proto3\" json:\"friends,omitempty\"`\n\tExtraUser *anypb.Any   `protobuf:\"bytes,14,opt,name=extra_user,json=extraUser,proto3\" json:\"extra_user,omitempty\"`\n}\n\nfunc (x *User) Reset() {\n\t*x = User{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *User) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*User) ProtoMessage() {}\n\nfunc (x *User) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use User.ProtoReflect.Descriptor instead.\nfunc (*User) Descriptor() ([]byte, []int) {\n\treturn file_test_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *User) GetId() uint32 {\n\tif x != nil {\n\t\treturn x.Id\n\t}\n\treturn 0\n}\n\nfunc (x *User) GetUsername() string {\n\tif x != nil {\n\t\treturn x.Username\n\t}\n\treturn \"\"\n}\n\nfunc (x *User) GetRole() Role {\n\tif x != nil {\n\t\treturn x.Role\n\t}\n\treturn Role_UNKNOWN\n}\n\nfunc (x *User) GetMeta() map[string]string {\n\tif x != nil {\n\t\treturn x.Meta\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetDeactivated() bool {\n\tif x != nil {\n\t\treturn x.Deactivated\n\t}\n\treturn false\n}\n\nfunc (x *User) GetPermissions() []Permission {\n\tif x != nil {\n\t\treturn x.Permissions\n\t}\n\treturn nil\n}\n\nfunc (m *User) GetName() isUser_Name {\n\tif m != nil {\n\t\treturn m.Name\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetMaleName() string {\n\tif x, ok := x.GetName().(*User_MaleName); ok {\n\t\treturn x.MaleName\n\t}\n\treturn \"\"\n}\n\nfunc (x *User) GetFemaleName() string {\n\tif x, ok := x.GetName().(*User_FemaleName); ok {\n\t\treturn x.FemaleName\n\t}\n\treturn \"\"\n}\n\nfunc (x *User) GetDetails() []*anypb.Any {\n\tif x != nil {\n\t\treturn x.Details\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetImages() []*Image {\n\tif x != nil {\n\t\treturn x.Images\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetAvatar() *Image {\n\tif x != nil {\n\t\treturn x.Avatar\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetTags() []string {\n\tif x != nil {\n\t\treturn x.Tags\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetFriends() []*User {\n\tif x != nil {\n\t\treturn x.Friends\n\t}\n\treturn nil\n}\n\nfunc (x *User) GetExtraUser() *anypb.Any {\n\tif x != nil {\n\t\treturn x.ExtraUser\n\t}\n\treturn nil\n}\n\ntype isUser_Name interface {\n\tisUser_Name()\n}\n\ntype User_MaleName struct {\n\tMaleName string `protobuf:\"bytes,7,opt,name=male_name,json=maleName,proto3,oneof\"`\n}\n\ntype User_FemaleName struct {\n\tFemaleName string `protobuf:\"bytes,8,opt,name=female_name,json=femaleName,proto3,oneof\"`\n}\n\nfunc (*User_MaleName) isUser_Name() {}\n\nfunc (*User_FemaleName) isUser_Name() {}\n\ntype UpdateUserRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUser      *User                  `protobuf:\"bytes,1,opt,name=user,proto3\" json:\"user,omitempty\"`\n\tFieldMask *fieldmaskpb.FieldMask `protobuf:\"bytes,2,opt,name=field_mask,json=fieldMask,proto3\" json:\"field_mask,omitempty\"`\n}\n\nfunc (x *UpdateUserRequest) Reset() {\n\t*x = UpdateUserRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *UpdateUserRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*UpdateUserRequest) ProtoMessage() {}\n\nfunc (x *UpdateUserRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use UpdateUserRequest.ProtoReflect.Descriptor instead.\nfunc (*UpdateUserRequest) Descriptor() ([]byte, []int) {\n\treturn file_test_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *UpdateUserRequest) GetUser() *User {\n\tif x != nil {\n\t\treturn x.User\n\t}\n\treturn nil\n}\n\nfunc (x *UpdateUserRequest) GetFieldMask() *fieldmaskpb.FieldMask {\n\tif x != nil {\n\t\treturn x.FieldMask\n\t}\n\treturn nil\n}\n\nvar File_test_proto protoreflect.FileDescriptor\n\nvar file_test_proto_rawDesc = []byte{\n\t0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f,\n\t0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e,\n\t0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d,\n\t0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4b, 0x0a, 0x05, 0x49, 0x6d, 0x61,\n\t0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x75,\n\t0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,\n\t0x61, 0x6c, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x64,\n\t0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x69,\n\t0x7a, 0x65, 0x64, 0x55, 0x72, 0x6c, 0x22, 0x39, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,\n\t0x73, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x0d, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x69,\n\t0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68,\n\t0x74, 0x22, 0xa0, 0x04, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,\n\t0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73,\n\t0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x0e, 0x32, 0x05, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c,\n\t0x65, 0x12, 0x23, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x0f, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,\n\t0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x61, 0x63, 0x74, 0x69,\n\t0x76, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x65, 0x61,\n\t0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2d, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d,\n\t0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x0b, 0x2e,\n\t0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d,\n\t0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x09, 0x6d, 0x61, 0x6c, 0x65, 0x5f,\n\t0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x6d, 0x61,\n\t0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x66, 0x65, 0x6d, 0x61, 0x6c, 0x65,\n\t0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x66,\n\t0x65, 0x6d, 0x61, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74,\n\t0x61, 0x69, 0x6c, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79,\n\t0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1e, 0x0a, 0x06, 0x69, 0x6d, 0x61,\n\t0x67, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x49, 0x6d, 0x61, 0x67,\n\t0x65, 0x52, 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x06, 0x61, 0x76, 0x61,\n\t0x74, 0x61, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x49, 0x6d, 0x61, 0x67,\n\t0x65, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67,\n\t0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1f, 0x0a,\n\t0x07, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x05,\n\t0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x07, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x33,\n\t0x0a, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x65, 0x78, 0x74, 0x72, 0x61, 0x55,\n\t0x73, 0x65, 0x72, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,\n\t0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,\n\t0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04,\n\t0x6e, 0x61, 0x6d, 0x65, 0x22, 0x69, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73,\n\t0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x04, 0x75, 0x73, 0x65,\n\t0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04,\n\t0x75, 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61,\n\t0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,\n\t0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64,\n\t0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x2a,\n\t0x2b, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,\n\t0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10,\n\t0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x2a, 0x2e, 0x0a, 0x0a,\n\t0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45,\n\t0x41, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x52, 0x49, 0x54, 0x45, 0x10, 0x01, 0x12,\n\t0x0b, 0x0a, 0x07, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x10, 0x02, 0x42, 0x2f, 0x5a, 0x2d,\n\t0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x65, 0x6e, 0x6e, 0x61,\n\t0x6e, 0x6f, 0x76, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x6d, 0x61, 0x73, 0x6b, 0x2d, 0x75, 0x74,\n\t0x69, 0x6c, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_test_proto_rawDescOnce sync.Once\n\tfile_test_proto_rawDescData = file_test_proto_rawDesc\n)\n\nfunc file_test_proto_rawDescGZIP() []byte {\n\tfile_test_proto_rawDescOnce.Do(func() {\n\t\tfile_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_proto_rawDescData)\n\t})\n\treturn file_test_proto_rawDescData\n}\n\nvar file_test_proto_enumTypes = make([]protoimpl.EnumInfo, 2)\nvar file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 5)\nvar file_test_proto_goTypes = []interface{}{\n\t(Role)(0),                     // 0: Role\n\t(Permission)(0),               // 1: Permission\n\t(*Image)(nil),                 // 2: Image\n\t(*Metrics)(nil),               // 3: Metrics\n\t(*User)(nil),                  // 4: User\n\t(*UpdateUserRequest)(nil),     // 5: UpdateUserRequest\n\tnil,                           // 6: User.MetaEntry\n\t(*anypb.Any)(nil),             // 7: google.protobuf.Any\n\t(*fieldmaskpb.FieldMask)(nil), // 8: google.protobuf.FieldMask\n}\nvar file_test_proto_depIdxs = []int32{\n\t0,  // 0: User.role:type_name -> Role\n\t6,  // 1: User.meta:type_name -> User.MetaEntry\n\t1,  // 2: User.permissions:type_name -> Permission\n\t7,  // 3: User.details:type_name -> google.protobuf.Any\n\t2,  // 4: User.images:type_name -> Image\n\t2,  // 5: User.avatar:type_name -> Image\n\t4,  // 6: User.friends:type_name -> User\n\t7,  // 7: User.extra_user:type_name -> google.protobuf.Any\n\t4,  // 8: UpdateUserRequest.user:type_name -> User\n\t8,  // 9: UpdateUserRequest.field_mask:type_name -> google.protobuf.FieldMask\n\t10, // [10:10] is the sub-list for method output_type\n\t10, // [10:10] is the sub-list for method input_type\n\t10, // [10:10] is the sub-list for extension type_name\n\t10, // [10:10] is the sub-list for extension extendee\n\t0,  // [0:10] is the sub-list for field type_name\n}\n\nfunc init() { file_test_proto_init() }\nfunc file_test_proto_init() {\n\tif File_test_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Image); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Metrics); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*User); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*UpdateUserRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_test_proto_msgTypes[2].OneofWrappers = []interface{}{\n\t\t(*User_MaleName)(nil),\n\t\t(*User_FemaleName)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_test_proto_rawDesc,\n\t\t\tNumEnums:      2,\n\t\t\tNumMessages:   5,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_test_proto_goTypes,\n\t\tDependencyIndexes: file_test_proto_depIdxs,\n\t\tEnumInfos:         file_test_proto_enumTypes,\n\t\tMessageInfos:      file_test_proto_msgTypes,\n\t}.Build()\n\tFile_test_proto = out.File\n\tfile_test_proto_rawDesc = nil\n\tfile_test_proto_goTypes = nil\n\tfile_test_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "testproto/test.proto",
    "content": "syntax = \"proto3\";\n\noption go_package = \"github.com/mennanov/fieldmask-utils/testproto\";\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/field_mask.proto\";\n\nmessage Image {\n    string original_url = 1;\n    string resized_url = 2;\n}\n\nmessage Metrics {\n    uint32 height = 1;\n    uint32 weight = 2;\n}\n\nenum Role {\n    UNKNOWN = 0;\n    REGULAR = 1;\n    ADMIN = 2;\n}\n\nenum Permission {\n    READ = 0;\n    WRITE = 1;\n    EXECUTE = 2;\n}\n\nmessage User {\n    uint32 id = 1;\n    string username = 2;\n    Role role = 3;\n    map<string, string> meta = 4;\n    bool deactivated = 5;\n\n    repeated Permission permissions = 6;\n    oneof name {\n        string male_name = 7;\n        string female_name = 8;\n    }\n    repeated google.protobuf.Any details = 9;\n    repeated Image images = 10;\n    Image avatar = 11;\n    repeated string tags = 12;\n    repeated User friends = 13;\n    google.protobuf.Any extra_user = 14;\n}\n\nmessage UpdateUserRequest {\n    User user = 1;\n    google.protobuf.FieldMask field_mask = 2;\n}\n"
  }
]