text: package dbus
  
  import (
  	"fmt"
  	"reflect"
  	"strings"
  )
  
  var sigToType = map[byte]reflect.Type{
  	'y': byteType,
  	'b': boolType,
  	'n': int16Type,
  	'q': uint16Type,
  	'i': int32Type,
  	'u': uint32Type,
  	'x': int64Type,
  	't': uint64Type,
  	'd': float64Type,
  	's': stringType,
  	'g': signatureType,
  	'o': objectPathType,
  	'v': variantType,
  	'h': unixFDIndexType,
  }
  
  // Signature represents a correct type signature as specified by the D-Bus
  // specification. The zero value represents the empty signature, "".
  type Signature struct {
  	str string
  }
  
  // SignatureOf returns the concatenation of all the signatures of the given
  // values. It panics if one of them is not representable in D-Bus.
  func SignatureOf(vs ...interface{}) Signature {
  	var s string
  	for _, v := range vs {
  		s += getSignature(reflect.TypeOf(v))
  	}
  	return Signature{s}
  }
  
  // SignatureOfType returns the signature of the given type. It panics if the
  // type is not representable in D-Bus.
  func SignatureOfType(t reflect.Type) Signature {
  	return Signature{getSignature(t)}
  }
  
  // getSignature returns the signature of the given type and panics on unknown types.
  func getSignature(t reflect.Type) string {
  	// handle simple types first
  	switch t.Kind() {
  	case reflect.Uint8:
  		return "y"
  	case reflect.Bool:
  		return "b"
  	case reflect.Int16:
  		return "n"
  	case reflect.Uint16:
  		return "q"
  	case reflect.Int32:
  		if t == unixFDType {
  			return "h"
  		}
  		return "i"
  	case reflect.Uint32:
  		if t == unixFDIndexType {
  			return "h"
  		}
  		return "u"
  	case reflect.Int64:
  		return "x"
  	case reflect.Uint64:
  		return "t"
  	case reflect.Float64:
  		return "d"
  	case reflect.Ptr:
  		return getSignature(t.Elem())
  	case reflect.String:
  		if t == objectPathType {
  			return "o"
  		}
  		return "s"
  	case reflect.Struct:
  		if t == variantType {
  			return "v"
  		} else if t == signatureType {
  			return "g"
  		}
  		var s string
  		for i := 0; i < t.NumField(); i++ {
  			field := t.Field(i)
  			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
  				s += getSignature(t.Field(i).Type)
  			}
  		}
  		return "(" + s + ")"
  	case reflect.Array, reflect.Slice:
  		return "a" + getSignature(t.Elem())
  	case reflect.Map:
  		if !isKeyType(t.Key()) {
  			panic(InvalidTypeError{t})
  		}
  		return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
  	}
  	panic(InvalidTypeError{t})
  }
  
  // ParseSignature returns the signature represented by this string, or a
  // SignatureError if the string is not a valid signature.
  func ParseSignature(s string) (sig Signature, err error) {
  	if len(s) == 0 {
  		return
  	}
  	if len(s) > 255 {
  		return Signature{""}, SignatureError{s, "too long"}
  	}
  	sig.str = s
  	for err == nil && len(s) != 0 {
  		err, s = validSingle(s, 0)
  	}
  	if err != nil {
  		sig = Signature{""}
  	}
  
  	return
  }
  
  // ParseSignatureMust behaves like ParseSignature, except that it panics if s
  // is not valid.
  func ParseSignatureMust(s string) Signature {
  	sig, err := ParseSignature(s)
  	if err != nil {
  		panic(err)
  	}
  	return sig
  }
  
  // Empty retruns whether the signature is the empty signature.
  func (s Signature) Empty() bool {
  	return s.str == ""
  }
  
  // Single returns whether the signature represents a single, complete type.
  func (s Signature) Single() bool {
  	err, r := validSingle(s.str, 0)
  	return err != nil && r == ""
  }
  
  // String returns the signature's string representation.
  func (s Signature) String() string {
  	return s.str
  }
  
  // A SignatureError indicates that a signature passed to a function or received
  // on a connection is not a valid signature.
  type SignatureError struct {
  	Sig    string
  	Reason string
  }
  
  func (e SignatureError) Error() string {
  	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
  }
  
  // Try to read a single type from this string. If it was successfull, err is nil
  // and rem is the remaining unparsed part. Otherwise, err is a non-nil
  // SignatureError and rem is "". depth is the current recursion depth which may
  // not be greater than 64 and should be given as 0 on the first call.
  func validSingle(s string, depth int) (err error, rem string) {
  	if s == "" {
  		return SignatureError{Sig: s, Reason: "empty signature"}, ""
  	}
  	if depth > 64 {
  		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
  	}
  	switch s[0] {
  	case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
  		return nil, s[1:]
  	case 'a':
  		if len(s) > 1 && s[1] == '{' {
  			i := findMatching(s[1:], '{', '}')
  			if i == -1 {
  				return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
  			}
  			i++
  			rem = s[i+1:]
  			s = s[2:i]
  			if err, _ = validSingle(s[:1], depth+1); err != nil {
  				return err, ""
  			}
  			err, nr := validSingle(s[1:], depth+1)
  			if err != nil {
  				return err, ""
  			}
  			if nr != "" {
  				return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
  			}
  			return nil, rem
  		}
  		return validSingle(s[1:], depth+1)
  	case '(':
  		i := findMatching(s, '(', ')')
  		if i == -1 {
  			return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
  		}
  		rem = s[i+1:]
  		s = s[1:i]
  		for err == nil && s != "" {
  			err, s = validSingle(s, depth+1)
  		}
  		if err != nil {
  			rem = ""
  		}
  		return
  	}
  	return SignatureError{Sig: s, Reason: "invalid type character"}, ""
  }
  
  func findMatching(s string, left, right rune) int {
  	n := 0
  	for i, v := range s {
  		if v == left {
  			n++
  		} else if v == right {
  			n--
  		}
  		if n == 0 {
  			return i
  		}
  	}
  	return -1
  }
  
  // typeFor returns the type of the given signature. It ignores any left over
  // characters and panics if s doesn't start with a valid type signature.
  func typeFor(s string) (t reflect.Type) {
  	err, _ := validSingle(s, 0)
  	if err != nil {
  		panic(err)
  	}
  
  	if t, ok := sigToType[s[0]]; ok {
  		return t
  	}
  	switch s[0] {
  	case 'a':
  		if s[1] == '{' {
  			i := strings.LastIndex(s, "}")
  			t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
  		} else {
  			t = reflect.SliceOf(typeFor(s[1:]))
  		}
  	case '(':
  		t = interfacesType
  	}
  	return
  }
  