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 }