* add usage docs for context types and metadata, improve comments * changes after review
		
			
				
	
	
		
			161 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package metadata
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net/textproto"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // defaultMetadataSize is used when initializing new Metadata.
 | |
| var defaultMetadataSize = 2
 | |
| 
 | |
| // Metadata maps keys to values. Use the New, NewWithMetadata and Pairs functions to create it.
 | |
| type Metadata map[string][]string
 | |
| 
 | |
| // New creates a zero-value Metadata with the specified size.
 | |
| func New(l int) Metadata {
 | |
| 	if l == 0 {
 | |
| 		l = defaultMetadataSize
 | |
| 	}
 | |
| 	md := make(Metadata, l)
 | |
| 	return md
 | |
| }
 | |
| 
 | |
| // NewWithMetadata creates a Metadata from the provided key-value map.
 | |
| func NewWithMetadata(m map[string]string) Metadata {
 | |
| 	md := make(Metadata, len(m))
 | |
| 	for key, val := range m {
 | |
| 		md[key] = append(md[key], val)
 | |
| 	}
 | |
| 	return md
 | |
| }
 | |
| 
 | |
| // Pairs returns a Metadata formed from the key-value mapping. It panics if the length of kv is odd.
 | |
| func Pairs(kv ...string) Metadata {
 | |
| 	if len(kv)%2 == 1 {
 | |
| 		panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
 | |
| 	}
 | |
| 	md := make(Metadata, len(kv)/2)
 | |
| 	for i := 0; i < len(kv); i += 2 {
 | |
| 		md[kv[i]] = append(md[kv[i]], kv[i+1])
 | |
| 	}
 | |
| 	return md
 | |
| }
 | |
| 
 | |
| // Join combines multiple Metadatas into a single Metadata.
 | |
| // The order of values for each key is determined by the order in which the Metadatas are provided to Join.
 | |
| func Join(mds ...Metadata) Metadata {
 | |
| 	out := Metadata{}
 | |
| 	for _, md := range mds {
 | |
| 		for k, v := range md {
 | |
| 			out[k] = append(out[k], v...)
 | |
| 		}
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // Copy returns a deep copy of Metadata.
 | |
| func Copy(src Metadata) Metadata {
 | |
| 	out := make(Metadata, len(src))
 | |
| 	for k, v := range src {
 | |
| 		out[k] = copyOf(v)
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // Copy returns a deep copy of Metadata.
 | |
| func (md Metadata) Copy() Metadata {
 | |
| 	out := make(Metadata, len(md))
 | |
| 	for k, v := range md {
 | |
| 		out[k] = copyOf(v)
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // CopyTo performs a deep copy of Metadata to the out.
 | |
| func (md Metadata) CopyTo(out Metadata) {
 | |
| 	for k, v := range md {
 | |
| 		out[k] = copyOf(v)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Len returns the number of items in Metadata.
 | |
| func (md Metadata) Len() int {
 | |
| 	return len(md)
 | |
| }
 | |
| 
 | |
| // AsMap returns a deep copy of Metadata as a map[string]string
 | |
| func (md Metadata) AsMap() map[string]string {
 | |
| 	out := make(map[string]string, len(md))
 | |
| 	for k, v := range md {
 | |
| 		out[k] = strings.Join(v, ",")
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // AsHTTP1 returns a deep copy of Metadata with keys converted to canonical MIME header key format.
 | |
| func (md Metadata) AsHTTP1() map[string][]string {
 | |
| 	out := make(map[string][]string, len(md))
 | |
| 	for k, v := range md {
 | |
| 		out[textproto.CanonicalMIMEHeaderKey(k)] = copyOf(v)
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // AsHTTP2 returns a deep copy of Metadata with keys converted to lowercase.
 | |
| func (md Metadata) AsHTTP2() map[string][]string {
 | |
| 	out := make(map[string][]string, len(md))
 | |
| 	for k, v := range md {
 | |
| 		out[strings.ToLower(k)] = copyOf(v)
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // Get retrieves the values for a given key, checking the key in three formats:
 | |
| // - exact case,
 | |
| // - lower case,
 | |
| // - canonical MIME header key format.
 | |
| func (md Metadata) Get(k string) []string {
 | |
| 	v, ok := md[k]
 | |
| 	if !ok {
 | |
| 		v, ok = md[strings.ToLower(k)]
 | |
| 	}
 | |
| 	if !ok {
 | |
| 		v = md[textproto.CanonicalMIMEHeaderKey(k)]
 | |
| 	}
 | |
| 	return v
 | |
| }
 | |
| 
 | |
| // GetJoined retrieves the values for a given key and joins them into a single string, separated by commas.
 | |
| func (md Metadata) GetJoined(k string) string {
 | |
| 	return strings.Join(md.Get(k), ",")
 | |
| }
 | |
| 
 | |
| // Set assigns the values to the given key.
 | |
| func (md Metadata) Set(key string, vals ...string) {
 | |
| 	if len(vals) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 	md[key] = vals
 | |
| }
 | |
| 
 | |
| // Append adds values to the existing values for the given key.
 | |
| func (md Metadata) Append(key string, vals ...string) {
 | |
| 	if len(vals) == 0 {
 | |
| 		return
 | |
| 	}
 | |
| 	md[key] = append(md[key], vals...)
 | |
| }
 | |
| 
 | |
| // Del removes the values for the given keys k. It checks and removes the keys in the following formats:
 | |
| // - exact case,
 | |
| // - lower case,
 | |
| // - canonical MIME header key format.
 | |
| func (md Metadata) Del(k ...string) {
 | |
| 	for i := range k {
 | |
| 		delete(md, k[i])
 | |
| 		delete(md, strings.ToLower(k[i]))
 | |
| 		delete(md, textproto.CanonicalMIMEHeaderKey(k[i]))
 | |
| 	}
 | |
| }
 |