-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3018 from apparentlymart/auto-set-hash
helper/schema: Default hashing function for sets
- Loading branch information
Showing
9 changed files
with
374 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package schema | ||
|
||
import ( | ||
"bytes" | ||
"sort" | ||
"strconv" | ||
) | ||
|
||
func SerializeValueForHash(buf *bytes.Buffer, val interface{}, schema *Schema) { | ||
if val == nil { | ||
buf.WriteRune(';') | ||
return | ||
} | ||
|
||
switch schema.Type { | ||
case TypeBool: | ||
if val.(bool) { | ||
buf.WriteRune('1') | ||
} else { | ||
buf.WriteRune('0') | ||
} | ||
case TypeInt: | ||
buf.WriteString(strconv.Itoa(val.(int))) | ||
case TypeFloat: | ||
buf.WriteString(strconv.FormatFloat(val.(float64), 'g', -1, 64)) | ||
case TypeString: | ||
buf.WriteString(val.(string)) | ||
case TypeList: | ||
buf.WriteRune('(') | ||
l := val.([]interface{}) | ||
for _, innerVal := range l { | ||
serializeCollectionMemberForHash(buf, innerVal, schema.Elem) | ||
} | ||
buf.WriteRune(')') | ||
case TypeMap: | ||
m := val.(map[string]interface{}) | ||
var keys []string | ||
for k := range m { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
buf.WriteRune('[') | ||
for _, k := range keys { | ||
innerVal := m[k] | ||
buf.WriteString(k) | ||
buf.WriteRune(':') | ||
serializeCollectionMemberForHash(buf, innerVal, schema.Elem) | ||
} | ||
buf.WriteRune(']') | ||
case TypeSet: | ||
buf.WriteRune('{') | ||
s := val.(*Set) | ||
for _, innerVal := range s.List() { | ||
serializeCollectionMemberForHash(buf, innerVal, schema.Elem) | ||
} | ||
buf.WriteRune('}') | ||
default: | ||
panic("unknown schema type to serialize") | ||
} | ||
buf.WriteRune(';') | ||
} | ||
|
||
// SerializeValueForHash appends a serialization of the given resource config | ||
// to the given buffer, guaranteeing deterministic results given the same value | ||
// and schema. | ||
// | ||
// Its primary purpose is as input into a hashing function in order | ||
// to hash complex substructures when used in sets, and so the serialization | ||
// is not reversible. | ||
func SerializeResourceForHash(buf *bytes.Buffer, val interface{}, resource *Resource) { | ||
sm := resource.Schema | ||
m := val.(map[string]interface{}) | ||
var keys []string | ||
for k := range sm { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
for _, k := range keys { | ||
innerSchema := sm[k] | ||
// Skip attributes that are not user-provided. Computed attributes | ||
// do not contribute to the hash since their ultimate value cannot | ||
// be known at plan/diff time. | ||
if !(innerSchema.Required || innerSchema.Optional) { | ||
continue | ||
} | ||
|
||
buf.WriteString(k) | ||
buf.WriteRune(':') | ||
innerVal := m[k] | ||
SerializeValueForHash(buf, innerVal, innerSchema) | ||
} | ||
} | ||
|
||
func serializeCollectionMemberForHash(buf *bytes.Buffer, val interface{}, elem interface{}) { | ||
switch tElem := elem.(type) { | ||
case *Schema: | ||
SerializeValueForHash(buf, val, tElem) | ||
case *Resource: | ||
buf.WriteRune('<') | ||
SerializeResourceForHash(buf, val, tElem) | ||
buf.WriteString(">;") | ||
default: | ||
panic("invalid element type") | ||
} | ||
} |
Oops, something went wrong.