func (left *Resource) checkType(t Value_Type) Value_Type {
	if left != nil && left.GetType() != t {
		panic(fmt.Sprintf("expected type %v instead of %v", t, left.GetType()))
	}
	return t
}
checkType panics if the type of this resources != t
package mesos
import (
	"bytes"
	"fmt"
	"strconv"
	"github.com/gogo/protobuf/proto"
	"github.com/mesos/mesos-go/api/v1/lib/roles"
)
const DefaultRole = "*"
var (
	CapabilityReservationRefinement string = ""
)
func IsCapabilityReservationRefinementEnabled() bool { return CapabilityReservationRefinement == "1" }
type (
	Resources         []Resource
	resourceErrorType int
	resourceError struct {
		errorType resourceErrorType
		reason    string
		spec      Resource
	}
)
const (
	resourceErrorTypeIllegalName resourceErrorType = iota
	resourceErrorTypeIllegalType
	resourceErrorTypeUnsupportedType
	resourceErrorTypeIllegalScalar
	resourceErrorTypeIllegalRanges
	resourceErrorTypeIllegalSet
	resourceErrorTypeIllegalDisk
	resourceErrorTypeIllegalReservation
	resourceErrorTypeIllegalShare
	noReason = ""  
)
var (
	resourceErrorMessages = map[resourceErrorType]string{
		resourceErrorTypeIllegalName:        "missing or illegal resource name",
		resourceErrorTypeIllegalType:        "missing or illegal resource type",
		resourceErrorTypeUnsupportedType:    "unsupported resource type",
		resourceErrorTypeIllegalScalar:      "illegal scalar resource",
		resourceErrorTypeIllegalRanges:      "illegal ranges resource",
		resourceErrorTypeIllegalSet:         "illegal set resource",
		resourceErrorTypeIllegalDisk:        "illegal disk resource",
		resourceErrorTypeIllegalReservation: "illegal resource reservation",
		resourceErrorTypeIllegalShare:       "illegal shared resource",
	}
)
func (t resourceErrorType) Generate(reason string) error {
	msg := resourceErrorMessages[t]
	if reason != noReason {
		if msg != "" {
			msg += ": " + reason
		} else {
			msg = reason
		}
	}
	return &resourceError{errorType: t, reason: msg}
}
func (err *resourceError) Reason() string          { return err.reason }
func (err *resourceError) Resource() Resource      { return err.spec }
func (err *resourceError) WithResource(r Resource) { err.spec = r }
func (err *resourceError) Error() string {
	if err.reason != "" {
		return "resource error: " + err.reason
	}
	return "resource error"
}
func IsResourceError(err error) (ok bool) {
	_, ok = err.(*resourceError)
	return
}
func (r *Resource_ReservationInfo) Assign() func(interface{}) {
	return func(v interface{}) {
		type reserver interface {
			WithReservation(*Resource_ReservationInfo)
		}
		if ri, ok := v.(reserver); ok {
			ri.WithReservation(r)
		}
	}
}
func (resources Resources) Clone() Resources {
	if resources == nil {
		return nil
	}
	clone := make(Resources, 0, len(resources))
	for i := range resources {
		rr := proto.Clone(&resources[i]).(*Resource)
		clone = append(clone, *rr)
	}
	return clone
}
func (resources Resources) Minus(that ...Resource) Resources {
	x := resources.Clone()
	return x.Subtract(that...)
}
func (resources *Resources) Subtract(that ...Resource) (rs Resources) {
	if resources != nil {
		if len(that) > 0 {
			x := make(Resources, len(that))
			copy(x, that)
			that = x
			for i := range that {
				resources.Subtract1(that[i])
			}
		}
		rs = *resources
	}
	return
}
func (resources Resources) Plus(that ...Resource) Resources {
	x := resources.Clone()
	return x.Add(that...)
}
func (resources *Resources) Add(that ...Resource) (rs Resources) {
	if resources != nil {
		rs = *resources
	}
	for i := range that {
		rs = rs._add(that[i])
	}
	if resources != nil {
		*resources = rs
	}
	return
}
func (resources *Resources) Add1(that Resource) (rs Resources) {
	if resources != nil {
		rs = *resources
	}
	rs = rs._add(that)
	if resources != nil {
		*resources = rs
	}
	return
}
func (resources Resources) _add(that Resource) Resources {
	if that.Validate() != nil || that.IsEmpty() {
		return resources
	}
	for i := range resources {
		r := &resources[i]
		if r.Addable(that) {
			r.Add(that)
			return resources
		}
	}
	r := proto.Clone(&that).(*Resource)
	return append(resources, *r)
}
func (resources *Resources) Minus1(that Resource) Resources {
	x := resources.Clone()
	return x.Subtract1(that)
}
func (resources *Resources) Subtract1(that Resource) Resources {
	if resources == nil {
		return nil
	}
	if that.Validate() == nil && !that.IsEmpty() {
		for i := range *resources {
			r := &(*resources)[i]
			if r.Subtractable(that) {
				r.Subtract(that)
				if r.Validate() != nil || r.IsEmpty() {
					(*resources), (*resources)[len((*resources))-1] = append((*resources)[:i], (*resources)[i+1:]...), Resource{}
				}
				break
			}
		}
	}
	return *resources
}
func (resources Resources) String() string {
	return resources.Format()
}
type ResourcesFormatOptions struct {
	ShowAllocated bool  
}
func (resources Resources) Format(options ...func(*ResourcesFormatOptions)) string {
	if len(resources) == 0 {
		return ""
	}
	var f ResourcesFormatOptions
	for _, o := range options {
		if o != nil {
			o(&f)
		}
	}
	buf := bytes.Buffer{}
	for i := range resources {
		if i > 0 {
			buf.WriteString(";")
		}
		r := &resources[i]
		buf.WriteString(r.Name)
		if r.AllocationInfo != nil && f.ShowAllocated {
			buf.WriteString("(allocated: ")
			buf.WriteString(r.AllocationInfo.GetRole())
			buf.WriteString(")")
		}
		if res := r.Reservations; len(res) > 0 || (r.Role != nil && *r.Role != "*") {
			if len(res) == 0 {
				res = make([]Resource_ReservationInfo, 0, 1)
				if r.Reservation == nil {
					res = append(res, Resource_ReservationInfo{
						Type: Resource_ReservationInfo_STATIC.Enum(),
						Role: r.Role,
					})
				} else {
					res = append(res, *r.Reservation)  
					res[0].Type = Resource_ReservationInfo_DYNAMIC.Enum()
					res[0].Role = r.Role
				}
			}
			buf.WriteString("(reservations: [")
			for j := range res {
				if j > 0 {
					buf.WriteString(",")
				}
				rr := &res[j]
				buf.WriteString("(")
				buf.WriteString(rr.GetType().String())
				buf.WriteString(",")
				buf.WriteString(rr.GetRole())
				if rr.Principal != nil {
					buf.WriteString(",")
					buf.WriteString(*rr.Principal)
				}
				if rr.Labels != nil {
					buf.WriteString(",{")
					rr.GetLabels().writeTo(&buf)
					buf.WriteString("}")
				}
				buf.WriteString(")")
			}
			buf.WriteString("])")
		}
		if d := r.GetDisk(); d != nil {
			buf.WriteString("[")
			if s := d.GetSource(); s != nil {
				switch s.GetType() {
				case Resource_DiskInfo_Source_BLOCK:
					buf.WriteString("BLOCK")
					if id, profile, vendor := s.GetID(), s.GetProfile(), s.GetVendor(); id != "" || profile != "" || vendor != "" {
						buf.WriteByte('(')
						buf.WriteString(vendor)
						buf.WriteByte(',')
						buf.WriteString(id)
						buf.WriteByte(',')
						buf.WriteString(profile)
						buf.WriteByte(')')
					}
				case Resource_DiskInfo_Source_RAW:
					buf.WriteString("RAW")
					if id, profile, vendor := s.GetID(), s.GetProfile(), s.GetVendor(); id != "" || profile != "" || vendor != "" {
						buf.WriteByte('(')
						buf.WriteString(vendor)
						buf.WriteByte(',')
						buf.WriteString(id)
						buf.WriteByte(',')
						buf.WriteString(profile)
						buf.WriteByte(')')
					}
				case Resource_DiskInfo_Source_PATH:
					buf.WriteString("PATH")
					if id, profile, vendor := s.GetID(), s.GetProfile(), s.GetVendor(); id != "" || profile != "" || vendor != "" {
						buf.WriteByte('(')
						buf.WriteString(vendor)
						buf.WriteByte(',')
						buf.WriteString(id)
						buf.WriteByte(',')
						buf.WriteString(profile)
						buf.WriteByte(')')
					} else if root := s.GetPath().GetRoot(); root != "" {
						buf.WriteByte(':')
						buf.WriteString(root)
					}
				case Resource_DiskInfo_Source_MOUNT:
					buf.WriteString("MOUNT")
					if id, profile, vendor := s.GetID(), s.GetProfile(), s.GetVendor(); id != "" || profile != "" || vendor != "" {
						buf.WriteByte('(')
						buf.WriteString(vendor)
						buf.WriteByte(',')
						buf.WriteString(id)
						buf.WriteByte(',')
						buf.WriteString(profile)
						buf.WriteByte(')')
					} else if root := s.GetMount().GetRoot(); root != "" {
						buf.WriteByte(':')
						buf.WriteString(root)
					}
				}
			}
			if p := d.GetPersistence(); p != nil {
				if d.GetSource() != nil {
					buf.WriteString(",")
				}
				buf.WriteString(p.GetID())
			}
			if v := d.GetVolume(); v != nil {
				buf.WriteString(":")
				vconfig := v.GetContainerPath()
				if h := v.GetHostPath(); h != "" {
					vconfig = h + ":" + vconfig
				}
				if m := v.Mode; m != nil {
					switch *m {
					case RO:
						vconfig += ":ro"
					case RW:
						vconfig += ":rw"
					default:
						panic("unrecognized volume mode: " + m.String())
					}
				}
				buf.WriteString(vconfig)
			}
			buf.WriteString("]")
		}
		if r.Revocable != nil {
			buf.WriteString("{REV}")
		}
		if r.Shared != nil {
			buf.WriteString("<SHARED>")
		}
		buf.WriteString(":")
		switch r.GetType() {
		case SCALAR:
			buf.WriteString(strconv.FormatFloat(r.GetScalar().GetValue(), 'f', -1, 64))
		case RANGES:
			buf.WriteString("[")
			ranges := Ranges(r.GetRanges().GetRange())
			for j := range ranges {
				if j > 0 {
					buf.WriteString(",")
				}
				if b, e := ranges[j].Begin, ranges[j].End; b == e {
					buf.WriteString(strconv.FormatUint(b, 10))
				} else {
					buf.WriteString(strconv.FormatUint(b, 10))
					buf.WriteString("-")
					buf.WriteString(strconv.FormatUint(e, 10))
				}
			}
			buf.WriteString("]")
		case SET:
			buf.WriteString("{")
			items := r.GetSet().GetItem()
			for j := range items {
				if j > 0 {
					buf.WriteString(",")
				}
				buf.WriteString(items[j])
			}
			buf.WriteString("}")
		}
	}
	return buf.String()
}
func (left *Resource) Validate() error {
	if left.GetName() == "" {
		return resourceErrorTypeIllegalName.Generate(noReason)
	}
	if _, ok := Value_Type_name[int32(left.GetType())]; !ok {
		return resourceErrorTypeIllegalType.Generate(noReason)
	}
	switch left.GetType() {
	case SCALAR:
		if s := left.GetScalar(); s == nil || left.GetRanges() != nil || left.GetSet() != nil {
			return resourceErrorTypeIllegalScalar.Generate(noReason)
		} else if s.GetValue() < 0 {
			return resourceErrorTypeIllegalScalar.Generate("value < 0")
		}
	case RANGES:
		r := left.GetRanges()
		if left.GetScalar() != nil || r == nil || left.GetSet() != nil {
			return resourceErrorTypeIllegalRanges.Generate(noReason)
		}
		for i, rr := range r.GetRange() {
			if rr.Begin > rr.End {
				return resourceErrorTypeIllegalRanges.Generate("begin > end")
			}
			for j := i + 1; j < len(r.GetRange()); j++ {
				r2 := r.GetRange()[j]
				if rr.Begin <= r2.Begin && r2.Begin <= rr.End {
					return resourceErrorTypeIllegalRanges.Generate("overlapping ranges")
				}
			}
		}
	case SET:
		s := left.GetSet()
		if left.GetScalar() != nil || left.GetRanges() != nil || s == nil {
			return resourceErrorTypeIllegalSet.Generate(noReason)
		}
		unique := make(map[string]struct{}, len(s.GetItem()))
		for _, x := range s.GetItem() {
			if _, found := unique[x]; found {
				return resourceErrorTypeIllegalSet.Generate("duplicated elements")
			}
			unique[x] = struct{}{}
		}
	default:
		return resourceErrorTypeUnsupportedType.Generate(noReason)
	}
	if disk := left.GetDisk(); disk != nil {
		if left.GetName() != "disk" {
			return resourceErrorTypeIllegalDisk.Generate("DiskInfo should not be set for \"" + left.GetName() + "\" resource")
		}
		if s := disk.GetSource(); s != nil {
			switch s.GetType() {
			case Resource_DiskInfo_Source_PATH,
				Resource_DiskInfo_Source_MOUNT:
			case Resource_DiskInfo_Source_BLOCK,
				Resource_DiskInfo_Source_RAW:
			case Resource_DiskInfo_Source_UNKNOWN:
				return resourceErrorTypeIllegalDisk.Generate(fmt.Sprintf("unsupported DiskInfo.Source.Type in %q", s))
			}
		}
	}
	if rs := left.GetReservations(); len(rs) == 0 {
		if _, err := roles.Parse(left.GetRole()); err != nil {
			return resourceErrorTypeIllegalReservation.Generate(err.Error())
		}
		if r := left.GetReservation(); r != nil {
			if r.Type != nil {
				return resourceErrorTypeIllegalReservation.Generate(
					"Resource.ReservationInfo.type must not be set for the Resource.reservation field")
			}
			if r.Role != nil {
				return resourceErrorTypeIllegalReservation.Generate(
					"Resource.ReservationInfo.role must not be set for the Resource.reservation field")
			}
			if left.GetRole() == "*" {
				return resourceErrorTypeIllegalReservation.Generate("default role cannot be dynamically reserved")
			}
		}
	} else {
		for i := range rs {
			r := &rs[i]
			if r.Type == nil {
				return resourceErrorTypeIllegalReservation.Generate(
					"Resource.ReservationInfo.type must be set")
			}
			if r.Role == nil {
				return resourceErrorTypeIllegalReservation.Generate(
					"Resource.ReservationInfo.role must be set")
			}
			if _, err := roles.Parse(r.GetRole()); err != nil {
				return resourceErrorTypeIllegalReservation.Generate(err.Error())
			}
			if r.GetRole() == "*" {
				return resourceErrorTypeIllegalReservation.Generate(
					"role '*' cannot be reserved")
			}
		}
		ancestor := rs[0].GetRole()
		for i := 1; i < len(rs); i++ {
			r := &rs[i]
			if r.GetType() == Resource_ReservationInfo_STATIC {
				return resourceErrorTypeIllegalReservation.Generate(
					"a refined reservation cannot be STATIC")
			}
			child := r.GetRole()
			if !roles.IsStrictSubroleOf(child, ancestor) {
				return resourceErrorTypeIllegalReservation.Generate(fmt.Sprintf(
					"role %q is not a refinement of %q", child, ancestor))
			}
		}
		if len(rs) == 1 {
			if r := left.Role; r != nil && *r != rs[0].GetRole() {
				return resourceErrorTypeIllegalReservation.Generate(fmt.Sprintf(
					"'Resource.role' field with %q does not match the role %q in 'Resource.reservations'",
					*r, rs[0].GetRole()))
			}
			switch rs[0].GetType() {
			case Resource_ReservationInfo_STATIC:
				if left.Reservation != nil {
					return resourceErrorTypeIllegalReservation.Generate(
						"'Resource.reservation' must not be set if the single reservation in 'Resource.reservations' is STATIC")
				}
			case Resource_ReservationInfo_DYNAMIC:
				if (left.Role == nil) != (left.GetReservation() == nil) {
					return resourceErrorTypeIllegalReservation.Generate(
						"'Resource.role' and 'Resource.reservation' must both be set or both not be set if the single reservation in 'Resource.reservations' is DYNAMIC")
				}
				if r := left.GetReservation(); r != nil && r.GetPrincipal() != rs[0].GetPrincipal() {
					return resourceErrorTypeIllegalReservation.Generate(fmt.Sprintf(
						"'Resource.reservation.principal' with %q does not match the principal %q in 'Resource.reservations'",
						r.GetPrincipal(), rs[0].GetPrincipal()))
				}
				if r := left.GetReservation(); r != nil && !r.GetLabels().Equivalent(rs[0].GetLabels()) {
					return resourceErrorTypeIllegalReservation.Generate(fmt.Sprintf(
						"'Resource.reservation.labels' with %q does not match the labels %q in 'Resource.reservations'",
						r.GetLabels(), rs[0].GetLabels()))
				}
			case Resource_ReservationInfo_UNKNOWN:
				return resourceErrorTypeIllegalReservation.Generate("Unsupported 'Resource.ReservationInfo.type'")
			}
		} else {
			if r := left.Role; r != nil {
				return resourceErrorTypeIllegalReservation.Generate(
					"'Resource.role' must not be set if there is more than one reservation in 'Resource.reservations'")
			}
			if r := left.GetReservation(); r != nil {
				return resourceErrorTypeIllegalReservation.Generate(
					"'Resource.reservation' must not be set if there is more than one reservation in 'Resource.reservations'")
			}
		}
	}
	if s := left.GetShared(); s != nil {
		if left.GetName() != "disk" {
			return resourceErrorTypeIllegalShare.Generate(fmt.Sprintf(
				"Resource %q cannot be shared", left.GetName()))
		}
		if p := left.GetDisk().GetPersistence(); p == nil {
			return resourceErrorTypeIllegalShare.Generate("only persistent volumes can be shared")
		}
	}
	return nil
}
func (left *Resource_AllocationInfo) Equivalent(right *Resource_AllocationInfo) bool {
	if (left == nil) != (right == nil) {
		return false
	} else if left == nil {
		return true
	}
	if (left.Role == nil) != (right.Role == nil) {
		return false
	}
	if left.Role != nil && *left.Role != *right.Role {
		return false
	}
	return true
}
func (r *Resource_ReservationInfo) Equivalent(right *Resource_ReservationInfo) bool {
	if (r == nil) != (right == nil) {
		return false
	} else if r == nil {
		return true
	}
	if (r.Type == nil) != (right.Type == nil) {
		return false
	}
	if r.Type != nil && *r.Type != *right.Type {
		return false
	}
	if (r.Role == nil) != (right.Role == nil) {
		return false
	}
	if r.Role != nil && *r.Role != *right.Role {
		return false
	}
	if (r.Principal == nil) != (right.Principal == nil) {
		return false
	}
	if r.Principal != nil && *r.Principal != *right.Principal {
		return false
	}
	return r.Labels.Equivalent(right.Labels)
}
func (left *Resource_DiskInfo) Equivalent(right *Resource_DiskInfo) bool {
	if (left == nil) != (right == nil) {
		return false
	}
	if a, b := left.GetSource(), right.GetSource(); (a == nil) != (b == nil) {
		return false
	} else if a != nil {
		if a.GetType() != b.GetType() {
			return false
		}
		if aa, bb := a.GetMount(), b.GetMount(); (aa == nil) != (bb == nil) {
			return false
		} else if aa.GetRoot() != bb.GetRoot() {
			return false
		}
		if aa, bb := a.GetPath(), b.GetPath(); (aa == nil) != (bb == nil) {
			return false
		} else if aa.GetRoot() != bb.GetRoot() {
			return false
		}
		if aa, bb := a.GetID(), b.GetID(); aa != bb {
			return false
		}
		if aa, bb := a.GetProfile(), b.GetProfile(); aa != bb {
			return false
		}
		if aa, bb := a.GetVendor(), b.GetVendor(); aa != bb {
			return false
		}
		if aa, bb := a.GetMetadata(), b.GetMetadata(); (aa == nil) != (bb == nil) {
			return false
		} else if !labelList(aa.GetLabels()).Equivalent(labelList(bb.GetLabels())) {
			return false
		}
	}
	if a, b := left.GetPersistence(), right.GetPersistence(); (a == nil) != (b == nil) {
		return false
	} else if a != nil {
		return a.GetID() == b.GetID()
	}
	return true
}
func (left *Resource) Equivalent(right Resource) bool {
	if left == nil {
		return right.IsEmpty()
	}
	if left.GetName() != right.GetName() ||
		left.GetType() != right.GetType() ||
		left.GetRole() != right.GetRole() {
		return false
	}
	if a, b := left.GetAllocationInfo(), right.GetAllocationInfo(); !a.Equivalent(b) {
		return false
	}
	if a, b := left.GetReservations(), right.GetReservations(); len(a) != len(b) {
		return false
	} else {
		for i := range a {
			ri := &a[i]
			if !ri.Equivalent(&b[i]) {
				return false
			}
		}
	}
	if !left.GetReservation().Equivalent(right.GetReservation()) {
		return false
	}
	if !left.GetDisk().Equivalent(right.GetDisk()) {
		return false
	}
	if (left.Revocable == nil) != (right.Revocable == nil) {
		return false
	}
	if a, b := left.ProviderID, right.ProviderID; (a == nil) != (b == nil) {
		return false
	} else if a != nil && a.Value != b.Value {
		return false
	}
	if a, b := left.Shared, right.Shared; (a == nil) != (b == nil) {
		return false
	}
	switch left.GetType() {
	case SCALAR:
		return left.GetScalar().Compare(right.GetScalar()) == 0
	case RANGES:
		return Ranges(left.GetRanges().GetRange()).Equivalent(right.GetRanges().GetRange())
	case SET:
		return left.GetSet().Compare(right.GetSet()) == 0
	default:
		return false
	}
}
func (left *Resource) Addable(right Resource) bool {
	if left == nil {
		return true
	}
	if left.GetName() != right.GetName() ||
		left.GetType() != right.GetType() {
		return false
	}
	if !IsCapabilityReservationRefinementEnabled() && left.GetRole() != right.GetRole() {
		return false
	}
	if a, b := left.GetShared(), right.GetShared(); (a == nil) != (b == nil) {
		return false
	} else if a != nil {
		return left.Equivalent(right)
	}
	if a, b := left.GetAllocationInfo(), right.GetAllocationInfo(); !a.Equivalent(b) {
		return false
	}
	if !left.GetReservation().Equivalent(right.GetReservation()) {
		return false
	}
	if a, b := left.Reservations, right.Reservations; len(a) != len(b) {
		return false
	} else {
		for i := range a {
			aa := &a[i]
			if !aa.Equivalent(&b[i]) {
				return false
			}
		}
	}
	if !left.GetDisk().Equivalent(right.GetDisk()) {
		return false
	}
	if ls := left.GetDisk().GetSource(); ls != nil {
		switch ls.GetType() {
		case Resource_DiskInfo_Source_PATH:
		case Resource_DiskInfo_Source_BLOCK,
			Resource_DiskInfo_Source_MOUNT:
			return false
		case Resource_DiskInfo_Source_RAW:
			if ls.GetID() != "" {
				return false
			}
		case Resource_DiskInfo_Source_UNKNOWN:
			panic("unreachable")
		}
	}
	if left.GetDisk().GetPersistence() != nil {
		return false
	}
	if (left.GetRevocable() == nil) != (right.GetRevocable() == nil) {
		return false
	}
	if a, b := left.GetProviderID(), right.GetProviderID(); (a == nil) != (b == nil) {
		return false
	} else if a != nil && a.Value != b.Value {
		return false
	}
	return true
}
func (left *Resource) Subtractable(right Resource) bool {
	if left.GetName() != right.GetName() ||
		left.GetType() != right.GetType() {
		return false
	}
	if !IsCapabilityReservationRefinementEnabled() && left.GetRole() != right.GetRole() {
		return false
	}
	if a, b := left.GetShared(), right.GetShared(); (a == nil) != (b == nil) {
		return false
	} else if a != nil {
		return left.Equivalent(right)
	}
	if a, b := left.GetAllocationInfo(), right.GetAllocationInfo(); !a.Equivalent(b) {
		return false
	}
	if !left.GetReservation().Equivalent(right.GetReservation()) {
		return false
	}
	if a, b := left.Reservations, right.Reservations; len(a) != len(b) {
		return false
	} else {
		for i := range a {
			aa := &a[i]
			if !aa.Equivalent(&b[i]) {
				return false
			}
		}
	}
	if !left.GetDisk().Equivalent(right.GetDisk()) {
		return false
	}
	if ls := left.GetDisk().GetSource(); ls != nil {
		switch ls.GetType() {
		case Resource_DiskInfo_Source_PATH:
		case Resource_DiskInfo_Source_BLOCK,
			Resource_DiskInfo_Source_MOUNT:
			if !left.Equivalent(right) {
				return false
			}
		case Resource_DiskInfo_Source_RAW:
			if ls.GetID() != "" && !left.Equivalent(right) {
				return false
			}
		case Resource_DiskInfo_Source_UNKNOWN:
			panic("unreachable")
		}
	}
	if left.GetDisk().GetPersistence() != nil && !left.Equivalent(right) {
		return false
	}
	if (left.GetRevocable() == nil) != (right.GetRevocable() == nil) {
		return false
	}
	if a, b := left.GetProviderID(), right.GetProviderID(); (a == nil) != (b == nil) {
		return false
	} else if a != nil && a.Value != b.Value {
		return false
	}
	return true
}
func (left Resource) Contains(right Resource) bool {
	if !left.Subtractable(right) {
		return false
	}
	switch left.GetType() {
	case SCALAR:
		return right.GetScalar().Compare(left.GetScalar()) <= 0
	case RANGES:
		return right.GetRanges().Compare(left.GetRanges()) <= 0
	case SET:
		return right.GetSet().Compare(left.GetSet()) <= 0
	default:
		return false
	}
}
func (left *Resource) Subtract(right Resource) {
	switch right.checkType(left.GetType()) {
	case SCALAR:
		left.Scalar = left.GetScalar().Subtract(right.GetScalar())
	case RANGES:
		left.Ranges = left.GetRanges().Subtract(right.GetRanges())
	case SET:
		left.Set = left.GetSet().Subtract(right.GetSet())
	}
}
func (left *Resource) Add(right Resource) {
	switch right.checkType(left.GetType()) {
	case SCALAR:
		left.Scalar = left.GetScalar().Add(right.GetScalar())
	case RANGES:
		left.Ranges = left.GetRanges().Add(right.GetRanges())
	case SET:
		left.Set = left.GetSet().Add(right.GetSet())
	}
}