gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

sig.go (5985B)


      1 package dbus
      2 
      3 import (
      4 	"fmt"
      5 	"reflect"
      6 	"strings"
      7 )
      8 
      9 var sigToType = map[byte]reflect.Type{
     10 	'y': byteType,
     11 	'b': boolType,
     12 	'n': int16Type,
     13 	'q': uint16Type,
     14 	'i': int32Type,
     15 	'u': uint32Type,
     16 	'x': int64Type,
     17 	't': uint64Type,
     18 	'd': float64Type,
     19 	's': stringType,
     20 	'g': signatureType,
     21 	'o': objectPathType,
     22 	'v': variantType,
     23 	'h': unixFDIndexType,
     24 }
     25 
     26 // Signature represents a correct type signature as specified by the D-Bus
     27 // specification. The zero value represents the empty signature, "".
     28 type Signature struct {
     29 	str string
     30 }
     31 
     32 // SignatureOf returns the concatenation of all the signatures of the given
     33 // values. It panics if one of them is not representable in D-Bus.
     34 func SignatureOf(vs ...interface{}) Signature {
     35 	var s string
     36 	for _, v := range vs {
     37 		s += getSignature(reflect.TypeOf(v))
     38 	}
     39 	return Signature{s}
     40 }
     41 
     42 // SignatureOfType returns the signature of the given type. It panics if the
     43 // type is not representable in D-Bus.
     44 func SignatureOfType(t reflect.Type) Signature {
     45 	return Signature{getSignature(t)}
     46 }
     47 
     48 // getSignature returns the signature of the given type and panics on unknown types.
     49 func getSignature(t reflect.Type) string {
     50 	// handle simple types first
     51 	switch t.Kind() {
     52 	case reflect.Uint8:
     53 		return "y"
     54 	case reflect.Bool:
     55 		return "b"
     56 	case reflect.Int16:
     57 		return "n"
     58 	case reflect.Uint16:
     59 		return "q"
     60 	case reflect.Int, reflect.Int32:
     61 		if t == unixFDType {
     62 			return "h"
     63 		}
     64 		return "i"
     65 	case reflect.Uint, reflect.Uint32:
     66 		if t == unixFDIndexType {
     67 			return "h"
     68 		}
     69 		return "u"
     70 	case reflect.Int64:
     71 		return "x"
     72 	case reflect.Uint64:
     73 		return "t"
     74 	case reflect.Float64:
     75 		return "d"
     76 	case reflect.Ptr:
     77 		return getSignature(t.Elem())
     78 	case reflect.String:
     79 		if t == objectPathType {
     80 			return "o"
     81 		}
     82 		return "s"
     83 	case reflect.Struct:
     84 		if t == variantType {
     85 			return "v"
     86 		} else if t == signatureType {
     87 			return "g"
     88 		}
     89 		var s string
     90 		for i := 0; i < t.NumField(); i++ {
     91 			field := t.Field(i)
     92 			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
     93 				s += getSignature(t.Field(i).Type)
     94 			}
     95 		}
     96 		return "(" + s + ")"
     97 	case reflect.Array, reflect.Slice:
     98 		return "a" + getSignature(t.Elem())
     99 	case reflect.Map:
    100 		if !isKeyType(t.Key()) {
    101 			panic(InvalidTypeError{t})
    102 		}
    103 		return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
    104 	case reflect.Interface:
    105 		return "v"
    106 	}
    107 	panic(InvalidTypeError{t})
    108 }
    109 
    110 // ParseSignature returns the signature represented by this string, or a
    111 // SignatureError if the string is not a valid signature.
    112 func ParseSignature(s string) (sig Signature, err error) {
    113 	if len(s) == 0 {
    114 		return
    115 	}
    116 	if len(s) > 255 {
    117 		return Signature{""}, SignatureError{s, "too long"}
    118 	}
    119 	sig.str = s
    120 	for err == nil && len(s) != 0 {
    121 		err, s = validSingle(s, 0)
    122 	}
    123 	if err != nil {
    124 		sig = Signature{""}
    125 	}
    126 
    127 	return
    128 }
    129 
    130 // ParseSignatureMust behaves like ParseSignature, except that it panics if s
    131 // is not valid.
    132 func ParseSignatureMust(s string) Signature {
    133 	sig, err := ParseSignature(s)
    134 	if err != nil {
    135 		panic(err)
    136 	}
    137 	return sig
    138 }
    139 
    140 // Empty returns whether the signature is the empty signature.
    141 func (s Signature) Empty() bool {
    142 	return s.str == ""
    143 }
    144 
    145 // Single returns whether the signature represents a single, complete type.
    146 func (s Signature) Single() bool {
    147 	err, r := validSingle(s.str, 0)
    148 	return err != nil && r == ""
    149 }
    150 
    151 // String returns the signature's string representation.
    152 func (s Signature) String() string {
    153 	return s.str
    154 }
    155 
    156 // A SignatureError indicates that a signature passed to a function or received
    157 // on a connection is not a valid signature.
    158 type SignatureError struct {
    159 	Sig    string
    160 	Reason string
    161 }
    162 
    163 func (e SignatureError) Error() string {
    164 	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
    165 }
    166 
    167 // Try to read a single type from this string. If it was successful, err is nil
    168 // and rem is the remaining unparsed part. Otherwise, err is a non-nil
    169 // SignatureError and rem is "". depth is the current recursion depth which may
    170 // not be greater than 64 and should be given as 0 on the first call.
    171 func validSingle(s string, depth int) (err error, rem string) {
    172 	if s == "" {
    173 		return SignatureError{Sig: s, Reason: "empty signature"}, ""
    174 	}
    175 	if depth > 64 {
    176 		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
    177 	}
    178 	switch s[0] {
    179 	case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
    180 		return nil, s[1:]
    181 	case 'a':
    182 		if len(s) > 1 && s[1] == '{' {
    183 			i := findMatching(s[1:], '{', '}')
    184 			if i == -1 {
    185 				return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
    186 			}
    187 			i++
    188 			rem = s[i+1:]
    189 			s = s[2:i]
    190 			if err, _ = validSingle(s[:1], depth+1); err != nil {
    191 				return err, ""
    192 			}
    193 			err, nr := validSingle(s[1:], depth+1)
    194 			if err != nil {
    195 				return err, ""
    196 			}
    197 			if nr != "" {
    198 				return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
    199 			}
    200 			return nil, rem
    201 		}
    202 		return validSingle(s[1:], depth+1)
    203 	case '(':
    204 		i := findMatching(s, '(', ')')
    205 		if i == -1 {
    206 			return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
    207 		}
    208 		rem = s[i+1:]
    209 		s = s[1:i]
    210 		for err == nil && s != "" {
    211 			err, s = validSingle(s, depth+1)
    212 		}
    213 		if err != nil {
    214 			rem = ""
    215 		}
    216 		return
    217 	}
    218 	return SignatureError{Sig: s, Reason: "invalid type character"}, ""
    219 }
    220 
    221 func findMatching(s string, left, right rune) int {
    222 	n := 0
    223 	for i, v := range s {
    224 		if v == left {
    225 			n++
    226 		} else if v == right {
    227 			n--
    228 		}
    229 		if n == 0 {
    230 			return i
    231 		}
    232 	}
    233 	return -1
    234 }
    235 
    236 // typeFor returns the type of the given signature. It ignores any left over
    237 // characters and panics if s doesn't start with a valid type signature.
    238 func typeFor(s string) (t reflect.Type) {
    239 	err, _ := validSingle(s, 0)
    240 	if err != nil {
    241 		panic(err)
    242 	}
    243 
    244 	if t, ok := sigToType[s[0]]; ok {
    245 		return t
    246 	}
    247 	switch s[0] {
    248 	case 'a':
    249 		if s[1] == '{' {
    250 			i := strings.LastIndex(s, "}")
    251 			t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
    252 		} else {
    253 			t = reflect.SliceOf(typeFor(s[1:]))
    254 		}
    255 	case '(':
    256 		t = interfacesType
    257 	}
    258 	return
    259 }