func (d *ResourceDiff) HasChange(key string) bool {
	old, new := d.GetChange(key)
	if eq, ok := old.(Equal); ok {
		return !eq.Equal(new)
	}
	return !reflect.DeepEqual(old, new)
}
HasChange checks to see if there is a change between state and the diff, or
in the overridden diff.
package schema
import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"sync"
	"github.com/hashicorp/terraform/terraform"
)
type newValueWriter struct {
	*MapFieldWriter
	computedKeys map[string]bool
	lock sync.Mutex
	once sync.Once
}
func (w *newValueWriter) init() {
	if w.computedKeys == nil {
		w.computedKeys = make(map[string]bool)
	}
}
func (w *newValueWriter) WriteField(address []string, value interface{}, computed bool) error {
	if value != nil && computed {
		return errors.New("Non-nil value with computed set")
	}
	if err := w.MapFieldWriter.WriteField(address, value); err != nil {
		return err
	}
	w.once.Do(w.init)
	w.lock.Lock()
	defer w.lock.Unlock()
	if computed {
		w.computedKeys[strings.Join(address, ".")] = true
	}
	return nil
}
func (w *newValueWriter) ComputedKeysMap() map[string]bool {
	w.once.Do(w.init)
	return w.computedKeys
}
type newValueReader struct {
	*MapFieldReader
	computedKeys map[string]bool
}
func (r *newValueReader) ReadField(address []string) (FieldReadResult, error) {
	addrKey := strings.Join(address, ".")
	v, err := r.MapFieldReader.ReadField(address)
	if err != nil {
		return FieldReadResult{}, err
	}
	for computedKey := range r.computedKeys {
		if childAddrOf(addrKey, computedKey) {
			if strings.HasSuffix(addrKey, ".#") {
				v.Exists = false
			}
			v.Computed = true
		}
	}
	return v, nil
}
type ResourceDiff struct {
	schema map[string]*Schema
	config *terraform.ResourceConfig
	state *terraform.InstanceState
	diff *terraform.InstanceDiff
	multiReader *MultiLevelFieldReader
	newWriter *newValueWriter
	updatedKeys map[string]bool
	forcedNewKeys map[string]bool
}
func newResourceDiff(schema map[string]*Schema, config *terraform.ResourceConfig, state *terraform.InstanceState, diff *terraform.InstanceDiff) *ResourceDiff {
	d := &ResourceDiff{
		config: config,
		state:  state,
		diff:   diff,
		schema: schema,
	}
	d.newWriter = &newValueWriter{
		MapFieldWriter: &MapFieldWriter{Schema: d.schema},
	}
	readers := make(map[string]FieldReader)
	var stateAttributes map[string]string
	if d.state != nil {
		stateAttributes = d.state.Attributes
		readers["state"] = &MapFieldReader{
			Schema: d.schema,
			Map:    BasicMapReader(stateAttributes),
		}
	}
	if d.config != nil {
		readers["config"] = &ConfigFieldReader{
			Schema: d.schema,
			Config: d.config,
		}
	}
	if d.diff != nil {
		readers["diff"] = &DiffFieldReader{
			Schema: d.schema,
			Diff:   d.diff,
			Source: &MultiLevelFieldReader{
				Levels:  []string{"state", "config"},
				Readers: readers,
			},
		}
	}
	readers["newDiff"] = &newValueReader{
		MapFieldReader: &MapFieldReader{
			Schema: d.schema,
			Map:    BasicMapReader(d.newWriter.Map()),
		},
		computedKeys: d.newWriter.ComputedKeysMap(),
	}
	d.multiReader = &MultiLevelFieldReader{
		Levels: []string{
			"state",
			"config",
			"diff",
			"newDiff",
		},
		Readers: readers,
	}
	d.updatedKeys = make(map[string]bool)
	d.forcedNewKeys = make(map[string]bool)
	return d
}
func (d *ResourceDiff) UpdatedKeys() []string {
	var s []string
	for k := range d.updatedKeys {
		s = append(s, k)
	}
	for k := range d.forcedNewKeys {
		for _, l := range s {
			if k == l {
				break
			}
		}
		s = append(s, k)
	}
	return s
}
func (d *ResourceDiff) Clear(key string) error {
	if err := d.checkKey(key, "Clear", true); err != nil {
		return err
	}
	return d.clear(key)
}
func (d *ResourceDiff) clear(key string) error {
	schemaL := addrToSchema(strings.Split(key, "."), d.schema)
	if len(schemaL) == 0 {
		return fmt.Errorf("%s is not a valid key", key)
	}
	for k := range d.diff.Attributes {
		if strings.HasPrefix(k, key) {
			delete(d.diff.Attributes, k)
		}
	}
	return nil
}
func (d *ResourceDiff) GetChangedKeysPrefix(prefix string) []string {
	keys := make([]string, 0)
	for k := range d.diff.Attributes {
		if strings.HasPrefix(k, prefix) {
			keys = append(keys, k)
		}
	}
	return keys
}
func (d *ResourceDiff) diffChange(key string) (interface{}, interface{}, bool, bool, bool) {
	old, new, customized := d.getChange(key)
	if !old.Exists {
		old.Value = nil
	}
	if !new.Exists || d.removed(key) {
		new.Value = nil
	}
	return old.Value, new.Value, !reflect.DeepEqual(old.Value, new.Value), new.Computed, customized
}
func (d *ResourceDiff) SetNew(key string, value interface{}) error {
	if err := d.checkKey(key, "SetNew", false); err != nil {
		return err
	}
	return d.setDiff(key, value, false)
}
func (d *ResourceDiff) SetNewComputed(key string) error {
	if err := d.checkKey(key, "SetNewComputed", false); err != nil {
		return err
	}
	return d.setDiff(key, nil, true)
}
func (d *ResourceDiff) setDiff(key string, new interface{}, computed bool) error {
	if err := d.clear(key); err != nil {
		return err
	}
	if err := d.newWriter.WriteField(strings.Split(key, "."), new, computed); err != nil {
		return fmt.Errorf("Cannot set new diff value for key %s: %s", key, err)
	}
	d.updatedKeys[key] = true
	return nil
}
func (d *ResourceDiff) ForceNew(key string) error {
	if !d.HasChange(key) {
		return fmt.Errorf("ForceNew: No changes for %s", key)
	}
	keyParts := strings.Split(key, ".")
	var schema *Schema
	schemaL := addrToSchema(keyParts, d.schema)
	if len(schemaL) > 0 {
		schema = schemaL[len(schemaL)-1]
	} else {
		return fmt.Errorf("ForceNew: %s is not a valid key", key)
	}
	schema.ForceNew = true
	d.forcedNewKeys[keyParts[0]] = true
	return nil
}
func (d *ResourceDiff) Get(key string) interface{} {
	r, _ := d.GetOk(key)
	return r
}
func (d *ResourceDiff) GetChange(key string) (interface{}, interface{}) {
	old, new, _ := d.getChange(key)
	return old.Value, new.Value
}
func (d *ResourceDiff) GetOk(key string) (interface{}, bool) {
	r := d.get(strings.Split(key, "."), "newDiff")
	exists := r.Exists && !r.Computed
	if exists {
		value := r.Value
		zero := r.Schema.Type.Zero()
		if eq, ok := value.(Equal); ok {
			exists = !eq.Equal(zero)
		} else {
			exists = !reflect.DeepEqual(value, zero)
		}
	}
	return r.Value, exists
}
func (d *ResourceDiff) GetOkExists(key string) (interface{}, bool) {
	r := d.get(strings.Split(key, "."), "newDiff")
	exists := r.Exists && !r.Computed
	return r.Value, exists
}
func (d *ResourceDiff) NewValueKnown(key string) bool {
	r := d.get(strings.Split(key, "."), "newDiff")
	return !r.Computed
}