github.com/elves/elvish@v0.15.0/pkg/eval/vals/assoc.go (about)

     1  package vals
     2  
     3  import (
     4  	"errors"
     5  )
     6  
     7  // Assocer wraps the Assoc method.
     8  type Assocer interface {
     9  	// Assoc returns a slightly modified version of the receiver with key k
    10  	// associated with value v.
    11  	Assoc(k, v interface{}) (interface{}, error)
    12  }
    13  
    14  var (
    15  	errAssocUnsupported        = errors.New("assoc is not supported")
    16  	errReplacementMustBeString = errors.New("replacement must be string")
    17  	errAssocWithSlice          = errors.New("assoc with slice not yet supported")
    18  )
    19  
    20  // Assoc takes a container, a key and value, and returns a modified version of
    21  // the container, in which the key associated with the value. It is implemented
    22  // for the builtin type string, List and Map types, StructMap types, and types
    23  // satisfying the Assocer interface. For other types, it returns an error.
    24  func Assoc(a, k, v interface{}) (interface{}, error) {
    25  	switch a := a.(type) {
    26  	case string:
    27  		return assocString(a, k, v)
    28  	case List:
    29  		return assocList(a, k, v)
    30  	case Map:
    31  		return a.Assoc(k, v), nil
    32  	case Assocer:
    33  		return a.Assoc(k, v)
    34  	}
    35  	return nil, errAssocUnsupported
    36  }
    37  
    38  func assocString(s string, k, v interface{}) (interface{}, error) {
    39  	i, j, err := convertStringIndex(k, s)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	repl, ok := v.(string)
    44  	if !ok {
    45  		return nil, errReplacementMustBeString
    46  	}
    47  	return s[:i] + repl + s[j:], nil
    48  }
    49  
    50  func assocList(l List, k, v interface{}) (interface{}, error) {
    51  	index, err := ConvertListIndex(k, l.Len())
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	if index.Slice {
    56  		return nil, errAssocWithSlice
    57  	}
    58  	return l.Assoc(index.Lower, v), nil
    59  }