github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/eval/vals/assoc.go (about)

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