gtsocial-umbx

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

variant.go (3670B)


      1 package dbus
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"reflect"
      7 	"sort"
      8 	"strconv"
      9 )
     10 
     11 // Variant represents the D-Bus variant type.
     12 type Variant struct {
     13 	sig   Signature
     14 	value interface{}
     15 }
     16 
     17 // MakeVariant converts the given value to a Variant. It panics if v cannot be
     18 // represented as a D-Bus type.
     19 func MakeVariant(v interface{}) Variant {
     20 	return MakeVariantWithSignature(v, SignatureOf(v))
     21 }
     22 
     23 // MakeVariantWithSignature converts the given value to a Variant.
     24 func MakeVariantWithSignature(v interface{}, s Signature) Variant {
     25 	return Variant{s, v}
     26 }
     27 
     28 // ParseVariant parses the given string as a variant as described at
     29 // https://developer.gnome.org/glib/stable/gvariant-text.html. If sig is not
     30 // empty, it is taken to be the expected signature for the variant.
     31 func ParseVariant(s string, sig Signature) (Variant, error) {
     32 	tokens := varLex(s)
     33 	p := &varParser{tokens: tokens}
     34 	n, err := varMakeNode(p)
     35 	if err != nil {
     36 		return Variant{}, err
     37 	}
     38 	if sig.str == "" {
     39 		sig, err = varInfer(n)
     40 		if err != nil {
     41 			return Variant{}, err
     42 		}
     43 	}
     44 	v, err := n.Value(sig)
     45 	if err != nil {
     46 		return Variant{}, err
     47 	}
     48 	return MakeVariant(v), nil
     49 }
     50 
     51 // format returns a formatted version of v and whether this string can be parsed
     52 // unambigously.
     53 func (v Variant) format() (string, bool) {
     54 	switch v.sig.str[0] {
     55 	case 'b', 'i':
     56 		return fmt.Sprint(v.value), true
     57 	case 'n', 'q', 'u', 'x', 't', 'd', 'h':
     58 		return fmt.Sprint(v.value), false
     59 	case 's':
     60 		return strconv.Quote(v.value.(string)), true
     61 	case 'o':
     62 		return strconv.Quote(string(v.value.(ObjectPath))), false
     63 	case 'g':
     64 		return strconv.Quote(v.value.(Signature).str), false
     65 	case 'v':
     66 		s, unamb := v.value.(Variant).format()
     67 		if !unamb {
     68 			return "<@" + v.value.(Variant).sig.str + " " + s + ">", true
     69 		}
     70 		return "<" + s + ">", true
     71 	case 'y':
     72 		return fmt.Sprintf("%#x", v.value.(byte)), false
     73 	}
     74 	rv := reflect.ValueOf(v.value)
     75 	switch rv.Kind() {
     76 	case reflect.Slice:
     77 		if rv.Len() == 0 {
     78 			return "[]", false
     79 		}
     80 		unamb := true
     81 		buf := bytes.NewBuffer([]byte("["))
     82 		for i := 0; i < rv.Len(); i++ {
     83 			// TODO: slooow
     84 			s, b := MakeVariant(rv.Index(i).Interface()).format()
     85 			unamb = unamb && b
     86 			buf.WriteString(s)
     87 			if i != rv.Len()-1 {
     88 				buf.WriteString(", ")
     89 			}
     90 		}
     91 		buf.WriteByte(']')
     92 		return buf.String(), unamb
     93 	case reflect.Map:
     94 		if rv.Len() == 0 {
     95 			return "{}", false
     96 		}
     97 		unamb := true
     98 		var buf bytes.Buffer
     99 		kvs := make([]string, rv.Len())
    100 		for i, k := range rv.MapKeys() {
    101 			s, b := MakeVariant(k.Interface()).format()
    102 			unamb = unamb && b
    103 			buf.Reset()
    104 			buf.WriteString(s)
    105 			buf.WriteString(": ")
    106 			s, b = MakeVariant(rv.MapIndex(k).Interface()).format()
    107 			unamb = unamb && b
    108 			buf.WriteString(s)
    109 			kvs[i] = buf.String()
    110 		}
    111 		buf.Reset()
    112 		buf.WriteByte('{')
    113 		sort.Strings(kvs)
    114 		for i, kv := range kvs {
    115 			if i > 0 {
    116 				buf.WriteString(", ")
    117 			}
    118 			buf.WriteString(kv)
    119 		}
    120 		buf.WriteByte('}')
    121 		return buf.String(), unamb
    122 	}
    123 	return `"INVALID"`, true
    124 }
    125 
    126 // Signature returns the D-Bus signature of the underlying value of v.
    127 func (v Variant) Signature() Signature {
    128 	return v.sig
    129 }
    130 
    131 // String returns the string representation of the underlying value of v as
    132 // described at https://developer.gnome.org/glib/stable/gvariant-text.html.
    133 func (v Variant) String() string {
    134 	s, unamb := v.format()
    135 	if !unamb {
    136 		return "@" + v.sig.str + " " + s
    137 	}
    138 	return s
    139 }
    140 
    141 // Value returns the underlying value of v.
    142 func (v Variant) Value() interface{} {
    143 	return v.value
    144 }
    145 
    146 // Store converts the variant into a native go type using the same
    147 // mechanism as the "Store" function.
    148 func (v Variant) Store(value interface{}) error {
    149 	return storeInterfaces(v.value, value)
    150 }