Skip to content

Commit 32b3c5d

Browse files
committed
Add FromCtyValueTagged
Like FromCtyValue, but you can pass in a different tag to decode with. Update code using literal "cty" to use a passed in tag string. Put the insides of FromCtyValue into FromCtyValueTagged, now FromCtyValue calls FromCtyValueTagged with literal "cty".
1 parent 15a9d85 commit 32b3c5d

File tree

5 files changed

+71
-34
lines changed

5 files changed

+71
-34
lines changed

cty/gocty/helpers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ var stringType = reflect.TypeOf("")
2727
//
2828
// This function will panic if two fields within the struct are tagged with
2929
// the same cty attribute name.
30-
func structTagIndices(st reflect.Type) map[string]int {
30+
func structTagIndices(st reflect.Type, tag string) map[string]int {
3131
ct := st.NumField()
3232
ret := make(map[string]int, ct)
3333

3434
for i := 0; i < ct; i++ {
3535
field := st.Field(i)
36-
attrName := field.Tag.Get("cty")
36+
attrName := field.Tag.Get(tag)
3737
if attrName != "" {
3838
ret[attrName] = i
3939
}

cty/gocty/in.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ func toCtyObject(val reflect.Value, attrTypes map[string]cty.Type, path cty.Path
355355
// path to give us a place to put our GetAttr step.
356356
path = append(path, cty.PathStep(nil))
357357

358-
attrFields := structTagIndices(val.Type())
358+
attrFields := structTagIndices(val.Type(), "cty")
359359

360360
vals := make(map[string]cty.Value, len(attrTypes))
361361
for k, at := range attrTypes {

cty/gocty/out.go

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import (
2727
// The function will panic if given a non-pointer as the Go value target,
2828
// since that is considered to be a bug in the calling program.
2929
func FromCtyValue(val cty.Value, target interface{}) error {
30+
return FromCtyValueTagged(val, target, "cty")
31+
}
32+
33+
func FromCtyValueTagged(val cty.Value, target interface{}, tag string) error {
3034
tVal := reflect.ValueOf(target)
3135
if tVal.Kind() != reflect.Ptr {
3236
panic("target value is not a pointer")
@@ -40,10 +44,10 @@ func FromCtyValue(val cty.Value, target interface{}) error {
4044
// unused capacity on the end of it, depending on how deeply-recursive
4145
// the given cty.Value is.
4246
path := make(cty.Path, 0)
43-
return fromCtyValue(val, tVal, path)
47+
return fromCtyValue(val, tVal, path, tag)
4448
}
4549

46-
func fromCtyValue(val cty.Value, target reflect.Value, path cty.Path) error {
50+
func fromCtyValue(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
4751
ty := val.Type()
4852

4953
deepTarget := fromCtyPopulatePtr(target, false)
@@ -89,17 +93,17 @@ func fromCtyValue(val cty.Value, target reflect.Value, path cty.Path) error {
8993

9094
switch {
9195
case ty.IsListType():
92-
return fromCtyList(val, target, path)
96+
return fromCtyList(val, target, path, tag)
9397
case ty.IsMapType():
94-
return fromCtyMap(val, target, path)
98+
return fromCtyMap(val, target, path, tag)
9599
case ty.IsSetType():
96-
return fromCtySet(val, target, path)
100+
return fromCtySet(val, target, path, tag)
97101
case ty.IsObjectType():
98-
return fromCtyObject(val, target, path)
102+
return fromCtyObject(val, target, path, tag)
99103
case ty.IsTupleType():
100-
return fromCtyTuple(val, target, path)
104+
return fromCtyTuple(val, target, path, tag)
101105
case ty.IsCapsuleType():
102-
return fromCtyCapsule(val, target, path)
106+
return fromCtyCapsule(val, target, path, tag)
103107
}
104108

105109
// We should never fall out here; reaching here indicates a bug in this
@@ -251,7 +255,7 @@ func fromCtyString(val cty.Value, target reflect.Value, path cty.Path) error {
251255
}
252256
}
253257

254-
func fromCtyList(val cty.Value, target reflect.Value, path cty.Path) error {
258+
func fromCtyList(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
255259
switch target.Kind() {
256260

257261
case reflect.Slice:
@@ -273,7 +277,7 @@ func fromCtyList(val cty.Value, target reflect.Value, path cty.Path) error {
273277
}
274278

275279
targetElem := tv.Index(i)
276-
err = fromCtyValue(val, targetElem, path)
280+
err = fromCtyValue(val, targetElem, path, tag)
277281
if err != nil {
278282
return true
279283
}
@@ -310,7 +314,7 @@ func fromCtyList(val cty.Value, target reflect.Value, path cty.Path) error {
310314
}
311315

312316
targetElem := target.Index(i)
313-
err = fromCtyValue(val, targetElem, path)
317+
err = fromCtyValue(val, targetElem, path, tag)
314318
if err != nil {
315319
return true
316320
}
@@ -332,7 +336,7 @@ func fromCtyList(val cty.Value, target reflect.Value, path cty.Path) error {
332336
}
333337
}
334338

335-
func fromCtyMap(val cty.Value, target reflect.Value, path cty.Path) error {
339+
func fromCtyMap(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
336340

337341
switch target.Kind() {
338342

@@ -356,7 +360,7 @@ func fromCtyMap(val cty.Value, target reflect.Value, path cty.Path) error {
356360
ks := key.AsString()
357361

358362
targetElem := reflect.New(et)
359-
err = fromCtyValue(val, targetElem, path)
363+
err = fromCtyValue(val, targetElem, path, tag)
360364

361365
tv.SetMapIndex(reflect.ValueOf(ks), targetElem.Elem())
362366

@@ -377,7 +381,7 @@ func fromCtyMap(val cty.Value, target reflect.Value, path cty.Path) error {
377381
}
378382
}
379383

380-
func fromCtySet(val cty.Value, target reflect.Value, path cty.Path) error {
384+
func fromCtySet(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
381385
switch target.Kind() {
382386

383387
case reflect.Slice:
@@ -393,7 +397,7 @@ func fromCtySet(val cty.Value, target reflect.Value, path cty.Path) error {
393397
var err error
394398
val.ForEachElement(func(key cty.Value, val cty.Value) bool {
395399
targetElem := tv.Index(i)
396-
err = fromCtyValue(val, targetElem, path)
400+
err = fromCtyValue(val, targetElem, path, tag)
397401
if err != nil {
398402
return true
399403
}
@@ -422,7 +426,7 @@ func fromCtySet(val cty.Value, target reflect.Value, path cty.Path) error {
422426
var err error
423427
val.ForEachElement(func(key cty.Value, val cty.Value) bool {
424428
targetElem := target.Index(i)
425-
err = fromCtyValue(val, targetElem, path)
429+
err = fromCtyValue(val, targetElem, path, tag)
426430
if err != nil {
427431
return true
428432
}
@@ -444,14 +448,14 @@ func fromCtySet(val cty.Value, target reflect.Value, path cty.Path) error {
444448
}
445449
}
446450

447-
func fromCtyObject(val cty.Value, target reflect.Value, path cty.Path) error {
451+
func fromCtyObject(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
448452

449453
switch target.Kind() {
450454

451455
case reflect.Struct:
452456

453457
attrTypes := val.Type().AttributeTypes()
454-
targetFields := structTagIndices(target.Type())
458+
targetFields := structTagIndices(target.Type(), tag)
455459

456460
path = append(path, nil)
457461

@@ -482,7 +486,7 @@ func fromCtyObject(val cty.Value, target reflect.Value, path cty.Path) error {
482486
ev := val.GetAttr(k)
483487

484488
targetField := target.Field(fieldIdx)
485-
err := fromCtyValue(ev, targetField, path)
489+
err := fromCtyValue(ev, targetField, path, tag)
486490
if err != nil {
487491
return err
488492
}
@@ -498,7 +502,7 @@ func fromCtyObject(val cty.Value, target reflect.Value, path cty.Path) error {
498502
}
499503
}
500504

501-
func fromCtyTuple(val cty.Value, target reflect.Value, path cty.Path) error {
505+
func fromCtyTuple(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
502506

503507
switch target.Kind() {
504508

@@ -521,7 +525,7 @@ func fromCtyTuple(val cty.Value, target reflect.Value, path cty.Path) error {
521525
ev := val.Index(cty.NumberIntVal(int64(i)))
522526

523527
targetField := target.Field(i)
524-
err := fromCtyValue(ev, targetField, path)
528+
err := fromCtyValue(ev, targetField, path, tag)
525529
if err != nil {
526530
return err
527531
}
@@ -537,7 +541,7 @@ func fromCtyTuple(val cty.Value, target reflect.Value, path cty.Path) error {
537541
}
538542
}
539543

540-
func fromCtyCapsule(val cty.Value, target reflect.Value, path cty.Path) error {
544+
func fromCtyCapsule(val cty.Value, target reflect.Value, path cty.Path, tag string) error {
541545

542546
if target.Kind() == reflect.Ptr {
543547
// Walk through indirection until we get to the last pointer,

cty/gocty/out_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,31 @@ func TestOut(t *testing.T) {
374374
}
375375
}
376376

377+
func TestOutOtherTags(t *testing.T) {
378+
taggedCty, taggedOther := new(testStructManyTag), new(testStructManyTag)
379+
err := FromCtyValueTagged(cty.ObjectVal(map[string]cty.Value{
380+
"name": cty.StringVal("Eva"),
381+
}), taggedCty, "cty")
382+
if err != nil {
383+
t.Fatalf("FromCtyValueTagged returned error: %s", err)
384+
}
385+
386+
err = FromCtyValueTagged(cty.ObjectVal(map[string]cty.Value{
387+
"another_name": cty.StringVal("Alice"),
388+
}), taggedOther, "other")
389+
if err != nil {
390+
t.Fatalf("FromCtyValueTagged returned error: %s", err)
391+
}
392+
393+
if taggedCty.Name != "Eva" {
394+
t.Fatalf("taggedCty name mismatch: %s != Eva!", taggedCty.Name)
395+
}
396+
397+
if taggedOther.Name != "Alice" {
398+
t.Fatalf("taggedCty name mismatch: %s != Alice!", taggedOther.Name)
399+
}
400+
}
401+
377402
type testOutAssertFunc func(cty.Value, reflect.Type, interface{}, *testing.T)
378403

379404
func testOutAssertPtrVal(want interface{}) testOutAssertFunc {
@@ -409,6 +434,10 @@ type testStruct struct {
409434
Number *int `cty:"number"`
410435
}
411436

437+
type testStructManyTag struct {
438+
Name string `cty:"name" other:"another_name"`
439+
}
440+
412441
type testTupleStruct struct {
413442
Name string
414443
Number int

cty/gocty/type_implied.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,20 @@ import (
2222
// type, because it cannot know the capsule types supported by the calling
2323
// program.
2424
func ImpliedType(gv interface{}) (cty.Type, error) {
25+
return ImpliedTypeTagged(gv, "cty")
26+
}
27+
28+
func ImpliedTypeTagged(gv interface{}, tag string) (cty.Type, error) {
2529
rt := reflect.TypeOf(gv)
2630
var path cty.Path
27-
return impliedType(rt, path)
31+
return impliedType(rt, path, tag)
2832
}
2933

30-
func impliedType(rt reflect.Type, path cty.Path) (cty.Type, error) {
34+
func impliedType(rt reflect.Type, path cty.Path, tag string) (cty.Type, error) {
3135
switch rt.Kind() {
3236

3337
case reflect.Ptr:
34-
return impliedType(rt.Elem(), path)
38+
return impliedType(rt.Elem(), path, tag)
3539

3640
// Primitive types
3741
case reflect.Bool:
@@ -48,7 +52,7 @@ func impliedType(rt reflect.Type, path cty.Path) (cty.Type, error) {
4852
// Collection types
4953
case reflect.Slice:
5054
path := append(path, cty.IndexStep{Key: cty.UnknownVal(cty.Number)})
51-
ety, err := impliedType(rt.Elem(), path)
55+
ety, err := impliedType(rt.Elem(), path, tag)
5256
if err != nil {
5357
return cty.NilType, err
5458
}
@@ -58,29 +62,29 @@ func impliedType(rt reflect.Type, path cty.Path) (cty.Type, error) {
5862
return cty.NilType, path.NewErrorf("no cty.Type for %s (must have string keys)", rt)
5963
}
6064
path := append(path, cty.IndexStep{Key: cty.UnknownVal(cty.String)})
61-
ety, err := impliedType(rt.Elem(), path)
65+
ety, err := impliedType(rt.Elem(), path, tag)
6266
if err != nil {
6367
return cty.NilType, err
6468
}
6569
return cty.Map(ety), nil
6670

6771
// Structural types
6872
case reflect.Struct:
69-
return impliedStructType(rt, path)
73+
return impliedStructType(rt, path, tag)
7074

7175
default:
7276
return cty.NilType, path.NewErrorf("no cty.Type for %s", rt)
7377
}
7478
}
7579

76-
func impliedStructType(rt reflect.Type, path cty.Path) (cty.Type, error) {
80+
func impliedStructType(rt reflect.Type, path cty.Path, tag string) (cty.Type, error) {
7781
if valueType.AssignableTo(rt) {
7882
// Special case: cty.Value represents cty.DynamicPseudoType, for
7983
// type conformance checking.
8084
return cty.DynamicPseudoType, nil
8185
}
8286

83-
fieldIdxs := structTagIndices(rt)
87+
fieldIdxs := structTagIndices(rt, tag)
8488
if len(fieldIdxs) == 0 {
8589
return cty.NilType, path.NewErrorf("no cty.Type for %s (no cty field tags)", rt)
8690
}
@@ -95,7 +99,7 @@ func impliedStructType(rt reflect.Type, path cty.Path) (cty.Type, error) {
9599
path[len(path)-1] = cty.GetAttrStep{Name: k}
96100

97101
ft := rt.Field(fi).Type
98-
aty, err := impliedType(ft, path)
102+
aty, err := impliedType(ft, path, tag)
99103
if err != nil {
100104
return cty.NilType, err
101105
}

0 commit comments

Comments
 (0)