ReasonForError

// ReasonForError returns the HTTP status for a particular error.
// It supports wrapped errors and returns StatusReasonUnknown when
// the error is nil or doesn't have a status.
func ReasonForError(err error) metav1.StatusReason {
	if status, ok := err.(APIStatus); ok || errors.As(err, &status) {
		return status.Status().Reason
	}
	return metav1.StatusReasonUnknown
}


reasonAndCodeForError

func reasonAndCodeForError(err error) (metav1.StatusReason, int32) {
	if status, ok := err.(APIStatus); ok || errors.As(err, &status) {
		return status.Status().Reason, status.Status().Code
	}
	return metav1.StatusReasonUnknown, 0
}


NewClientErrorReporter

// NewClientErrorReporter will respond with valid v1.Status objects that report
// unexpected server responses. Primarily used by watch to report errors when
// we attempt to decode a response from the server and it is not in the form
// we expect. Because watch is a dependency of the core api, we can't return
// meta/v1.Status in that package and so much inject this interface to convert a
// generic error as appropriate. The reason is passed as a unique status cause
// on the returned status, otherwise the generic "ClientError" is returned.
func NewClientErrorReporter(code int, verb string, reason string) *ErrorReporter {
	return &ErrorReporter{
		code:   code,
		verb:   verb,
		reason: reason,
	}
}


AsObject

// AsObject returns a valid error runtime.Object (a v1.Status) for the given
// error, using the code and verb of the reporter type. The error is set to
// indicate that this was an unexpected server response.
func (r *ErrorReporter) AsObject(err error) runtime.Object {
	status := NewGenericServerResponse(r.code, r.verb, schema.GroupResource{}, "", err.Error(), 0, true)
	if status.ErrStatus.Details == nil {
		status.ErrStatus.Details = &metav1.StatusDetails{}
	}
	reason := r.reason
	if len(reason) == 0 {
		reason = "ClientError"
	}
	status.ErrStatus.Details.Causes = append(status.ErrStatus.Details.Causes, metav1.StatusCause{
		Type:    metav1.CauseType(reason),
		Message: err.Error(),
	})
	return &status.ErrStatus
}


SetStatusCondition

// SetStatusCondition sets the corresponding condition in conditions to newCondition.
// conditions must be non-nil.
//  1. if the condition of the specified type already exists (all fields of the existing condition are updated to
//     newCondition, LastTransitionTime is set to now if the new status differs from the old status)
//  2. if a condition of the specified type does not exist (LastTransitionTime is set to now() if unset, and newCondition is appended)
func SetStatusCondition(conditions *[]metav1.Condition, newCondition metav1.Condition) {
	if conditions == nil {
		return
	}
	existingCondition := FindStatusCondition(*conditions, newCondition.Type)
	if existingCondition == nil {
		if newCondition.LastTransitionTime.IsZero() {
			newCondition.LastTransitionTime = metav1.NewTime(time.Now())
		}
		*conditions = append(*conditions, newCondition)
		return
	}

	if existingCondition.Status != newCondition.Status {
		existingCondition.Status = newCondition.Status
		if !newCondition.LastTransitionTime.IsZero() {
			existingCondition.LastTransitionTime = newCondition.LastTransitionTime
		} else {
			existingCondition.LastTransitionTime = metav1.NewTime(time.Now())
		}
	}

	existingCondition.Reason = newCondition.Reason
	existingCondition.Message = newCondition.Message
	existingCondition.ObservedGeneration = newCondition.ObservedGeneration
}


RemoveStatusCondition

// RemoveStatusCondition removes the corresponding conditionType from conditions.
// conditions must be non-nil.
func RemoveStatusCondition(conditions *[]metav1.Condition, conditionType string) {
	if conditions == nil || len(*conditions) == 0 {
		return
	}
	newConditions := make([]metav1.Condition, 0, len(*conditions)-1)
	for _, condition := range *conditions {
		if condition.Type != conditionType {
			newConditions = append(newConditions, condition)
		}
	}

	*conditions = newConditions
}


FindStatusCondition

// FindStatusCondition finds the conditionType in conditions.
func FindStatusCondition(conditions []metav1.Condition, conditionType string) *metav1.Condition {
	for i := range conditions {
		if conditions[i].Type == conditionType {
			return &conditions[i]
		}
	}

	return nil
}


IsStatusConditionTrue

// IsStatusConditionTrue returns true when the conditionType is present and set to `metav1.ConditionTrue`
func IsStatusConditionTrue(conditions []metav1.Condition, conditionType string) bool {
	return IsStatusConditionPresentAndEqual(conditions, conditionType, metav1.ConditionTrue)
}


IsStatusConditionFalse

// IsStatusConditionFalse returns true when the conditionType is present and set to `metav1.ConditionFalse`
func IsStatusConditionFalse(conditions []metav1.Condition, conditionType string) bool {
	return IsStatusConditionPresentAndEqual(conditions, conditionType, metav1.ConditionFalse)
}


IsStatusConditionPresentAndEqual

// IsStatusConditionPresentAndEqual returns true when conditionType is present and equal to status.
func IsStatusConditionPresentAndEqual(conditions []metav1.Condition, conditionType string, status metav1.ConditionStatus) bool {
	for _, condition := range conditions {
		if condition.Type == conditionType {
			return condition.Status == status
		}
	}
	return false
}


Error

func (e *AmbiguousResourceError) Error() string {
	switch {
	case len(e.MatchingKinds) > 0 && len(e.MatchingResources) > 0:
		return fmt.Sprintf("%v matches multiple resources %v and kinds %v", e.PartialResource, e.MatchingResources, e.MatchingKinds)
	case len(e.MatchingKinds) > 0:
		return fmt.Sprintf("%v matches multiple kinds %v", e.PartialResource, e.MatchingKinds)
	case len(e.MatchingResources) > 0:
		return fmt.Sprintf("%v matches multiple resources %v", e.PartialResource, e.MatchingResources)
	}
	return fmt.Sprintf("%v matches multiple resources or kinds", e.PartialResource)
}


Is

func (*AmbiguousResourceError) Is(target error) bool {
	_, ok := target.(*AmbiguousResourceError)
	return ok
}


Error

func (e *AmbiguousKindError) Error() string {
	switch {
	case len(e.MatchingKinds) > 0 && len(e.MatchingResources) > 0:
		return fmt.Sprintf("%v matches multiple resources %v and kinds %v", e.PartialKind, e.MatchingResources, e.MatchingKinds)
	case len(e.MatchingKinds) > 0:
		return fmt.Sprintf("%v matches multiple kinds %v", e.PartialKind, e.MatchingKinds)
	case len(e.MatchingResources) > 0:
		return fmt.Sprintf("%v matches multiple resources %v", e.PartialKind, e.MatchingResources)
	}
	return fmt.Sprintf("%v matches multiple resources or kinds", e.PartialKind)
}


Is

func (*AmbiguousKindError) Is(target error) bool {
	_, ok := target.(*AmbiguousKindError)
	return ok
}


IsAmbiguousError

func IsAmbiguousError(err error) bool {
	if err == nil {
		return false
	}
	return errors.Is(err, &AmbiguousResourceError{}) || errors.Is(err, &AmbiguousKindError{})
}


Error

func (e *NoResourceMatchError) Error() string {
	return fmt.Sprintf("no matches for %v", e.PartialResource)
}


Is

func (*NoResourceMatchError) Is(target error) bool {
	_, ok := target.(*NoResourceMatchError)
	return ok
}


Error

func (e *NoKindMatchError) Error() string {
	searchedVersions := sets.NewString()
	for _, v := range e.SearchedVersions {
		searchedVersions.Insert(schema.GroupVersion{Group: e.GroupKind.Group, Version: v}.String())
	}

	switch len(searchedVersions) {
	case 0:
		return fmt.Sprintf("no matches for kind %q in group %q", e.GroupKind.Kind, e.GroupKind.Group)
	case 1:
		return fmt.Sprintf("no matches for kind %q in version %q", e.GroupKind.Kind, searchedVersions.List()[0])
	default:
		return fmt.Sprintf("no matches for kind %q in versions %q", e.GroupKind.Kind, searchedVersions.List())
	}
}


Is

func (*NoKindMatchError) Is(target error) bool {
	_, ok := target.(*NoKindMatchError)
	return ok
}


IsNoMatchError

func IsNoMatchError(err error) bool {
	if err == nil {
		return false
	}
	return errors.Is(err, &NoResourceMatchError{}) || errors.Is(err, &NoKindMatchError{})
}


String

func (m FirstHitRESTMapper) String() string {
	return fmt.Sprintf("FirstHitRESTMapper{\n\t%v\n}", m.MultiRESTMapper)
}


ResourceFor

func (m FirstHitRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
	errors := []error{}
	for _, t := range m.MultiRESTMapper {
		ret, err := t.ResourceFor(resource)
		if err == nil {
			return ret, nil
		}
		errors = append(errors, err)
	}

	return schema.GroupVersionResource{}, collapseAggregateErrors(errors)
}


KindFor

func (m FirstHitRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
	errors := []error{}
	for _, t := range m.MultiRESTMapper {
		ret, err := t.KindFor(resource)
		if err == nil {
			return ret, nil
		}
		errors = append(errors, err)
	}

	return schema.GroupVersionKind{}, collapseAggregateErrors(errors)
}


RESTMapping

// RESTMapping provides the REST mapping for the resource based on the
// kind and version. This implementation supports multiple REST schemas and
// return the first match.
func (m FirstHitRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
	errors := []error{}
	for _, t := range m.MultiRESTMapper {
		ret, err := t.RESTMapping(gk, versions...)
		if err == nil {
			return ret, nil
		}
		errors = append(errors, err)
	}

	return nil, collapseAggregateErrors(errors)
}


Reset

func (m FirstHitRESTMapper) Reset() {
	m.MultiRESTMapper.Reset()
}


collapseAggregateErrors

// collapseAggregateErrors returns the minimal errors.  it handles empty as nil, handles one item in a list
// by returning the item, and collapses all NoMatchErrors to a single one (since they should all be the same)
func collapseAggregateErrors(errors []error) error {
	if len(errors) == 0 {
		return nil
	}
	if len(errors) == 1 {
		return errors[0]
	}

	allNoMatchErrors := true
	for _, err := range errors {
		allNoMatchErrors = allNoMatchErrors && IsNoMatchError(err)
	}
	if allNoMatchErrors {
		return errors[0]
	}

	return utilerrors.NewAggregate(errors)
}


IsListType

// IsListType returns true if the provided Object has a slice called Items.
// TODO: Replace the code in this check with an interface comparison by
// creating and enforcing that lists implement a list accessor.
func IsListType(obj runtime.Object) bool {
	switch t := obj.(type) {
	case runtime.Unstructured:
		return t.IsList()
	}
	t := reflect.TypeOf(obj)

	isListCache.lock.RLock()
	ok, exists := isListCache.byType[t]
	isListCache.lock.RUnlock()

	if !exists {
		_, err := getItemsPtr(obj)
		ok = err == nil

		// cache only the first 1024 types
		isListCache.lock.Lock()
		if len(isListCache.byType) < 1024 {
			isListCache.byType[t] = ok
		}
		isListCache.lock.Unlock()
	}

	return ok
}


GetItemsPtr

// GetItemsPtr returns a pointer to the list object's Items member.
// If 'list' doesn't have an Items member, it's not really a list type
// and an error will be returned.
// This function will either return a pointer to a slice, or an error, but not both.
// TODO: this will be replaced with an interface in the future
func GetItemsPtr(list runtime.Object) (interface{}, error) {
	obj, err := getItemsPtr(list)
	if err != nil {
		return nil, fmt.Errorf("%T is not a list: %v", list, err)
	}
	return obj, nil
}


getItemsPtr

// getItemsPtr returns a pointer to the list object's Items member or an error.
func getItemsPtr(list runtime.Object) (interface{}, error) {
	v, err := conversion.EnforcePtr(list)
	if err != nil {
		return nil, err
	}

	items := v.FieldByName("Items")
	if !items.IsValid() {
		return nil, errExpectFieldItems
	}
	switch items.Kind() {
	case reflect.Interface, reflect.Pointer:
		target := reflect.TypeOf(items.Interface()).Elem()
		if target.Kind() != reflect.Slice {
			return nil, errExpectSliceItems
		}
		return items.Interface(), nil
	case reflect.Slice:
		return items.Addr().Interface(), nil
	default:
		return nil, errExpectSliceItems
	}
}


EachListItem

// EachListItem invokes fn on each runtime.Object in the list. Any error immediately terminates
// the loop.
func EachListItem(obj runtime.Object, fn func(runtime.Object) error) error {
	if unstructured, ok := obj.(runtime.Unstructured); ok {
		return unstructured.EachListItem(fn)
	}
	// TODO: Change to an interface call?
	itemsPtr, err := GetItemsPtr(obj)
	if err != nil {
		return err
	}
	items, err := conversion.EnforcePtr(itemsPtr)
	if err != nil {
		return err
	}
	len := items.Len()
	if len == 0 {
		return nil
	}
	takeAddr := false
	if elemType := items.Type().Elem(); elemType.Kind() != reflect.Pointer && elemType.Kind() != reflect.Interface {
		if !items.Index(0).CanAddr() {
			return fmt.Errorf("unable to take address of items in %T for EachListItem", obj)
		}
		takeAddr = true
	}

	for i := 0; i < len; i++ {
		raw := items.Index(i)
		if takeAddr {
			raw = raw.Addr()
		}
		switch item := raw.Interface().(type) {
		case *runtime.RawExtension:
			if err := fn(item.Object); err != nil {
				return err
			}
		case runtime.Object:
			if err := fn(item); err != nil {
				return err
			}
		default:
			obj, ok := item.(runtime.Object)
			if !ok {
				return fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
			}
			if err := fn(obj); err != nil {
				return err
			}
		}
	}
	return nil
}


ExtractList

// ExtractList returns obj's Items element as an array of runtime.Objects.
// Returns an error if obj is not a List type (does not have an Items member).
func ExtractList(obj runtime.Object) ([]runtime.Object, error) {
	itemsPtr, err := GetItemsPtr(obj)
	if err != nil {
		return nil, err
	}
	items, err := conversion.EnforcePtr(itemsPtr)
	if err != nil {
		return nil, err
	}
	list := make([]runtime.Object, items.Len())
	for i := range list {
		raw := items.Index(i)
		switch item := raw.Interface().(type) {
		case runtime.RawExtension:
			switch {
			case item.Object != nil:
				list[i] = item.Object
			case item.Raw != nil:
				// TODO: Set ContentEncoding and ContentType correctly.
				list[i] = &runtime.Unknown{Raw: item.Raw}
			default:
				list[i] = nil
			}
		case runtime.Object:
			list[i] = item
		default:
			var found bool
			if list[i], found = raw.Addr().Interface().(runtime.Object); !found {
				return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
			}
		}
	}
	return list, nil
}


LenList

// LenList returns the length of this list or 0 if it is not a list.
func LenList(list runtime.Object) int {
	itemsPtr, err := GetItemsPtr(list)
	if err != nil {
		return 0
	}
	items, err := conversion.EnforcePtr(itemsPtr)
	if err != nil {
		return 0
	}
	return items.Len()
}


SetList

// SetList sets the given list object's Items member have the elements given in
// objects.
// Returns an error if list is not a List type (does not have an Items member),
// or if any of the objects are not of the right type.
func SetList(list runtime.Object, objects []runtime.Object) error {
	itemsPtr, err := GetItemsPtr(list)
	if err != nil {
		return err
	}
	items, err := conversion.EnforcePtr(itemsPtr)
	if err != nil {
		return err
	}
	if items.Type() == objectSliceType {
		items.Set(reflect.ValueOf(objects))
		return nil
	}
	slice := reflect.MakeSlice(items.Type(), len(objects), len(objects))
	for i := range objects {
		dest := slice.Index(i)
		if dest.Type() == reflect.TypeOf(runtime.RawExtension{}) {
			dest = dest.FieldByName("Object")
		}

		// check to see if you're directly assignable
		if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
			dest.Set(reflect.ValueOf(objects[i]))
			continue
		}

		src, err := conversion.EnforcePtr(objects[i])
		if err != nil {
			return err
		}
		if src.Type().AssignableTo(dest.Type()) {
			dest.Set(src)
		} else if src.Type().ConvertibleTo(dest.Type()) {
			dest.Set(src.Convert(dest.Type()))
		} else {
			return fmt.Errorf("item[%d]: can't assign or convert %v into %v", i, src.Type(), dest.Type())
		}
	}
	items.Set(slice)
	return nil
}


NewLazyRESTMapperLoader

// NewLazyRESTMapperLoader handles unrecoverable errors when creating a RESTMapper / ObjectTyper by
// returning those initialization errors when the interface methods are invoked. This defers the
// initialization and any server calls until a client actually needs to perform the action.
func NewLazyRESTMapperLoader(fn func() (RESTMapper, error)) RESTMapper {
	obj := &lazyObject{loader: fn}
	return obj
}


init

// init lazily loads the mapper and typer, returning an error if initialization has failed.
func (o *lazyObject) init() error {
	o.lock.Lock()
	defer o.lock.Unlock()
	if o.loaded {
		return o.err
	}
	o.mapper, o.err = o.loader()
	o.loaded = true
	return o.err
}


KindFor

func (o *lazyObject) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
	if err := o.init(); err != nil {
		return schema.GroupVersionKind{}, err
	}
	return o.mapper.KindFor(resource)
}


KindsFor

func (o *lazyObject) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
	if err := o.init(); err != nil {
		return []schema.GroupVersionKind{}, err
	}
	return o.mapper.KindsFor(resource)
}


ResourceFor

func (o *lazyObject) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
	if err := o.init(); err != nil {
		return schema.GroupVersionResource{}, err
	}
	return o.mapper.ResourceFor(input)
}


ResourcesFor

func (o *lazyObject) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
	if err := o.init(); err != nil {
		return []schema.GroupVersionResource{}, err
	}
	return o.mapper.ResourcesFor(input)
}


RESTMapping

func (o *lazyObject) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
	if err := o.init(); err != nil {
		return nil, err
	}
	return o.mapper.RESTMapping(gk, versions...)
}


RESTMappings

func (o *lazyObject) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
	if err := o.init(); err != nil {
		return nil, err
	}
	return o.mapper.RESTMappings(gk, versions...)
}


ResourceSingularizer

func (o *lazyObject) ResourceSingularizer(resource string) (singular string, err error) {
	if err := o.init(); err != nil {
		return "", err
	}
	return o.mapper.ResourceSingularizer(resource)
}


Reset

func (o *lazyObject) Reset() {
	o.lock.Lock()
	defer o.lock.Unlock()
	if o.loaded && o.err == nil {
		MaybeResetRESTMapper(o.mapper)
	}
}


CommonAccessor

// CommonAccessor returns a Common interface for the provided object or an error if the object does
// not provide List.
func CommonAccessor(obj interface{}) (metav1.Common, error) {
	switch t := obj.(type) {
	case List:
		return t, nil
	case ListMetaAccessor:
		if m := t.GetListMeta(); m != nil {
			return m, nil
		}
		return nil, errNotCommon
	case metav1.ListMetaAccessor:
		if m := t.GetListMeta(); m != nil {
			return m, nil
		}
		return nil, errNotCommon
	case metav1.Object:
		return t, nil
	case metav1.ObjectMetaAccessor:
		if m := t.GetObjectMeta(); m != nil {
			return m, nil
		}
		return nil, errNotCommon
	default:
		return nil, errNotCommon
	}
}


ListAccessor

// ListAccessor returns a List interface for the provided object or an error if the object does
// not provide List.
// IMPORTANT: Objects are NOT a superset of lists. Do not use this check to determine whether an
// object *is* a List.
func ListAccessor(obj interface{}) (List, error) {
	switch t := obj.(type) {
	case List:
		return t, nil
	case ListMetaAccessor:
		if m := t.GetListMeta(); m != nil {
			return m, nil
		}
		return nil, errNotList
	case metav1.ListMetaAccessor:
		if m := t.GetListMeta(); m != nil {
			return m, nil
		}
		return nil, errNotList
	default:
		return nil, errNotList
	}
}


Accessor

// Accessor takes an arbitrary object pointer and returns meta.Interface.
// obj must be a pointer to an API type. An error is returned if the minimum
// required fields are missing. Fields that are not required return the default
// value and are a no-op if set.
func Accessor(obj interface{}) (metav1.Object, error) {
	switch t := obj.(type) {
	case metav1.Object:
		return t, nil
	case metav1.ObjectMetaAccessor:
		if m := t.GetObjectMeta(); m != nil {
			return m, nil
		}
		return nil, errNotObject
	default:
		return nil, errNotObject
	}
}


AsPartialObjectMetadata

// AsPartialObjectMetadata takes the metav1 interface and returns a partial object.
// TODO: consider making this solely a conversion action.
func AsPartialObjectMetadata(m metav1.Object) *metav1.PartialObjectMetadata {
	switch t := m.(type) {
	case *metav1.ObjectMeta:
		return &metav1.PartialObjectMetadata{ObjectMeta: *t}
	default:
		return &metav1.PartialObjectMetadata{
			ObjectMeta: metav1.ObjectMeta{
				Name:                       m.GetName(),
				GenerateName:               m.GetGenerateName(),
				Namespace:                  m.GetNamespace(),
				SelfLink:                   m.GetSelfLink(),
				UID:                        m.GetUID(),
				ResourceVersion:            m.GetResourceVersion(),
				Generation:                 m.GetGeneration(),
				CreationTimestamp:          m.GetCreationTimestamp(),
				DeletionTimestamp:          m.GetDeletionTimestamp(),
				DeletionGracePeriodSeconds: m.GetDeletionGracePeriodSeconds(),
				Labels:                     m.GetLabels(),
				Annotations:                m.GetAnnotations(),
				OwnerReferences:            m.GetOwnerReferences(),
				Finalizers:                 m.GetFinalizers(),
				ManagedFields:              m.GetManagedFields(),
			},
		}
	}
}


TypeAccessor

// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
// and Kind of an in-memory internal object.
// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
// api conventions).
func TypeAccessor(obj interface{}) (Type, error) {
	if typed, ok := obj.(runtime.Object); ok {
		return objectAccessor{typed}, nil
	}
	v, err := conversion.EnforcePtr(obj)
	if err != nil {
		return nil, err
	}
	t := v.Type()
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
	}

	typeMeta := v.FieldByName("TypeMeta")
	if !typeMeta.IsValid() {
		return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
	}
	a := &genericAccessor{}
	if err := extractFromTypeMeta(typeMeta, a); err != nil {
		return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
	}
	return a, nil
}


GetKind

func (obj objectAccessor) GetKind() string {
	return obj.GetObjectKind().GroupVersionKind().Kind
}


SetKind

func (obj objectAccessor) SetKind(kind string) {
	gvk := obj.GetObjectKind().GroupVersionKind()
	gvk.Kind = kind
	obj.GetObjectKind().SetGroupVersionKind(gvk)
}


GetAPIVersion

func (obj objectAccessor) GetAPIVersion() string {
	return obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
}


SetAPIVersion

func (obj objectAccessor) SetAPIVersion(version string) {
	gvk := obj.GetObjectKind().GroupVersionKind()
	gv, err := schema.ParseGroupVersion(version)
	if err != nil {
		gv = schema.GroupVersion{Version: version}
	}
	gvk.Group, gvk.Version = gv.Group, gv.Version
	obj.GetObjectKind().SetGroupVersionKind(gvk)
}


NewAccessor

// NewAccessor returns a MetadataAccessor that can retrieve
// or manipulate resource version on objects derived from core API
// metadata concepts.
func NewAccessor() MetadataAccessor {
	return resourceAccessor{}
}


Kind

func (resourceAccessor) Kind(obj runtime.Object) (string, error) {
	return objectAccessor{obj}.GetKind(), nil
}


SetKind

func (resourceAccessor) SetKind(obj runtime.Object, kind string) error {
	objectAccessor{obj}.SetKind(kind)
	return nil
}


APIVersion

func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) {
	return objectAccessor{obj}.GetAPIVersion(), nil
}


SetAPIVersion

func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error {
	objectAccessor{obj}.SetAPIVersion(version)
	return nil
}


Namespace

func (resourceAccessor) Namespace(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetNamespace(), nil
}


SetNamespace

func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetNamespace(namespace)
	return nil
}


Name

func (resourceAccessor) Name(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetName(), nil
}


SetName

func (resourceAccessor) SetName(obj runtime.Object, name string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetName(name)
	return nil
}


GenerateName

func (resourceAccessor) GenerateName(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetGenerateName(), nil
}


SetGenerateName

func (resourceAccessor) SetGenerateName(obj runtime.Object, name string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetGenerateName(name)
	return nil
}


UID

func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetUID(), nil
}


SetUID

func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetUID(uid)
	return nil
}


SelfLink

func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) {
	accessor, err := CommonAccessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetSelfLink(), nil
}


SetSelfLink

func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error {
	accessor, err := CommonAccessor(obj)
	if err != nil {
		return err
	}
	accessor.SetSelfLink(selfLink)
	return nil
}


Labels

func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return nil, err
	}
	return accessor.GetLabels(), nil
}


SetLabels

func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetLabels(labels)
	return nil
}


Annotations

func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return nil, err
	}
	return accessor.GetAnnotations(), nil
}


SetAnnotations

func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetAnnotations(annotations)
	return nil
}


ResourceVersion

func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) {
	accessor, err := CommonAccessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetResourceVersion(), nil
}


SetResourceVersion

func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error {
	accessor, err := CommonAccessor(obj)
	if err != nil {
		return err
	}
	accessor.SetResourceVersion(version)
	return nil
}


Continue

func (resourceAccessor) Continue(obj runtime.Object) (string, error) {
	accessor, err := ListAccessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.GetContinue(), nil
}


SetContinue

func (resourceAccessor) SetContinue(obj runtime.Object, version string) error {
	accessor, err := ListAccessor(obj)
	if err != nil {
		return err
	}
	accessor.SetContinue(version)
	return nil
}


extractFromOwnerReference

// extractFromOwnerReference extracts v to o. v is the OwnerReferences field of an object.
func extractFromOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
	if err := runtime.Field(v, "APIVersion", &o.APIVersion); err != nil {
		return err
	}
	if err := runtime.Field(v, "Kind", &o.Kind); err != nil {
		return err
	}
	if err := runtime.Field(v, "Name", &o.Name); err != nil {
		return err
	}
	if err := runtime.Field(v, "UID", &o.UID); err != nil {
		return err
	}
	var controllerPtr *bool
	if err := runtime.Field(v, "Controller", &controllerPtr); err != nil {
		return err
	}
	if controllerPtr != nil {
		controller := *controllerPtr
		o.Controller = &controller
	}
	var blockOwnerDeletionPtr *bool
	if err := runtime.Field(v, "BlockOwnerDeletion", &blockOwnerDeletionPtr); err != nil {
		return err
	}
	if blockOwnerDeletionPtr != nil {
		block := *blockOwnerDeletionPtr
		o.BlockOwnerDeletion = &block
	}
	return nil
}


setOwnerReference

// setOwnerReference sets v to o. v is the OwnerReferences field of an object.
func setOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
	if err := runtime.SetField(o.APIVersion, v, "APIVersion"); err != nil {
		return err
	}
	if err := runtime.SetField(o.Kind, v, "Kind"); err != nil {
		return err
	}
	if err := runtime.SetField(o.Name, v, "Name"); err != nil {
		return err
	}
	if err := runtime.SetField(o.UID, v, "UID"); err != nil {
		return err
	}
	if o.Controller != nil {
		controller := *(o.Controller)
		if err := runtime.SetField(&controller, v, "Controller"); err != nil {
			return err
		}
	}
	if o.BlockOwnerDeletion != nil {
		block := *(o.BlockOwnerDeletion)
		if err := runtime.SetField(&block, v, "BlockOwnerDeletion"); err != nil {
			return err
		}
	}
	return nil
}


GetNamespace

func (a genericAccessor) GetNamespace() string {
	if a.namespace == nil {
		return ""
	}
	return *a.namespace
}


SetNamespace

func (a genericAccessor) SetNamespace(namespace string) {
	if a.namespace == nil {
		return
	}
	*a.namespace = namespace
}


GetName

func (a genericAccessor) GetName() string {
	if a.name == nil {
		return ""
	}
	return *a.name
}


SetName

func (a genericAccessor) SetName(name string) {
	if a.name == nil {
		return
	}
	*a.name = name
}


GetGenerateName

func (a genericAccessor) GetGenerateName() string {
	if a.generateName == nil {
		return ""
	}
	return *a.generateName
}


SetGenerateName

func (a genericAccessor) SetGenerateName(generateName string) {
	if a.generateName == nil {
		return
	}
	*a.generateName = generateName
}


GetUID

func (a genericAccessor) GetUID() types.UID {
	if a.uid == nil {
		return ""
	}
	return *a.uid
}


SetUID

func (a genericAccessor) SetUID(uid types.UID) {
	if a.uid == nil {
		return
	}
	*a.uid = uid
}


GetAPIVersion

func (a genericAccessor) GetAPIVersion() string {
	return *a.apiVersion
}


SetAPIVersion

func (a genericAccessor) SetAPIVersion(version string) {
	*a.apiVersion = version
}


GetKind

func (a genericAccessor) GetKind() string {
	return *a.kind
}


SetKind

func (a genericAccessor) SetKind(kind string) {
	*a.kind = kind
}


GetResourceVersion

func (a genericAccessor) GetResourceVersion() string {
	return *a.resourceVersion
}


SetResourceVersion

func (a genericAccessor) SetResourceVersion(version string) {
	*a.resourceVersion = version
}


GetSelfLink

func (a genericAccessor) GetSelfLink() string {
	return *a.selfLink
}


SetSelfLink

func (a genericAccessor) SetSelfLink(selfLink string) {
	*a.selfLink = selfLink
}


GetCreationTimestamp

func (a genericAccessor) GetCreationTimestamp() metav1.Time {
	return *a.creationTimestamp
}


SetCreationTimestamp

func (a genericAccessor) SetCreationTimestamp(timestamp metav1.Time) {
	*a.creationTimestamp = timestamp
}


GetDeletionTimestamp

func (a genericAccessor) GetDeletionTimestamp() *metav1.Time {
	return *a.deletionTimestamp
}


SetDeletionTimestamp

func (a genericAccessor) SetDeletionTimestamp(timestamp *metav1.Time) {
	*a.deletionTimestamp = timestamp
}


GetLabels

func (a genericAccessor) GetLabels() map[string]string {
	if a.labels == nil {
		return nil
	}
	return *a.labels
}


SetLabels

func (a genericAccessor) SetLabels(labels map[string]string) {
	*a.labels = labels
}


GetAnnotations

func (a genericAccessor) GetAnnotations() map[string]string {
	if a.annotations == nil {
		return nil
	}
	return *a.annotations
}


SetAnnotations

func (a genericAccessor) SetAnnotations(annotations map[string]string) {
	if a.annotations == nil {
		emptyAnnotations := make(map[string]string)
		a.annotations = &emptyAnnotations
	}
	*a.annotations = annotations
}


GetFinalizers

func (a genericAccessor) GetFinalizers() []string {
	if a.finalizers == nil {
		return nil
	}
	return *a.finalizers
}


SetFinalizers

func (a genericAccessor) SetFinalizers(finalizers []string) {
	*a.finalizers = finalizers
}


GetOwnerReferences

func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
	var ret []metav1.OwnerReference
	s := a.ownerReferences
	if s.Kind() != reflect.Pointer || s.Elem().Kind() != reflect.Slice {
		klog.Errorf("expect %v to be a pointer to slice", s)
		return ret
	}
	s = s.Elem()
	// Set the capacity to one element greater to avoid copy if the caller later append an element.
	ret = make([]metav1.OwnerReference, s.Len(), s.Len()+1)
	for i := 0; i < s.Len(); i++ {
		if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil {
			klog.Errorf("extractFromOwnerReference failed: %v", err)
			return ret
		}
	}
	return ret
}


SetOwnerReferences

func (a genericAccessor) SetOwnerReferences(references []metav1.OwnerReference) {
	s := a.ownerReferences
	if s.Kind() != reflect.Pointer || s.Elem().Kind() != reflect.Slice {
		klog.Errorf("expect %v to be a pointer to slice", s)
	}
	s = s.Elem()
	newReferences := reflect.MakeSlice(s.Type(), len(references), len(references))
	for i := 0; i < len(references); i++ {
		if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil {
			klog.Errorf("setOwnerReference failed: %v", err)
			return
		}
	}
	s.Set(newReferences)
}


extractFromTypeMeta

// extractFromTypeMeta extracts pointers to version and kind fields from an object
func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil {
		return err
	}
	return nil
}


String

func (m MultiRESTMapper) String() string {
	nested := make([]string, 0, len(m))
	for _, t := range m {
		currString := fmt.Sprintf("%v", t)
		splitStrings := strings.Split(currString, "\n")
		nested = append(nested, strings.Join(splitStrings, "\n\t"))
	}

	return fmt.Sprintf("MultiRESTMapper{\n\t%s\n}", strings.Join(nested, "\n\t"))
}


ResourceSingularizer

// ResourceSingularizer converts a REST resource name from plural to singular (e.g., from pods to pod)
// This implementation supports multiple REST schemas and return the first match.
func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
	for _, t := range m {
		singular, err = t.ResourceSingularizer(resource)
		if err == nil {
			return
		}
	}
	return
}


ResourcesFor

func (m MultiRESTMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
	allGVRs := []schema.GroupVersionResource{}
	for _, t := range m {
		gvrs, err := t.ResourcesFor(resource)
		// ignore "no match" errors, but any other error percolates back up
		if IsNoMatchError(err) {
			continue
		}
		if err != nil {
			return nil, err
		}

		// walk the existing values to de-dup
		for _, curr := range gvrs {
			found := false
			for _, existing := range allGVRs {
				if curr == existing {
					found = true
					break
				}
			}

			if !found {
				allGVRs = append(allGVRs, curr)
			}
		}
	}

	if len(allGVRs) == 0 {
		return nil, &NoResourceMatchError{PartialResource: resource}
	}

	return allGVRs, nil
}


KindsFor

func (m MultiRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
	allGVKs := []schema.GroupVersionKind{}
	for _, t := range m {
		gvks, err := t.KindsFor(resource)
		// ignore "no match" errors, but any other error percolates back up
		if IsNoMatchError(err) {
			continue
		}
		if err != nil {
			return nil, err
		}

		// walk the existing values to de-dup
		for _, curr := range gvks {
			found := false
			for _, existing := range allGVKs {
				if curr == existing {
					found = true
					break
				}
			}

			if !found {
				allGVKs = append(allGVKs, curr)
			}
		}
	}

	if len(allGVKs) == 0 {
		return nil, &NoResourceMatchError{PartialResource: resource}
	}

	return allGVKs, nil
}


ResourceFor

func (m MultiRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
	resources, err := m.ResourcesFor(resource)
	if err != nil {
		return schema.GroupVersionResource{}, err
	}
	if len(resources) == 1 {
		return resources[0], nil
	}

	return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources}
}


KindFor

func (m MultiRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
	kinds, err := m.KindsFor(resource)
	if err != nil {
		return schema.GroupVersionKind{}, err
	}
	if len(kinds) == 1 {
		return kinds[0], nil
	}

	return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds}
}


RESTMapping

// RESTMapping provides the REST mapping for the resource based on the
// kind and version. This implementation supports multiple REST schemas and
// return the first match.
func (m MultiRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
	allMappings := []*RESTMapping{}
	errors := []error{}

	for _, t := range m {
		currMapping, err := t.RESTMapping(gk, versions...)
		// ignore "no match" errors, but any other error percolates back up
		if IsNoMatchError(err) {
			continue
		}
		if err != nil {
			errors = append(errors, err)
			continue
		}

		allMappings = append(allMappings, currMapping)
	}

	// if we got exactly one mapping, then use it even if other requested failed
	if len(allMappings) == 1 {
		return allMappings[0], nil
	}
	if len(allMappings) > 1 {
		var kinds []schema.GroupVersionKind
		for _, m := range allMappings {
			kinds = append(kinds, m.GroupVersionKind)
		}
		return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
	}
	if len(errors) > 0 {
		return nil, utilerrors.NewAggregate(errors)
	}
	return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
}


RESTMappings

// RESTMappings returns all possible RESTMappings for the provided group kind, or an error
// if the type is not recognized.
func (m MultiRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
	var allMappings []*RESTMapping
	var errors []error

	for _, t := range m {
		currMappings, err := t.RESTMappings(gk, versions...)
		// ignore "no match" errors, but any other error percolates back up
		if IsNoMatchError(err) {
			continue
		}
		if err != nil {
			errors = append(errors, err)
			continue
		}
		allMappings = append(allMappings, currMappings...)
	}
	if len(errors) > 0 {
		return nil, utilerrors.NewAggregate(errors)
	}
	if len(allMappings) == 0 {
		return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
	}
	return allMappings, nil
}


Reset

func (m MultiRESTMapper) Reset() {
	for _, t := range m {
		MaybeResetRESTMapper(t)
	}
}


String

func (m PriorityRESTMapper) String() string {
	return fmt.Sprintf("PriorityRESTMapper{\n\t%v\n\t%v\n\t%v\n}", m.ResourcePriority, m.KindPriority, m.Delegate)
}


ResourceFor

// ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit.
func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
	originalGVRs, originalErr := m.Delegate.ResourcesFor(partiallySpecifiedResource)
	if originalErr != nil && len(originalGVRs) == 0 {
		return schema.GroupVersionResource{}, originalErr
	}
	if len(originalGVRs) == 1 {
		return originalGVRs[0], originalErr
	}

	remainingGVRs := append([]schema.GroupVersionResource{}, originalGVRs...)
	for _, pattern := range m.ResourcePriority {
		matchedGVRs := []schema.GroupVersionResource{}
		for _, gvr := range remainingGVRs {
			if resourceMatches(pattern, gvr) {
				matchedGVRs = append(matchedGVRs, gvr)
			}
		}

		switch len(matchedGVRs) {
		case 0:
			// if you have no matches, then nothing matched this pattern just move to the next
			continue
		case 1:
			// one match, return
			return matchedGVRs[0], originalErr
		default:
			// more than one match, use the matched hits as the list moving to the next pattern.
			// this way you can have a series of selection criteria
			remainingGVRs = matchedGVRs
		}
	}

	return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingResources: originalGVRs}
}


KindFor

// KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit.
func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
	originalGVKs, originalErr := m.Delegate.KindsFor(partiallySpecifiedResource)
	if originalErr != nil && len(originalGVKs) == 0 {
		return schema.GroupVersionKind{}, originalErr
	}
	if len(originalGVKs) == 1 {
		return originalGVKs[0], originalErr
	}

	remainingGVKs := append([]schema.GroupVersionKind{}, originalGVKs...)
	for _, pattern := range m.KindPriority {
		matchedGVKs := []schema.GroupVersionKind{}
		for _, gvr := range remainingGVKs {
			if kindMatches(pattern, gvr) {
				matchedGVKs = append(matchedGVKs, gvr)
			}
		}

		switch len(matchedGVKs) {
		case 0:
			// if you have no matches, then nothing matched this pattern just move to the next
			continue
		case 1:
			// one match, return
			return matchedGVKs[0], originalErr
		default:
			// more than one match, use the matched hits as the list moving to the next pattern.
			// this way you can have a series of selection criteria
			remainingGVKs = matchedGVKs
		}
	}

	return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs}
}


resourceMatches

func resourceMatches(pattern schema.GroupVersionResource, resource schema.GroupVersionResource) bool {
	if pattern.Group != AnyGroup && pattern.Group != resource.Group {
		return false
	}
	if pattern.Version != AnyVersion && pattern.Version != resource.Version {
		return false
	}
	if pattern.Resource != AnyResource && pattern.Resource != resource.Resource {
		return false
	}

	return true
}


kindMatches

func kindMatches(pattern schema.GroupVersionKind, kind schema.GroupVersionKind) bool {
	if pattern.Group != AnyGroup && pattern.Group != kind.Group {
		return false
	}
	if pattern.Version != AnyVersion && pattern.Version != kind.Version {
		return false
	}
	if pattern.Kind != AnyKind && pattern.Kind != kind.Kind {
		return false
	}

	return true
}


RESTMapping

func (m PriorityRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
	mappings, originalErr := m.Delegate.RESTMappings(gk, versions...)
	if originalErr != nil && len(mappings) == 0 {
		return nil, originalErr
	}

	// any versions the user provides take priority
	priorities := m.KindPriority
	if len(versions) > 0 {
		priorities = make([]schema.GroupVersionKind, 0, len(m.KindPriority)+len(versions))
		for _, version := range versions {
			gv := schema.GroupVersion{
				Version: version,
				Group:   gk.Group,
			}
			priorities = append(priorities, gv.WithKind(AnyKind))
		}
		priorities = append(priorities, m.KindPriority...)
	}

	remaining := append([]*RESTMapping{}, mappings...)
	for _, pattern := range priorities {
		var matching []*RESTMapping
		for _, m := range remaining {
			if kindMatches(pattern, m.GroupVersionKind) {
				matching = append(matching, m)
			}
		}

		switch len(matching) {
		case 0:
			// if you have no matches, then nothing matched this pattern just move to the next
			continue
		case 1:
			// one match, return
			return matching[0], originalErr
		default:
			// more than one match, use the matched hits as the list moving to the next pattern.
			// this way you can have a series of selection criteria
			remaining = matching
		}
	}
	if len(remaining) == 1 {
		return remaining[0], originalErr
	}

	var kinds []schema.GroupVersionKind
	for _, m := range mappings {
		kinds = append(kinds, m.GroupVersionKind)
	}
	return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
}


RESTMappings

func (m PriorityRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
	return m.Delegate.RESTMappings(gk, versions...)
}


ResourceSingularizer

func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
	return m.Delegate.ResourceSingularizer(resource)
}


ResourcesFor

func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
	return m.Delegate.ResourcesFor(partiallySpecifiedResource)
}


KindsFor

func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
	return m.Delegate.KindsFor(partiallySpecifiedResource)
}


Reset

func (m PriorityRESTMapper) Reset() {
	MaybeResetRESTMapper(m.Delegate)
}


Name

func (r *restScope) Name() RESTScopeName {
	return r.name
}


String

func (m *DefaultRESTMapper) String() string {
	if m == nil {
		return "<nil>"
	}
	return fmt.Sprintf("DefaultRESTMapper{kindToPluralResource=%v}", m.kindToPluralResource)
}


NewDefaultRESTMapper

// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion
// to a resource name and back based on the objects in a runtime.Scheme
// and the Kubernetes API conventions. Takes a group name, a priority list of the versions
// to search when an object has no default version (set empty to return an error),
// and a function that retrieves the correct metadata for a given version.
func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion) *DefaultRESTMapper {
	resourceToKind := make(map[schema.GroupVersionResource]schema.GroupVersionKind)
	kindToPluralResource := make(map[schema.GroupVersionKind]schema.GroupVersionResource)
	kindToScope := make(map[schema.GroupVersionKind]RESTScope)
	singularToPlural := make(map[schema.GroupVersionResource]schema.GroupVersionResource)
	pluralToSingular := make(map[schema.GroupVersionResource]schema.GroupVersionResource)
	// TODO: verify name mappings work correctly when versions differ

	return &DefaultRESTMapper{
		resourceToKind:       resourceToKind,
		kindToPluralResource: kindToPluralResource,
		kindToScope:          kindToScope,
		defaultGroupVersions: defaultGroupVersions,
		singularToPlural:     singularToPlural,
		pluralToSingular:     pluralToSingular,
	}
}


Add

func (m *DefaultRESTMapper) Add(kind schema.GroupVersionKind, scope RESTScope) {
	plural, singular := UnsafeGuessKindToResource(kind)
	m.AddSpecific(kind, plural, singular, scope)
}


AddSpecific

func (m *DefaultRESTMapper) AddSpecific(kind schema.GroupVersionKind, plural, singular schema.GroupVersionResource, scope RESTScope) {
	m.singularToPlural[singular] = plural
	m.pluralToSingular[plural] = singular

	m.resourceToKind[singular] = kind
	m.resourceToKind[plural] = kind

	m.kindToPluralResource[kind] = plural
	m.kindToScope[kind] = scope
}


UnsafeGuessKindToResource

// UnsafeGuessKindToResource converts Kind to a resource name.
// Broken. This method only "sort of" works when used outside of this package.  It assumes that Kinds and Resources match
// and they aren't guaranteed to do so.
func UnsafeGuessKindToResource(kind schema.GroupVersionKind) ( /*plural*/ schema.GroupVersionResource /*singular*/, schema.GroupVersionResource) {
	kindName := kind.Kind
	if len(kindName) == 0 {
		return schema.GroupVersionResource{}, schema.GroupVersionResource{}
	}
	singularName := strings.ToLower(kindName)
	singular := kind.GroupVersion().WithResource(singularName)

	for _, skip := range unpluralizedSuffixes {
		if strings.HasSuffix(singularName, skip) {
			return singular, singular
		}
	}

	switch string(singularName[len(singularName)-1]) {
	case "s":
		return kind.GroupVersion().WithResource(singularName + "es"), singular
	case "y":
		return kind.GroupVersion().WithResource(strings.TrimSuffix(singularName, "y") + "ies"), singular
	}

	return kind.GroupVersion().WithResource(singularName + "s"), singular
}


ResourceSingularizer

// ResourceSingularizer implements RESTMapper
// It converts a resource name from plural to singular (e.g., from pods to pod)
func (m *DefaultRESTMapper) ResourceSingularizer(resourceType string) (string, error) {
	partialResource := schema.GroupVersionResource{Resource: resourceType}
	resources, err := m.ResourcesFor(partialResource)
	if err != nil {
		return resourceType, err
	}

	singular := schema.GroupVersionResource{}
	for _, curr := range resources {
		currSingular, ok := m.pluralToSingular[curr]
		if !ok {
			continue
		}
		if singular.Empty() {
			singular = currSingular
			continue
		}

		if currSingular.Resource != singular.Resource {
			return resourceType, fmt.Errorf("multiple possible singular resources (%v) found for %v", resources, resourceType)
		}
	}

	if singular.Empty() {
		return resourceType, fmt.Errorf("no singular of resource %v has been defined", resourceType)
	}

	return singular.Resource, nil
}


coerceResourceForMatching

// coerceResourceForMatching makes the resource lower case and converts internal versions to unspecified (legacy behavior)
func coerceResourceForMatching(resource schema.GroupVersionResource) schema.GroupVersionResource {
	resource.Resource = strings.ToLower(resource.Resource)
	if resource.Version == runtime.APIVersionInternal {
		resource.Version = ""
	}

	return resource
}


ResourcesFor

func (m *DefaultRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
	resource := coerceResourceForMatching(input)

	hasResource := len(resource.Resource) > 0
	hasGroup := len(resource.Group) > 0
	hasVersion := len(resource.Version) > 0

	if !hasResource {
		return nil, fmt.Errorf("a resource must be present, got: %v", resource)
	}

	ret := []schema.GroupVersionResource{}
	switch {
	case hasGroup && hasVersion:
		// fully qualified.  Find the exact match
		for plural, singular := range m.pluralToSingular {
			if singular == resource {
				ret = append(ret, plural)
				break
			}
			if plural == resource {
				ret = append(ret, plural)
				break
			}
		}

	case hasGroup:
		// given a group, prefer an exact match.  If you don't find one, resort to a prefix match on group
		foundExactMatch := false
		requestedGroupResource := resource.GroupResource()
		for plural, singular := range m.pluralToSingular {
			if singular.GroupResource() == requestedGroupResource {
				foundExactMatch = true
				ret = append(ret, plural)
			}
			if plural.GroupResource() == requestedGroupResource {
				foundExactMatch = true
				ret = append(ret, plural)
			}
		}

		// if you didn't find an exact match, match on group prefixing. This allows storageclass.storage to match
		// storageclass.storage.k8s.io
		if !foundExactMatch {
			for plural, singular := range m.pluralToSingular {
				if !strings.HasPrefix(plural.Group, requestedGroupResource.Group) {
					continue
				}
				if singular.Resource == requestedGroupResource.Resource {
					ret = append(ret, plural)
				}
				if plural.Resource == requestedGroupResource.Resource {
					ret = append(ret, plural)
				}
			}

		}

	case hasVersion:
		for plural, singular := range m.pluralToSingular {
			if singular.Version == resource.Version && singular.Resource == resource.Resource {
				ret = append(ret, plural)
			}
			if plural.Version == resource.Version && plural.Resource == resource.Resource {
				ret = append(ret, plural)
			}
		}

	default:
		for plural, singular := range m.pluralToSingular {
			if singular.Resource == resource.Resource {
				ret = append(ret, plural)
			}
			if plural.Resource == resource.Resource {
				ret = append(ret, plural)
			}
		}
	}

	if len(ret) == 0 {
		return nil, &NoResourceMatchError{PartialResource: resource}
	}

	sort.Sort(resourceByPreferredGroupVersion{ret, m.defaultGroupVersions})
	return ret, nil
}


ResourceFor

func (m *DefaultRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
	resources, err := m.ResourcesFor(resource)
	if err != nil {
		return schema.GroupVersionResource{}, err
	}
	if len(resources) == 1 {
		return resources[0], nil
	}

	return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources}
}


KindsFor

func (m *DefaultRESTMapper) KindsFor(input schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
	resource := coerceResourceForMatching(input)

	hasResource := len(resource.Resource) > 0
	hasGroup := len(resource.Group) > 0
	hasVersion := len(resource.Version) > 0

	if !hasResource {
		return nil, fmt.Errorf("a resource must be present, got: %v", resource)
	}

	ret := []schema.GroupVersionKind{}
	switch {
	// fully qualified.  Find the exact match
	case hasGroup && hasVersion:
		kind, exists := m.resourceToKind[resource]
		if exists {
			ret = append(ret, kind)
		}

	case hasGroup:
		foundExactMatch := false
		requestedGroupResource := resource.GroupResource()
		for currResource, currKind := range m.resourceToKind {
			if currResource.GroupResource() == requestedGroupResource {
				foundExactMatch = true
				ret = append(ret, currKind)
			}
		}

		// if you didn't find an exact match, match on group prefixing. This allows storageclass.storage to match
		// storageclass.storage.k8s.io
		if !foundExactMatch {
			for currResource, currKind := range m.resourceToKind {
				if !strings.HasPrefix(currResource.Group, requestedGroupResource.Group) {
					continue
				}
				if currResource.Resource == requestedGroupResource.Resource {
					ret = append(ret, currKind)
				}
			}

		}

	case hasVersion:
		for currResource, currKind := range m.resourceToKind {
			if currResource.Version == resource.Version && currResource.Resource == resource.Resource {
				ret = append(ret, currKind)
			}
		}

	default:
		for currResource, currKind := range m.resourceToKind {
			if currResource.Resource == resource.Resource {
				ret = append(ret, currKind)
			}
		}
	}

	if len(ret) == 0 {
		return nil, &NoResourceMatchError{PartialResource: input}
	}

	sort.Sort(kindByPreferredGroupVersion{ret, m.defaultGroupVersions})
	return ret, nil
}


KindFor

func (m *DefaultRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
	kinds, err := m.KindsFor(resource)
	if err != nil {
		return schema.GroupVersionKind{}, err
	}
	if len(kinds) == 1 {
		return kinds[0], nil
	}

	return schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds}
}


Len

func (o kindByPreferredGroupVersion) Len() int      { return len(o.list) }


Swap

func (o kindByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] }


Less

func (o kindByPreferredGroupVersion) Less(i, j int) bool {
	lhs := o.list[i]
	rhs := o.list[j]
	if lhs == rhs {
		return false
	}

	if lhs.GroupVersion() == rhs.GroupVersion() {
		return lhs.Kind < rhs.Kind
	}

	// otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order
	lhsIndex := -1
	rhsIndex := -1

	for i := range o.sortOrder {
		if o.sortOrder[i] == lhs.GroupVersion() {
			lhsIndex = i
		}
		if o.sortOrder[i] == rhs.GroupVersion() {
			rhsIndex = i
		}
	}

	if rhsIndex == -1 {
		return true
	}

	return lhsIndex < rhsIndex
}


Len

func (o resourceByPreferredGroupVersion) Len() int      { return len(o.list) }


Swap

func (o resourceByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] }


Less

func (o resourceByPreferredGroupVersion) Less(i, j int) bool {
	lhs := o.list[i]
	rhs := o.list[j]
	if lhs == rhs {
		return false
	}

	if lhs.GroupVersion() == rhs.GroupVersion() {
		return lhs.Resource < rhs.Resource
	}

	// otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order
	lhsIndex := -1
	rhsIndex := -1

	for i := range o.sortOrder {
		if o.sortOrder[i] == lhs.GroupVersion() {
			lhsIndex = i
		}
		if o.sortOrder[i] == rhs.GroupVersion() {
			rhsIndex = i
		}
	}

	if rhsIndex == -1 {
		return true
	}

	return lhsIndex < rhsIndex
}


RESTMapping

// RESTMapping returns a struct representing the resource path and conversion interfaces a
// RESTClient should use to operate on the provided group/kind in order of versions. If a version search
// order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which
// version should be used to access the named group/kind.
func (m *DefaultRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
	mappings, err := m.RESTMappings(gk, versions...)
	if err != nil {
		return nil, err
	}
	if len(mappings) == 0 {
		return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
	}
	// since we rely on RESTMappings method
	// take the first match and return to the caller
	// as this was the existing behavior.
	return mappings[0], nil
}


RESTMappings

// RESTMappings returns the RESTMappings for the provided group kind. If a version search order
// is not provided, the search order provided to DefaultRESTMapper will be used.
func (m *DefaultRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
	mappings := make([]*RESTMapping, 0)
	potentialGVK := make([]schema.GroupVersionKind, 0)
	hadVersion := false

	// Pick an appropriate version
	for _, version := range versions {
		if len(version) == 0 || version == runtime.APIVersionInternal {
			continue
		}
		currGVK := gk.WithVersion(version)
		hadVersion = true
		if _, ok := m.kindToPluralResource[currGVK]; ok {
			potentialGVK = append(potentialGVK, currGVK)
			break
		}
	}
	// Use the default preferred versions
	if !hadVersion && len(potentialGVK) == 0 {
		for _, gv := range m.defaultGroupVersions {
			if gv.Group != gk.Group {
				continue
			}
			potentialGVK = append(potentialGVK, gk.WithVersion(gv.Version))
		}
	}

	if len(potentialGVK) == 0 {
		return nil, &NoKindMatchError{GroupKind: gk, SearchedVersions: versions}
	}

	for _, gvk := range potentialGVK {
		//Ensure we have a REST mapping
		res, ok := m.kindToPluralResource[gvk]
		if !ok {
			continue
		}

		// Ensure we have a REST scope
		scope, ok := m.kindToScope[gvk]
		if !ok {
			return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion(), gvk.Kind)
		}

		mappings = append(mappings, &RESTMapping{
			Resource:         res,
			GroupVersionKind: gvk,
			Scope:            scope,
		})
	}

	if len(mappings) == 0 {
		return nil, &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Group: gk.Group, Resource: gk.Kind}}
	}
	return mappings, nil
}


MaybeResetRESTMapper

// MaybeResetRESTMapper calls Reset() on the mapper if it is a ResettableRESTMapper.
func MaybeResetRESTMapper(mapper RESTMapper) {
	m, ok := mapper.(ResettableRESTMapper)
	if ok {
		m.Reset()
	}
}


MetaToTableRow

// MetaToTableRow converts a list or object into one or more table rows. The provided rowFn is invoked for
// each accessed item, with name and age being passed to each.
func MetaToTableRow(obj runtime.Object, rowFn func(obj runtime.Object, m metav1.Object, name, age string) ([]interface{}, error)) ([]metav1.TableRow, error) {
	if meta.IsListType(obj) {
		rows := make([]metav1.TableRow, 0, 16)
		err := meta.EachListItem(obj, func(obj runtime.Object) error {
			nestedRows, err := MetaToTableRow(obj, rowFn)
			if err != nil {
				return err
			}
			rows = append(rows, nestedRows...)
			return nil
		})
		if err != nil {
			return nil, err
		}
		return rows, nil
	}

	rows := make([]metav1.TableRow, 0, 1)
	m, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}
	row := metav1.TableRow{
		Object: runtime.RawExtension{Object: obj},
	}
	row.Cells, err = rowFn(obj, m, m.GetName(), ConvertToHumanReadableDateType(m.GetCreationTimestamp()))
	if err != nil {
		return nil, err
	}
	rows = append(rows, row)
	return rows, nil
}


ConvertToHumanReadableDateType

// ConvertToHumanReadableDateType returns the elapsed time since timestamp in
// human-readable approximation.
func ConvertToHumanReadableDateType(timestamp metav1.Time) string {
	if timestamp.IsZero() {
		return "<unknown>"
	}
	return duration.HumanDuration(time.Since(timestamp.Time))
}


infScale

// infScale adapts a Scale value to an inf.Scale value.
func (s Scale) infScale() inf.Scale {
	return inf.Scale(-s) // inf.Scale is upside-down
}


Sign

// Sign returns 0 if the value is zero, -1 if it is less than 0, or 1 if it is greater than 0.
func (a int64Amount) Sign() int {
	switch {
	case a.value == 0:
		return 0
	case a.value > 0:
		return 1
	default:
		return -1
	}
}


// AsInt64 returns the current amount as an int64 at scale 0, or false if the value cannot be
// represented in an int64 OR would result in a loss of precision. This method is intended as
// an optimization to avoid calling AsDec.
func (a int64Amount) AsInt64() (int64, bool) {
	if a.scale == 0 {
		return a.value, true
	}
	if a.scale < 0 {
		// TODO: attempt to reduce factors, although it is assumed that factors are reduced prior
		// to the int64Amount being created.
		return 0, false
	}
	return positiveScaleInt64(a.value, a.scale)
}


// AsScaledInt64 returns an int64 representing the value of this amount at the specified scale,
// rounding up, or false if that would result in overflow. (1e20).AsScaledInt64(1) would result
// in overflow because 1e19 is not representable as an int64. Note that setting a scale larger
// than the current value may result in loss of precision - i.e. (1e-6).AsScaledInt64(0) would
// return 1, because 0.000001 is rounded up to 1.
func (a int64Amount) AsScaledInt64(scale Scale) (result int64, ok bool) {
	if a.scale < scale {
		result, _ = negativeScaleInt64(a.value, scale-a.scale)
		return result, true
	}
	return positiveScaleInt64(a.value, a.scale-scale)
}


AsDec

// AsDec returns an inf.Dec representation of this value.
func (a int64Amount) AsDec() *inf.Dec {
	var base inf.Dec
	base.SetUnscaled(a.value)
	base.SetScale(inf.Scale(-a.scale))
	return &base
}


Cmp

// Cmp returns 0 if a and b are equal, 1 if a is greater than b, or -1 if a is less than b.
func (a int64Amount) Cmp(b int64Amount) int {
	switch {
	case a.scale == b.scale:
		// compare only the unscaled portion
	case a.scale > b.scale:
		result, remainder, exact := divideByScaleInt64(b.value, a.scale-b.scale)
		if !exact {
			return a.AsDec().Cmp(b.AsDec())
		}
		if result == a.value {
			switch {
			case remainder == 0:
				return 0
			case remainder > 0:
				return -1
			default:
				return 1
			}
		}
		b.value = result
	default:
		result, remainder, exact := divideByScaleInt64(a.value, b.scale-a.scale)
		if !exact {
			return a.AsDec().Cmp(b.AsDec())
		}
		if result == b.value {
			switch {
			case remainder == 0:
				return 0
			case remainder > 0:
				return 1
			default:
				return -1
			}
		}
		a.value = result
	}

	switch {
	case a.value == b.value:
		return 0
	case a.value < b.value:
		return -1
	default:
		return 1
	}
}


Add

// Add adds two int64Amounts together, matching scales. It will return false and not mutate
// a if overflow or underflow would result.
func (a *int64Amount) Add(b int64Amount) bool {
	switch {
	case b.value == 0:
		return true
	case a.value == 0:
		a.value = b.value
		a.scale = b.scale
		return true
	case a.scale == b.scale:
		c, ok := int64Add(a.value, b.value)
		if !ok {
			return false
		}
		a.value = c
	case a.scale > b.scale:
		c, ok := positiveScaleInt64(a.value, a.scale-b.scale)
		if !ok {
			return false
		}
		c, ok = int64Add(c, b.value)
		if !ok {
			return false
		}
		a.scale = b.scale
		a.value = c
	default:
		c, ok := positiveScaleInt64(b.value, b.scale-a.scale)
		if !ok {
			return false
		}
		c, ok = int64Add(a.value, c)
		if !ok {
			return false
		}
		a.value = c
	}
	return true
}


Sub

// Sub removes the value of b from the current amount, or returns false if underflow would result.
func (a *int64Amount) Sub(b int64Amount) bool {
	return a.Add(int64Amount{value: -b.value, scale: b.scale})
}


AsScale

// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
func (a int64Amount) AsScale(scale Scale) (int64Amount, bool) {
	if a.scale >= scale {
		return a, true
	}
	result, exact := negativeScaleInt64(a.value, scale-a.scale)
	return int64Amount{value: result, scale: scale}, exact
}


AsCanonicalBytes

// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
func (a int64Amount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
	mantissa := a.value
	exponent = int32(a.scale)

	amount, times := removeInt64Factors(mantissa, 10)
	exponent += int32(times)

	// make sure exponent is a multiple of 3
	var ok bool
	switch exponent % 3 {
	case 1, -2:
		amount, ok = int64MultiplyScale10(amount)
		if !ok {
			return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
		}
		exponent = exponent - 1
	case 2, -1:
		amount, ok = int64MultiplyScale100(amount)
		if !ok {
			return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
		}
		exponent = exponent - 2
	}
	return strconv.AppendInt(out, amount, 10), exponent
}


// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
// return []byte("2048"), 1.
func (a int64Amount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
	value, ok := a.AsScaledInt64(0)
	if !ok {
		return infDecAmount{a.AsDec()}.AsCanonicalBase1024Bytes(out)
	}
	amount, exponent := removeInt64Factors(value, 1024)
	return strconv.AppendInt(out, amount, 10), exponent
}


AsScale

// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
func (a infDecAmount) AsScale(scale Scale) (infDecAmount, bool) {
	tmp := &inf.Dec{}
	tmp.Round(a.Dec, scale.infScale(), inf.RoundUp)
	return infDecAmount{tmp}, tmp.Cmp(a.Dec) == 0
}


AsCanonicalBytes

// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
func (a infDecAmount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
	mantissa := a.Dec.UnscaledBig()
	exponent = int32(-a.Dec.Scale())
	amount := big.NewInt(0).Set(mantissa)
	// move all factors of 10 into the exponent for easy reasoning
	amount, times := removeBigIntFactors(amount, bigTen)
	exponent += times

	// make sure exponent is a multiple of 3
	for exponent%3 != 0 {
		amount.Mul(amount, bigTen)
		exponent--
	}

	return append(out, amount.String()...), exponent
}


// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
// return []byte("2048"), 1.
func (a infDecAmount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
	tmp := &inf.Dec{}
	tmp.Round(a.Dec, 0, inf.RoundUp)
	amount, exponent := removeBigIntFactors(tmp.UnscaledBig(), big1024)
	return append(out, amount.String()...), exponent
}


// int64Add returns a+b, or false if that would overflow int64.
func int64Add(a, b int64) (int64, bool) {
	c := a + b
	switch {
	case a > 0 && b > 0:
		if c < 0 {
			return 0, false
		}
	case a < 0 && b < 0:
		if c > 0 {
			return 0, false
		}
		if a == mostNegative && b == mostNegative {
			return 0, false
		}
	}
	return c, true
}


// int64Multiply returns a*b, or false if that would overflow or underflow int64.
func int64Multiply(a, b int64) (int64, bool) {
	if a == 0 || b == 0 || a == 1 || b == 1 {
		return a * b, true
	}
	if a == mostNegative || b == mostNegative {
		return 0, false
	}
	c := a * b
	return c, c/b == a
}


// int64MultiplyScale returns a*b, assuming b is greater than one, or false if that would overflow or underflow int64.
// Use when b is known to be greater than one.
func int64MultiplyScale(a int64, b int64) (int64, bool) {
	if a == 0 || a == 1 {
		return a * b, true
	}
	if a == mostNegative && b != 1 {
		return 0, false
	}
	c := a * b
	return c, c/b == a
}


// int64MultiplyScale10 multiplies a by 10, or returns false if that would overflow. This method is faster than
// int64Multiply(a, 10) because the compiler can optimize constant factor multiplication.
func int64MultiplyScale10(a int64) (int64, bool) {
	if a == 0 || a == 1 {
		return a * 10, true
	}
	if a == mostNegative {
		return 0, false
	}
	c := a * 10
	return c, c/10 == a
}


// int64MultiplyScale100 multiplies a by 100, or returns false if that would overflow. This method is faster than
// int64Multiply(a, 100) because the compiler can optimize constant factor multiplication.
func int64MultiplyScale100(a int64) (int64, bool) {
	if a == 0 || a == 1 {
		return a * 100, true
	}
	if a == mostNegative {
		return 0, false
	}
	c := a * 100
	return c, c/100 == a
}


// int64MultiplyScale1000 multiplies a by 1000, or returns false if that would overflow. This method is faster than
// int64Multiply(a, 1000) because the compiler can optimize constant factor multiplication.
func int64MultiplyScale1000(a int64) (int64, bool) {
	if a == 0 || a == 1 {
		return a * 1000, true
	}
	if a == mostNegative {
		return 0, false
	}
	c := a * 1000
	return c, c/1000 == a
}


// positiveScaleInt64 multiplies base by 10^scale, returning false if the
// value overflows. Passing a negative scale is undefined.
func positiveScaleInt64(base int64, scale Scale) (int64, bool) {
	switch scale {
	case 0:
		return base, true
	case 1:
		return int64MultiplyScale10(base)
	case 2:
		return int64MultiplyScale100(base)
	case 3:
		return int64MultiplyScale1000(base)
	case 6:
		return int64MultiplyScale(base, 1000000)
	case 9:
		return int64MultiplyScale(base, 1000000000)
	default:
		value := base
		var ok bool
		for i := Scale(0); i < scale; i++ {
			if value, ok = int64MultiplyScale(value, 10); !ok {
				return 0, false
			}
		}
		return value, true
	}
}


// negativeScaleInt64 reduces base by the provided scale, rounding up, until the
// value is zero or the scale is reached. Passing a negative scale is undefined.
// The value returned, if not exact, is rounded away from zero.
func negativeScaleInt64(base int64, scale Scale) (result int64, exact bool) {
	if scale == 0 {
		return base, true
	}

	value := base
	var fraction bool
	for i := Scale(0); i < scale; i++ {
		if !fraction && value%10 != 0 {
			fraction = true
		}
		value = value / 10
		if value == 0 {
			if fraction {
				if base > 0 {
					return 1, false
				}
				return -1, false
			}
			return 0, true
		}
	}
	if fraction {
		if base > 0 {
			value++
		} else {
			value--
		}
	}
	return value, !fraction
}


// negativeScaleInt64 returns the result of dividing base by scale * 10 and the remainder, or
// false if no such division is possible. Dividing by negative scales is undefined.
func divideByScaleInt64(base int64, scale Scale) (result, remainder int64, exact bool) {
	if scale == 0 {
		return base, 0, true
	}
	// the max scale representable in base 10 in an int64 is 18 decimal places
	if scale >= 18 {
		return 0, base, false
	}
	divisor := pow10Int64(int64(scale))
	return base / divisor, base % divisor, true
}


// removeInt64Factors divides in a loop; the return values have the property that
// value == result * base ^ scale
func removeInt64Factors(value int64, base int64) (result int64, times int32) {
	times = 0
	result = value
	negative := result < 0
	if negative {
		result = -result
	}
	switch base {
	// allow the compiler to optimize the common cases
	case 10:
		for result >= 10 && result%10 == 0 {
			times++
			result = result / 10
		}
	// allow the compiler to optimize the common cases
	case 1024:
		for result >= 1024 && result%1024 == 0 {
			times++
			result = result / 1024
		}
	default:
		for result >= base && result%base == 0 {
			times++
			result = result / base
		}
	}
	if negative {
		result = -result
	}
	return result, times
}


removeBigIntFactors

// removeBigIntFactors divides in a loop; the return values have the property that
// d == result * factor ^ times
// d may be modified in place.
// If d == 0, then the return values will be (0, 0)
func removeBigIntFactors(d, factor *big.Int) (result *big.Int, times int32) {
	q := big.NewInt(0)
	m := big.NewInt(0)
	for d.Cmp(bigZero) != 0 {
		q.DivMod(d, factor, m)
		if m.Cmp(bigZero) != 0 {
			break
		}
		times++
		d, q = q, d
	}
	return d, times
}


MustParse

// MustParse turns the given string into a quantity or panics; for tests
// or other cases where you know the string is valid.
func MustParse(str string) Quantity {
	q, err := ParseQuantity(str)
	if err != nil {
		panic(fmt.Errorf("cannot parse '%v': %v", str, err))
	}
	return q
}


parseQuantityString

// parseQuantityString is a fast scanner for quantity values.
func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) {
	positive = true
	pos := 0
	end := len(str)

	// handle leading sign
	if pos < end {
		switch str[0] {
		case '-':
			positive = false
			pos++
		case '+':
			pos++
		}
	}

	// strip leading zeros
Zeroes:
	for i := pos; ; i++ {
		if i >= end {
			num = "0"
			value = num
			return
		}
		switch str[i] {
		case '0':
			pos++
		default:
			break Zeroes
		}
	}

	// extract the numerator
Num:
	for i := pos; ; i++ {
		if i >= end {
			num = str[pos:end]
			value = str[0:end]
			return
		}
		switch str[i] {
		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		default:
			num = str[pos:i]
			pos = i
			break Num
		}
	}

	// if we stripped all numerator positions, always return 0
	if len(num) == 0 {
		num = "0"
	}

	// handle a denominator
	if pos < end && str[pos] == '.' {
		pos++
	Denom:
		for i := pos; ; i++ {
			if i >= end {
				denom = str[pos:end]
				value = str[0:end]
				return
			}
			switch str[i] {
			case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
			default:
				denom = str[pos:i]
				pos = i
				break Denom
			}
		}
		// TODO: we currently allow 1.G, but we may not want to in the future.
		// if len(denom) == 0 {
		// 	err = ErrFormatWrong
		// 	return
		// }
	}
	value = str[0:pos]

	// grab the elements of the suffix
	suffixStart := pos
	for i := pos; ; i++ {
		if i >= end {
			suffix = str[suffixStart:end]
			return
		}
		if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") {
			pos = i
			break
		}
	}
	if pos < end {
		switch str[pos] {
		case '-', '+':
			pos++
		}
	}
Suffix:
	for i := pos; ; i++ {
		if i >= end {
			suffix = str[suffixStart:end]
			return
		}
		switch str[i] {
		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		default:
			break Suffix
		}
	}
	// we encountered a non decimal in the Suffix loop, but the last character
	// was not a valid exponent
	err = ErrFormatWrong
	return
}


ParseQuantity

// ParseQuantity turns str into a Quantity, or returns an error.
func ParseQuantity(str string) (Quantity, error) {
	if len(str) == 0 {
		return Quantity{}, ErrFormatWrong
	}
	if str == "0" {
		return Quantity{Format: DecimalSI, s: str}, nil
	}

	positive, value, num, denom, suf, err := parseQuantityString(str)
	if err != nil {
		return Quantity{}, err
	}

	base, exponent, format, ok := quantitySuffixer.interpret(suffix(suf))
	if !ok {
		return Quantity{}, ErrSuffix
	}

	precision := int32(0)
	scale := int32(0)
	mantissa := int64(1)
	switch format {
	case DecimalExponent, DecimalSI:
		scale = exponent
		precision = maxInt64Factors - int32(len(num)+len(denom))
	case BinarySI:
		scale = 0
		switch {
		case exponent >= 0 && len(denom) == 0:
			// only handle positive binary numbers with the fast path
			mantissa = int64(int64(mantissa) << uint64(exponent))
			// 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision
			precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1
		default:
			precision = -1
		}
	}

	if precision >= 0 {
		// if we have a denominator, shift the entire value to the left by the number of places in the
		// denominator
		scale -= int32(len(denom))
		if scale >= int32(Nano) {
			shifted := num + denom

			var value int64
			value, err := strconv.ParseInt(shifted, 10, 64)
			if err != nil {
				return Quantity{}, ErrNumeric
			}
			if result, ok := int64Multiply(value, int64(mantissa)); ok {
				if !positive {
					result = -result
				}
				// if the number is in canonical form, reuse the string
				switch format {
				case BinarySI:
					if exponent%10 == 0 && (value&0x07 != 0) {
						return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
					}
				default:
					if scale%3 == 0 && !strings.HasSuffix(shifted, "000") && shifted[0] != '0' {
						return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
					}
				}
				return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format}, nil
			}
		}
	}

	amount := new(inf.Dec)
	if _, ok := amount.SetString(value); !ok {
		return Quantity{}, ErrNumeric
	}

	// So that no one but us has to think about suffixes, remove it.
	if base == 10 {
		amount.SetScale(amount.Scale() + Scale(exponent).infScale())
	} else if base == 2 {
		// numericSuffix = 2 ** exponent
		numericSuffix := big.NewInt(1).Lsh(bigOne, uint(exponent))
		ub := amount.UnscaledBig()
		amount.SetUnscaledBig(ub.Mul(ub, numericSuffix))
	}

	// Cap at min/max bounds.
	sign := amount.Sign()
	if sign == -1 {
		amount.Neg(amount)
	}

	// This rounds non-zero values up to the minimum representable value, under the theory that
	// if you want some resources, you should get some resources, even if you asked for way too small
	// of an amount.  Arguably, this should be inf.RoundHalfUp (normal rounding), but that would have
	// the side effect of rounding values < .5n to zero.
	if v, ok := amount.Unscaled(); v != int64(0) || !ok {
		amount.Round(amount, Nano.infScale(), inf.RoundUp)
	}

	// The max is just a simple cap.
	// TODO: this prevents accumulating quantities greater than int64, for instance quota across a cluster
	if format == BinarySI && amount.Cmp(maxAllowed.Dec) > 0 {
		amount.Set(maxAllowed.Dec)
	}

	if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 {
		// This avoids rounding and hopefully confusion, too.
		format = DecimalSI
	}
	if sign == -1 {
		amount.Neg(amount)
	}

	return Quantity{d: infDecAmount{amount}, Format: format}, nil
}


DeepCopy

// DeepCopy returns a deep-copy of the Quantity value.  Note that the method
// receiver is a value, so we can mutate it in-place and return it.
func (q Quantity) DeepCopy() Quantity {
	if q.d.Dec != nil {
		tmp := &inf.Dec{}
		q.d.Dec = tmp.Set(q.d.Dec)
	}
	return q
}


OpenAPISchemaType

// OpenAPISchemaType is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
//
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
func (_ Quantity) OpenAPISchemaType() []string { return []string{"string"} }


OpenAPISchemaFormat

// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
func (_ Quantity) OpenAPISchemaFormat() string { return "" }


// OpenAPIV3OneOfTypes is used by the kube-openapi generator when constructing
// the OpenAPI v3 spec of this type.
func (Quantity) OpenAPIV3OneOfTypes() []string { return []string{"string", "number"} }


CanonicalizeBytes

// CanonicalizeBytes returns the canonical form of q and its suffix (see comment on Quantity).
//
// Note about BinarySI:
//   - If q.Format is set to BinarySI and q.Amount represents a non-zero value between
//     -1 and +1, it will be emitted as if q.Format were DecimalSI.
//   - Otherwise, if q.Format is set to BinarySI, fractional parts of q.Amount will be
//     rounded up. (1.1i becomes 2i.)
func (q *Quantity) CanonicalizeBytes(out []byte) (result, suffix []byte) {
	if q.IsZero() {
		return zeroBytes, nil
	}

	var rounded CanonicalValue
	format := q.Format
	switch format {
	case DecimalExponent, DecimalSI:
	case BinarySI:
		if q.CmpInt64(-1024) > 0 && q.CmpInt64(1024) < 0 {
			// This avoids rounding and hopefully confusion, too.
			format = DecimalSI
		} else {
			var exact bool
			if rounded, exact = q.AsScale(0); !exact {
				// Don't lose precision-- show as DecimalSI
				format = DecimalSI
			}
		}
	default:
		format = DecimalExponent
	}

	// TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
	// one of the other formats.
	switch format {
	case DecimalExponent, DecimalSI:
		number, exponent := q.AsCanonicalBytes(out)
		suffix, _ := quantitySuffixer.constructBytes(10, exponent, format)
		return number, suffix
	default:
		// format must be BinarySI
		number, exponent := rounded.AsCanonicalBase1024Bytes(out)
		suffix, _ := quantitySuffixer.constructBytes(2, exponent*10, format)
		return number, suffix
	}
}


// AsApproximateFloat64 returns a float64 representation of the quantity which may
// lose precision. If the value of the quantity is outside the range of a float64
// +Inf/-Inf will be returned.
func (q *Quantity) AsApproximateFloat64() float64 {
	var base float64
	var exponent int
	if q.d.Dec != nil {
		base, _ = big.NewFloat(0).SetInt(q.d.Dec.UnscaledBig()).Float64()
		exponent = int(-q.d.Dec.Scale())
	} else {
		base = float64(q.i.value)
		exponent = int(q.i.scale)
	}
	if exponent == 0 {
		return base
	}

	return base * math.Pow10(exponent)
}


// AsInt64 returns a representation of the current value as an int64 if a fast conversion
// is possible. If false is returned, callers must use the inf.Dec form of this quantity.
func (q *Quantity) AsInt64() (int64, bool) {
	if q.d.Dec != nil {
		return 0, false
	}
	return q.i.AsInt64()
}


ToDec

// ToDec promotes the quantity in place to use an inf.Dec representation and returns itself.
func (q *Quantity) ToDec() *Quantity {
	if q.d.Dec == nil {
		q.d.Dec = q.i.AsDec()
		q.i = int64Amount{}
	}
	return q
}


AsDec

// AsDec returns the quantity as represented by a scaled inf.Dec.
func (q *Quantity) AsDec() *inf.Dec {
	if q.d.Dec != nil {
		return q.d.Dec
	}
	q.d.Dec = q.i.AsDec()
	q.i = int64Amount{}
	return q.d.Dec
}


AsCanonicalBytes

// AsCanonicalBytes returns the canonical byte representation of this quantity as a mantissa
// and base 10 exponent. The out byte slice may be passed to the method to avoid an extra
// allocation.
func (q *Quantity) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
	if q.d.Dec != nil {
		return q.d.AsCanonicalBytes(out)
	}
	return q.i.AsCanonicalBytes(out)
}


IsZero

// IsZero returns true if the quantity is equal to zero.
func (q *Quantity) IsZero() bool {
	if q.d.Dec != nil {
		return q.d.Dec.Sign() == 0
	}
	return q.i.value == 0
}


Sign

// Sign returns 0 if the quantity is zero, -1 if the quantity is less than zero, or 1 if the
// quantity is greater than zero.
func (q *Quantity) Sign() int {
	if q.d.Dec != nil {
		return q.d.Dec.Sign()
	}
	return q.i.Sign()
}


AsScale

// AsScale returns the current value, rounded up to the provided scale, and returns
// false if the scale resulted in a loss of precision.
func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) {
	if q.d.Dec != nil {
		return q.d.AsScale(scale)
	}
	return q.i.AsScale(scale)
}


RoundUp

// RoundUp updates the quantity to the provided scale, ensuring that the value is at
// least 1. False is returned if the rounding operation resulted in a loss of precision.
// Negative numbers are rounded away from zero (-9 scale 1 rounds to -10).
func (q *Quantity) RoundUp(scale Scale) bool {
	if q.d.Dec != nil {
		q.s = ""
		d, exact := q.d.AsScale(scale)
		q.d = d
		return exact
	}
	// avoid clearing the string value if we have already calculated it
	if q.i.scale >= scale {
		return true
	}
	q.s = ""
	i, exact := q.i.AsScale(scale)
	q.i = i
	return exact
}


Add

// Add adds the provide y quantity to the current value. If the current value is zero,
// the format of the quantity will be updated to the format of y.
func (q *Quantity) Add(y Quantity) {
	q.s = ""
	if q.d.Dec == nil && y.d.Dec == nil {
		if q.i.value == 0 {
			q.Format = y.Format
		}
		if q.i.Add(y.i) {
			return
		}
	} else if q.IsZero() {
		q.Format = y.Format
	}
	q.ToDec().d.Dec.Add(q.d.Dec, y.AsDec())
}


Sub

// Sub subtracts the provided quantity from the current value in place. If the current
// value is zero, the format of the quantity will be updated to the format of y.
func (q *Quantity) Sub(y Quantity) {
	q.s = ""
	if q.IsZero() {
		q.Format = y.Format
	}
	if q.d.Dec == nil && y.d.Dec == nil && q.i.Sub(y.i) {
		return
	}
	q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec())
}


Cmp

// Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
// quantity is greater than y.
func (q *Quantity) Cmp(y Quantity) int {
	if q.d.Dec == nil && y.d.Dec == nil {
		return q.i.Cmp(y.i)
	}
	return q.AsDec().Cmp(y.AsDec())
}


// CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
// quantity is greater than y.
func (q *Quantity) CmpInt64(y int64) int {
	if q.d.Dec != nil {
		return q.d.Dec.Cmp(inf.NewDec(y, inf.Scale(0)))
	}
	return q.i.Cmp(int64Amount{value: y})
}


Neg

// Neg sets quantity to be the negative value of itself.
func (q *Quantity) Neg() {
	q.s = ""
	if q.d.Dec == nil {
		q.i.value = -q.i.value
		return
	}
	q.d.Dec.Neg(q.d.Dec)
}


Equal

// Equal checks equality of two Quantities. This is useful for testing with
// cmp.Equal.
func (q Quantity) Equal(v Quantity) bool {
	return q.Cmp(v) == 0
}


String

// String formats the Quantity as a string, caching the result if not calculated.
// String is an expensive operation and caching this result significantly reduces the cost of
// normal parse / marshal operations on Quantity.
func (q *Quantity) String() string {
	if q == nil {
		return "<nil>"
	}
	if len(q.s) == 0 {
		result := make([]byte, 0, int64QuantityExpectedBytes)
		number, suffix := q.CanonicalizeBytes(result)
		number = append(number, suffix...)
		q.s = string(number)
	}
	return q.s
}


MarshalJSON

// MarshalJSON implements the json.Marshaller interface.
func (q Quantity) MarshalJSON() ([]byte, error) {
	if len(q.s) > 0 {
		out := make([]byte, len(q.s)+2)
		out[0], out[len(out)-1] = '"', '"'
		copy(out[1:], q.s)
		return out, nil
	}
	result := make([]byte, int64QuantityExpectedBytes)
	result[0] = '"'
	number, suffix := q.CanonicalizeBytes(result[1:1])
	// if the same slice was returned to us that we passed in, avoid another allocation by copying number into
	// the source slice and returning that
	if len(number) > 0 && &number[0] == &result[1] && (len(number)+len(suffix)+2) <= int64QuantityExpectedBytes {
		number = append(number, suffix...)
		number = append(number, '"')
		return result[:1+len(number)], nil
	}
	// if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use
	// append
	result = result[:1]
	result = append(result, number...)
	result = append(result, suffix...)
	result = append(result, '"')
	return result, nil
}


ToUnstructured

// ToUnstructured implements the value.UnstructuredConverter interface.
func (q Quantity) ToUnstructured() interface{} {
	return q.String()
}


UnmarshalJSON

// UnmarshalJSON implements the json.Unmarshaller interface.
// TODO: Remove support for leading/trailing whitespace
func (q *Quantity) UnmarshalJSON(value []byte) error {
	l := len(value)
	if l == 4 && bytes.Equal(value, []byte("null")) {
		q.d.Dec = nil
		q.i = int64Amount{}
		return nil
	}
	if l >= 2 && value[0] == '"' && value[l-1] == '"' {
		value = value[1 : l-1]
	}

	parsed, err := ParseQuantity(strings.TrimSpace(string(value)))
	if err != nil {
		return err
	}

	// This copy is safe because parsed will not be referred to again.
	*q = parsed
	return nil
}


NewDecimalQuantity

// NewDecimalQuantity returns a new Quantity representing the given
// value in the given format.
func NewDecimalQuantity(b inf.Dec, format Format) *Quantity {
	return &Quantity{
		d:      infDecAmount{&b},
		Format: format,
	}
}


NewQuantity

// NewQuantity returns a new Quantity representing the given
// value in the given format.
func NewQuantity(value int64, format Format) *Quantity {
	return &Quantity{
		i:      int64Amount{value: value},
		Format: format,
	}
}


NewMilliQuantity

// NewMilliQuantity returns a new Quantity representing the given
// value * 1/1000 in the given format. Note that BinarySI formatting
// will round fractional values, and will be changed to DecimalSI for
// values x where (-1 < x < 1) && (x != 0).
func NewMilliQuantity(value int64, format Format) *Quantity {
	return &Quantity{
		i:      int64Amount{value: value, scale: -3},
		Format: format,
	}
}


NewScaledQuantity

// NewScaledQuantity returns a new Quantity representing the given
// value * 10^scale in DecimalSI format.
func NewScaledQuantity(value int64, scale Scale) *Quantity {
	return &Quantity{
		i:      int64Amount{value: value, scale: scale},
		Format: DecimalSI,
	}
}


Value

// Value returns the unscaled value of q rounded up to the nearest integer away from 0.
func (q *Quantity) Value() int64 {
	return q.ScaledValue(0)
}


MilliValue

// MilliValue returns the value of ceil(q * 1000); this could overflow an int64;
// if that's a concern, call Value() first to verify the number is small enough.
func (q *Quantity) MilliValue() int64 {
	return q.ScaledValue(Milli)
}


ScaledValue

// ScaledValue returns the value of ceil(q / 10^scale).
// For example, NewQuantity(1, DecimalSI).ScaledValue(Milli) returns 1000.
// This could overflow an int64.
// To detect overflow, call Value() first and verify the expected magnitude.
func (q *Quantity) ScaledValue(scale Scale) int64 {
	if q.d.Dec == nil {
		i, _ := q.i.AsScaledInt64(scale)
		return i
	}
	dec := q.d.Dec
	return scaledValue(dec.UnscaledBig(), int(dec.Scale()), int(scale.infScale()))
}


Set

// Set sets q's value to be value.
func (q *Quantity) Set(value int64) {
	q.SetScaled(value, 0)
}


SetMilli

// SetMilli sets q's value to be value * 1/1000.
func (q *Quantity) SetMilli(value int64) {
	q.SetScaled(value, Milli)
}


SetScaled

// SetScaled sets q's value to be value * 10^scale
func (q *Quantity) SetScaled(value int64, scale Scale) {
	q.s = ""
	q.d.Dec = nil
	q.i = int64Amount{value: value, scale: scale}
}


Set

// Set implements pflag.Value.Set and Go flag.Value.Set.
func (q *QuantityValue) Set(s string) error {
	quantity, err := ParseQuantity(s)
	if err != nil {
		return err
	}
	q.Quantity = quantity
	return nil
}


Type

// Type implements pflag.Value.Type.
func (q QuantityValue) Type() string {
	return "quantity"
}


Marshal

func (m *Quantity) Marshal() (data []byte, err error) {
	size := m.Size()
	data = make([]byte, size)
	n, err := m.MarshalToSizedBuffer(data[:size])
	if err != nil {
		return nil, err
	}
	return data[:n], nil
}


MarshalTo

// MarshalTo is a customized version of the generated Protobuf unmarshaler for a struct
// with a single string field.
func (m *Quantity) MarshalTo(data []byte) (int, error) {
	size := m.Size()
	return m.MarshalToSizedBuffer(data[:size])
}


MarshalToSizedBuffer

// MarshalToSizedBuffer is a customized version of the generated
// Protobuf unmarshaler for a struct with a single string field.
func (m *Quantity) MarshalToSizedBuffer(data []byte) (int, error) {
	i := len(data)
	_ = i
	var l int
	_ = l

	// BEGIN CUSTOM MARSHAL
	out := m.String()
	i -= len(out)
	copy(data[i:], out)
	i = encodeVarintGenerated(data, i, uint64(len(out)))
	// END CUSTOM MARSHAL
	i--
	data[i] = 0xa

	return len(data) - i, nil
}


encodeVarintGenerated

func encodeVarintGenerated(data []byte, offset int, v uint64) int {
	offset -= sovGenerated(v)
	base := offset
	for v >= 1<<7 {
		data[offset] = uint8(v&0x7f | 0x80)
		v >>= 7
		offset++
	}
	data[offset] = uint8(v)
	return base
}


Size

func (m *Quantity) Size() (n int) {
	var l int
	_ = l

	// BEGIN CUSTOM SIZE
	l = len(m.String())
	// END CUSTOM SIZE

	n += 1 + l + sovGenerated(uint64(l))
	return n
}


sovGenerated

func sovGenerated(x uint64) (n int) {
	return (bits.Len64(x|1) + 6) / 7
}


Unmarshal

// Unmarshal is a customized version of the generated Protobuf unmarshaler for a struct
// with a single string field.
func (m *Quantity) Unmarshal(data []byte) error {
	l := len(data)
	iNdEx := 0
	for iNdEx < l {
		preIndex := iNdEx
		var wire uint64
		for shift := uint(0); ; shift += 7 {
			if shift >= 64 {
				return ErrIntOverflowGenerated
			}
			if iNdEx >= l {
				return io.ErrUnexpectedEOF
			}
			b := data[iNdEx]
			iNdEx++
			wire |= (uint64(b) & 0x7F) << shift
			if b < 0x80 {
				break
			}
		}
		fieldNum := int32(wire >> 3)
		wireType := int(wire & 0x7)
		if wireType == 4 {
			return fmt.Errorf("proto: Quantity: wiretype end group for non-group")
		}
		if fieldNum <= 0 {
			return fmt.Errorf("proto: Quantity: illegal tag %d (wire type %d)", fieldNum, wire)
		}
		switch fieldNum {
		case 1:
			if wireType != 2 {
				return fmt.Errorf("proto: wrong wireType = %d for field String_", wireType)
			}
			var stringLen uint64
			for shift := uint(0); ; shift += 7 {
				if shift >= 64 {
					return ErrIntOverflowGenerated
				}
				if iNdEx >= l {
					return io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				stringLen |= (uint64(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			intStringLen := int(stringLen)
			if intStringLen < 0 {
				return ErrInvalidLengthGenerated
			}
			postIndex := iNdEx + intStringLen
			if postIndex > l {
				return io.ErrUnexpectedEOF
			}
			s := string(data[iNdEx:postIndex])

			// BEGIN CUSTOM DECODE
			p, err := ParseQuantity(s)
			if err != nil {
				return err
			}
			*m = p
			// END CUSTOM DECODE

			iNdEx = postIndex
		default:
			iNdEx = preIndex
			skippy, err := skipGenerated(data[iNdEx:])
			if err != nil {
				return err
			}
			if (skippy < 0) || (iNdEx+skippy) < 0 {
				return ErrInvalidLengthGenerated
			}
			if (iNdEx + skippy) > l {
				return io.ErrUnexpectedEOF
			}
			iNdEx += skippy
		}
	}

	if iNdEx > l {
		return io.ErrUnexpectedEOF
	}
	return nil
}


skipGenerated

func skipGenerated(data []byte) (n int, err error) {
	l := len(data)
	iNdEx := 0
	for iNdEx < l {
		var wire uint64
		for shift := uint(0); ; shift += 7 {
			if shift >= 64 {
				return 0, ErrIntOverflowGenerated
			}
			if iNdEx >= l {
				return 0, io.ErrUnexpectedEOF
			}
			b := data[iNdEx]
			iNdEx++
			wire |= (uint64(b) & 0x7F) << shift
			if b < 0x80 {
				break
			}
		}
		wireType := int(wire & 0x7)
		switch wireType {
		case 0:
			for shift := uint(0); ; shift += 7 {
				if shift >= 64 {
					return 0, ErrIntOverflowGenerated
				}
				if iNdEx >= l {
					return 0, io.ErrUnexpectedEOF
				}
				iNdEx++
				if data[iNdEx-1] < 0x80 {
					break
				}
			}
			return iNdEx, nil
		case 1:
			iNdEx += 8
			return iNdEx, nil
		case 2:
			var length int
			for shift := uint(0); ; shift += 7 {
				if shift >= 64 {
					return 0, ErrIntOverflowGenerated
				}
				if iNdEx >= l {
					return 0, io.ErrUnexpectedEOF
				}
				b := data[iNdEx]
				iNdEx++
				length |= (int(b) & 0x7F) << shift
				if b < 0x80 {
					break
				}
			}
			iNdEx += length
			if length < 0 {
				return 0, ErrInvalidLengthGenerated
			}
			return iNdEx, nil
		case 3:
			for {
				var innerWire uint64
				var start int = iNdEx
				for shift := uint(0); ; shift += 7 {
					if shift >= 64 {
						return 0, ErrIntOverflowGenerated
					}
					if iNdEx >= l {
						return 0, io.ErrUnexpectedEOF
					}
					b := data[iNdEx]
					iNdEx++
					innerWire |= (uint64(b) & 0x7F) << shift
					if b < 0x80 {
						break
					}
				}
				innerWireType := int(innerWire & 0x7)
				if innerWireType == 4 {
					break
				}
				next, err := skipGenerated(data[start:])
				if err != nil {
					return 0, err
				}
				iNdEx = start + next
			}
			return iNdEx, nil
		case 4:
			return iNdEx, nil
		case 5:
			iNdEx += 4
			return iNdEx, nil
		default:
			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
		}
	}
	panic("unreachable")
}


init

func init() {
	intPool.New = func() interface{} {
		return &big.Int{}
	}
}


scaledValue

// scaledValue scales given unscaled value from scale to new Scale and returns
// an int64. It ALWAYS rounds up the result when scale down. The final result might
// overflow.
//
// scale, newScale represents the scale of the unscaled decimal.
// The mathematical value of the decimal is unscaled * 10**(-scale).
func scaledValue(unscaled *big.Int, scale, newScale int) int64 {
	dif := scale - newScale
	if dif == 0 {
		return unscaled.Int64()
	}

	// Handle scale up
	// This is an easy case, we do not need to care about rounding and overflow.
	// If any intermediate operation causes overflow, the result will overflow.
	if dif < 0 {
		return unscaled.Int64() * int64(math.Pow10(-dif))
	}

	// Handle scale down
	// We have to be careful about the intermediate operations.

	// fast path when unscaled < max.Int64 and exp(10,dif) < max.Int64
	const log10MaxInt64 = 19
	if unscaled.Cmp(maxInt64) < 0 && dif < log10MaxInt64 {
		divide := int64(math.Pow10(dif))
		result := unscaled.Int64() / divide
		mod := unscaled.Int64() % divide
		if mod != 0 {
			return result + 1
		}
		return result
	}

	// We should only convert back to int64 when getting the result.
	divisor := intPool.Get().(*big.Int)
	exp := intPool.Get().(*big.Int)
	result := intPool.Get().(*big.Int)
	defer func() {
		intPool.Put(divisor)
		intPool.Put(exp)
		intPool.Put(result)
	}()

	// divisor = 10^(dif)
	// TODO: create loop up table if exp costs too much.
	divisor.Exp(bigTen, exp.SetInt64(int64(dif)), nil)
	// reuse exp
	remainder := exp

	// result = unscaled / divisor
	// remainder = unscaled % divisor
	result.DivMod(unscaled, divisor, remainder)
	if remainder.Sign() != 0 {
		return result.Int64() + 1
	}

	return result.Int64()
}


addSuffix

func (ls *listSuffixer) addSuffix(s suffix, pair bePair) {
	if ls.suffixToBE == nil {
		ls.suffixToBE = map[suffix]bePair{}
	}
	if ls.beToSuffix == nil {
		ls.beToSuffix = map[bePair]suffix{}
	}
	if ls.beToSuffixBytes == nil {
		ls.beToSuffixBytes = map[bePair][]byte{}
	}
	ls.suffixToBE[s] = pair
	ls.beToSuffix[pair] = s
	ls.beToSuffixBytes[pair] = []byte(s)
}


lookup

func (ls *listSuffixer) lookup(s suffix) (base, exponent int32, ok bool) {
	pair, ok := ls.suffixToBE[s]
	if !ok {
		return 0, 0, false
	}
	return pair.base, pair.exponent, true
}


construct

func (ls *listSuffixer) construct(base, exponent int32) (s suffix, ok bool) {
	s, ok = ls.beToSuffix[bePair{base, exponent}]
	return
}