go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/strpair/pair.go (about)

     1  // Copyright 2017 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package strpair implements parsing and formatting of lists of
    16  // colon-delimited key-value pair strings.
    17  //
    18  // Example of pairs:
    19  //
    20  //	master:tryserver.chromium.linux
    21  //	builder:linux_chromium_rel_ng
    22  //	buildset:patch/gerrit/chromium-review.googlesource.com/677784/5
    23  package strpair
    24  
    25  import (
    26  	"sort"
    27  	"strings"
    28  )
    29  
    30  // Parse parses a colon-delimited key-value pair.
    31  //
    32  // If pair does not have ":", the whole string becomes the key with an empty
    33  // value.
    34  func Parse(pair string) (k, v string) {
    35  	parts := strings.SplitN(pair, ":", 2)
    36  	k = parts[0]
    37  	if len(parts) > 1 {
    38  		v = parts[1]
    39  	} else {
    40  		// this pair is invalid. This should not happen in practice.
    41  		// Do not panic because this function is used for externally-supplied
    42  		// data.
    43  	}
    44  	return
    45  }
    46  
    47  // Format formats a pair from a key and a value.
    48  func Format(k, v string) string {
    49  	return k + ":" + v
    50  }
    51  
    52  // Map contains parsed string pairs.
    53  type Map map[string][]string
    54  
    55  // Get gets the first value associated with the given key.
    56  // If there are no values associated with the key, Get returns
    57  // the empty string. To access multiple values, use the map
    58  // directly.
    59  func (m Map) Get(key string) string {
    60  	if m == nil {
    61  		return ""
    62  	}
    63  	vs := m[key]
    64  	if len(vs) == 0 {
    65  		return ""
    66  	}
    67  	return vs[0]
    68  }
    69  
    70  // Set sets the key to value. It replaces any existing values.
    71  func (m Map) Set(key, value string) {
    72  	m[key] = []string{value}
    73  }
    74  
    75  // Add adds the value to key. It appends to any existing
    76  // values associated with key.
    77  func (m Map) Add(key, value string) {
    78  	m[key] = append(m[key], value)
    79  }
    80  
    81  // Del deletes the values associated with key.
    82  func (m Map) Del(key string) {
    83  	delete(m, key)
    84  }
    85  
    86  // ParseMap parses a list of colon-delimited key-value pair strings.
    87  func ParseMap(raw []string) Map {
    88  	m := make(Map, len(raw))
    89  	for _, t := range raw {
    90  		m.Add(Parse(t))
    91  	}
    92  	return m
    93  }
    94  
    95  // Format converts m to a sorted list of strings.
    96  func (m Map) Format() []string {
    97  	res := make([]string, 0, len(m))
    98  	for k, values := range m {
    99  		for _, v := range values {
   100  			res = append(res, Format(k, v))
   101  		}
   102  	}
   103  	sort.Strings(res)
   104  	return res
   105  }
   106  
   107  // Copy returns a deep copy of m.
   108  func (m Map) Copy() Map {
   109  	cpy := make(Map, len(m))
   110  	for k, vs := range m {
   111  		cpy[k] = append([]string(nil), vs...)
   112  	}
   113  	return cpy
   114  }
   115  
   116  // Contains returns true if m contains the key-value pair.
   117  func (m Map) Contains(key, value string) bool {
   118  	for _, v := range m[key] {
   119  		if v == value {
   120  			return true
   121  		}
   122  	}
   123  	return false
   124  }